lib/parks/cdaparks/cdabase.js
import moment from 'moment-timezone';
import fetch from 'node-fetch';
import {Park} from '../park.js';
import {entityType, queueType, scheduleType} from '../types.js';
import {entityCategory, entityTags} from '../tags.js';
import dotenv from 'dotenv';
dotenv.config();
/**
* CDA Park Object
* Make sure all environment variables are set in an .env file which should be in the main location.
* Not setting these variables will make the module exit early without returning data.
*
* This class is here to fetch the POI data and to attach queue times data to it.
* After the fetches this data is send to the end user and from there he could do whatever he wants to do.
*
* Most park specific parameters are set already
* @class
*/
export class CDABase extends Park {
/**
* Create a new Compagnie des Alpes Park object
* @param {object} options
*/
constructor(options = {}) {
// Language settings
options.cachepoistime = process.env.CACHE_DURATION_POIS;
options.languages = process.env.LANGUAGES;
options.langoptions = `{'en', 'de', 'nl'}`;
super(options);
// Check for existance
if (!this.config.apiBase) throw new Error('Missing Compagnie des Alpes apiBase!');
if (!this.config.languages) {
this.config.languages = 'en';
};
if (!this.config.cachepoistime) {
this.config.cachepoistime = '12'; // Default cache value is 12 hours
};
}
/**
* Get All POIS of Compagnie des Alpes
* This data contains all the POIS in Compagnie des Alpes
* @return {string} All Compagnie des Alpes POIS
*/
async getPOIS() {
return fetch(this.config.apiBase +
`${this.config.languages}/api/entertainments`,
{
method: 'GET',
},
)
.then((res) => res.json())
.then((rideData) => {
// Immediately return ridedata
return Promise.resolve(rideData);
});
}
/**
* Get All Rides of Compagnie des Alpes
* This data contains all the Ride POIS in Compagnie des Alpes park
* @return {string} All Compagnie des Alpes ride POIS
*/
async buildRidePOI() {
// Obtain the POIS
return await this.getPOIS().then((rideData) => {
// POI array
const poi = [];
// Set initial height values
let minHeightAccompanied = undefined;
let minHeight = undefined;
rideData.entertainment.forEach((ride) => {
const category = [];
const tags = [];
// Add tags and categories
if (ride.babyswitch === true) {
tags.push(entityTags.childSwap);
}
if (ride.category.name === 'Family') {
category.push(entityCategory.family);
}
if (ride.category.name === 'Kids') {
category.push(entityCategory.youngest);
}
if (ride.category.name === 'Thrills') {
category.push(entityCategory.thrill);
}
// Min height values, sometimes in french, sometimes in english
ride.parameters.forEach((param) => {
if (param.title === 'taille min accompagné' || param.title === 'min accompanied heigh') {
minHeightAccompanied = param.value;
}
if (param.title === 'taille min non accompagné' || param.title === 'min unaccompanied heigh') {
minHeight = param.value;
}
});
const restrictions = {
minHeightAccompanied,
minHeight,
};
let description = undefined;
let shortdescription = undefined;
// Add descriptions
ride.additionalContent.forEach((desc) => {
description = desc.text;
shortdescription = desc.title;
});
let lat = undefined;
let lon = undefined;
// Add location
if (ride.location) {
lat = JSON.parse(ride.location.lat);
lon = JSON.parse(ride.location.lon);
}
// Build the POI object
poi[ride.uuid] = {
name: ride.title,
id: ride.uuid,
location: {
latitude: lat,
longitude: lon,
},
meta: {
description: description,
shortdescription: shortdescription,
category,
type: entityType.ride,
restrictions,
},
};
});
return Promise.resolve(poi);
});
}
/**
* Get All Queues of Compagnie des Alpes
* This data contains all the POIS in Compagnie des Alpes park
* @return {string} All Compagnie des Alpes POIS with queuetimes
*/
async getQueue() {
// Obtain ridedata first
const rideData = await this.buildRidePOI();
return fetch(this.config.apiBase +
`${this.config.languages}/api/waiting_time`,
{
method: 'GET',
},
)
.then((res) => res.json())
.then((waitData) => {
// Ride array
const rides = [];
waitData.forEach((ride) => {
// Set default values
let wait = null;
let state = null;
let active = null;
// Add the queuetime and ride status
if (ride.status === 'closed') {
wait = 0;
state = queueType.closed;
active = false;
} else if (ride.status === 'outoforder') { // Seems to be maintenance?
wait = 0;
state = queueType.refurbishment;
active = false;
} else {
wait = ride.waitingTime;
state = queueType.operating;
active = true;
}
// Attach queue if the poi exists
if (rideData[ride.id]) {
rides.push({
name: rideData[ride.id].name,
id: rideData[ride.id].id,
waitTime: wait,
status: state,
active: active,
location: {
latitude: rideData[ride.id].location.latitude,
longitude: rideData[ride.id].location.longitude,
},
meta: {
description: rideData[ride.id].meta.description,
short_description: rideData[ride.id].meta.shortdescription,
category: rideData[ride.id].meta.category,
type: entityType.ride,
restrictions: rideData[ride.id].meta.restrictions,
},
});
}
});
return rides;
});
}
/**
* Get All Operating Hours of Compagnie des Alpes
* This data contains all the Operating Hours in Compagnie des Alpes, fetched with currentyear.
* @return {string} All Compagnie des Alpes calendar data
*/
async getOpHours() {
// Declare the currentyear for the URL
const currentYear = moment().format('YYYY');
return fetch(
this.config.apiBase +
`${this.config.languages}/api/calendar/${currentYear}?_format=json`,
{
method: 'GET',
},
)
.then((res) => res.json())
.then((json) => {
// Calendar object
const Calendar = [];
// The calendar provides data for the whole year, however, we don't want past data.
Object.keys(json.opening_hours).forEach((key) => {
const now = moment().format('MM') + '\/' + moment().format('DD');
// Only continue if our hit is AFTER yesterday
if (moment(key).isSameOrAfter(moment(now))) {
// Declare default statusses
let state = json.opening_hours[key].status;
let open = undefined;
let close = undefined;
let name = undefined;
// Split the date object
const datesplit = key.split('/');
const date = currentYear + '-' + datesplit[0] + '-' + datesplit[1];
// Park is closed, nothing returned
if (state === 'closed') {
name = 'Closed';
state = scheduleType.closed;
open = moment(`${date} 23:59`, 'YYYY-MM-DD HH:mm a', `${this.config.Timezone}`).format();
close = moment(`${date} 23:59`, 'YYYY-MM-DD HH:mm a', `${this.config.Timezone}`).format();
// Park is open, but sold out, strangely enough operating hours are removed as well
} else if (state === 'soldout') {
name = 'Sold out, using longest possible hours';
open = moment(`${date} 10:00`, 'YYYY-MM-DD HH:mm a', `${this.config.Timezone}`).format();
close = moment(`${date} 23:00`, 'YYYY-MM-DD HH:mm a', `${this.config.Timezone}`).format();
state = scheduleType.operating;
// Park is operating as normal
} else {
name = 'Open';
state = scheduleType.operating;
open = moment(`${date} ${json.opening_hours[key].mo_time}`, 'YYYY-MM-DD HH:mm a', `${this.config.Timezone}`).format();
close = moment(`${date} ${json.opening_hours[key].mc_time}`, 'YYYY-MM-DD HH:mm a', `${this.config.Timezone}`).format();
}
// Set the hours object
const hourobj = {
name: name,
openingTime: open,
closingTime: close,
date: date,
type: state,
};
Calendar.push(hourobj);
}
});
return Promise.resolve(Calendar);
});
}
}
export default CDABase;