diff --git a/app/component/routepage/ScheduleContainer.js b/app/component/routepage/ScheduleContainer.js index b944a2d94f..6963e89208 100644 --- a/app/component/routepage/ScheduleContainer.js +++ b/app/component/routepage/ScheduleContainer.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import React, { PureComponent } from 'react'; import { createFragmentContainer, graphql } from 'react-relay'; +import { connectToStores } from 'fluxible-addons-react'; import { matchShape, routerShape, RedirectException } from 'found'; import moment from 'moment'; import { intlShape } from 'react-intl'; @@ -356,10 +357,12 @@ class ScheduleContainer extends PureComponent { breakpoint: PropTypes.string.isRequired, router: routerShape.isRequired, route: routeShape.isRequired, + lang: PropTypes.string, }; static defaultProps = { serviceDay: undefined, + lang: 'en', }; static contextTypes = { @@ -900,11 +903,11 @@ class ScheduleContainer extends PureComponent { const routeTimetableUrl = routeTimetableHandler && this.context.config.URL.ROUTE_TIMETABLES[routeIdSplitted[0]] && - routeTimetableHandler.timetableUrlResolver( + routeTimetableHandler.routeTimetableUrlResolver( this.context.config.URL.ROUTE_TIMETABLES[routeIdSplitted[0]], this.props.route, - this.context.config.API_SUBSCRIPTION_QUERY_PARAMETER_NAME, - this.context.config.API_SUBSCRIPTION_TOKEN, + newServiceDay, + this.props.lang, ); const showTrips = this.getTrips( @@ -1033,7 +1036,13 @@ class ScheduleContainer extends PureComponent { } const containerComponent = createFragmentContainer( - withBreakpoint(ScheduleContainer), + connectToStores( + withBreakpoint(ScheduleContainer), + ['PreferencesStore'], + context => ({ + lang: context.getStore('PreferencesStore').getLanguage(), + }), + ), { pattern: graphql` fragment ScheduleContainer_pattern on Pattern { diff --git a/app/component/stop/Timetable.js b/app/component/stop/Timetable.js index 43ab2cd30a..3d1e4408ab 100644 --- a/app/component/stop/Timetable.js +++ b/app/component/stop/Timetable.js @@ -310,7 +310,7 @@ class Timetable extends React.Component { this.context.config.URL.STOP_TIMETABLES[stopIdSplitted[0]] && locationType !== 'STATION' && date - ? stopTimetableHandler.stopPdfUrlResolver( + ? stopTimetableHandler.stopTimetableUrlResolver( this.context.config.URL.STOP_TIMETABLES[stopIdSplitted[0]], this.props.stop, date, diff --git a/app/configurations/config.default.js b/app/configurations/config.default.js index 4fc8320632..afa0168ba1 100644 --- a/app/configurations/config.default.js +++ b/app/configurations/config.default.js @@ -10,8 +10,8 @@ const MAP_URL = process.env.MAP_URL || 'https://dev-cdn.digitransit.fi'; const MAP_VERSION = process.env.MAP_VERSION || 'v3'; const POI_MAP_PREFIX = `${MAP_URL}/map/v3/finland`; const OTP_URL = process.env.OTP_URL || `${API_URL}/routing/v2/finland/`; -const STOP_TIMETABLES_URL = - process.env.STOP_TIMETABLES_URL || 'https://dev.kartat.hsl.fi'; +const HSL_TIMETABLES_URL = + process.env.HSL_TIMETABLES_URL || 'https://dev.kartat.hsl.fi'; const APP_PATH = process.env.APP_CONTEXT || ''; const { // AXE, @@ -92,11 +92,11 @@ export default { : '' }`, ROUTE_TIMETABLES: { - HSL: `${API_URL}/timetables/v1/hsl/routes/`, - tampere: 'https://www.nysse.fi/aikataulut-ja-reitit/linjat/', + HSL: `${HSL_TIMETABLES_URL}/julkaisin-render/?component=LineTimetable`, + tampere: 'https://www.nysse.fi/matkan-suunnittelu/linjat/', }, STOP_TIMETABLES: { - HSL: `${STOP_TIMETABLES_URL}/julkaisin-render/?component=Timetable`, + HSL: `${HSL_TIMETABLES_URL}/julkaisin-render/?component=Timetable`, }, WEATHER_DATA: 'https://opendata.fmi.fi/wfs?service=WFS&version=2.0.0&request=getFeature&storedquery_id=fmi::forecast::harmonie::surface::point::simple×tep=5¶meters=temperature,WindSpeedMS,WeatherSymbol3', @@ -559,10 +559,6 @@ export default { defaultMapZoom: 12, - availableRouteTimetables: {}, - - routeTimetableUrlResolver: {}, - showTenWeeksOnRouteSchedule: true, useRealtimeTravellerCapacities: false, diff --git a/app/configurations/config.matka.js b/app/configurations/config.matka.js index e5a9683fb0..2f48366662 100644 --- a/app/configurations/config.matka.js +++ b/app/configurations/config.matka.js @@ -23,9 +23,6 @@ const virtualMonitorBaseUrl = IS_DEV ? 'https://dev-matkamonitori.digitransit.fi' : 'https://matkamonitori.digitransit.fi'; -// route timetable data needs to be up-to-date before this is enabled -// const HSLRouteTimetable = require('./timetableConfigUtils').default.HSLRoutes; - export default { CONFIG, OTPTimeout: process.env.OTP_TIMEOUT || 30000, diff --git a/app/configurations/timetableConfigUtils.js b/app/configurations/timetableConfigUtils.js index e59b2d4ef8..ad887ada43 100644 --- a/app/configurations/timetableConfigUtils.js +++ b/app/configurations/timetableConfigUtils.js @@ -3,41 +3,33 @@ export default { HSL: { - // Gets updated when server starts with {routeName: timetableName} - // where routeName and timetableNames are route gtfsId values without ":" - availableRouteTimetables: {}, - - // gets the name of the route (in gtfsId format without the ":" part) which - // contains the timetable pdf for the current route (it can be stored under different route) - // if there is no available timetable for the route, return null so that the weekly - // timetable button will not be rendered in UI - timetableUrlResolver: function timetableUrlResolver( + routeTimetableUrlResolver: function routeTimetableUrlResolver( baseURL, route, - subscriptionParam, - subscriptionToken, + date, + lang, ) { - const routeIdSplitted = route.gtfsId.split(':'); - const routeId = routeIdSplitted[1]; - const routePDFUrlName = this.availableRouteTimetables[routeId]; - if (routePDFUrlName === undefined) { - return null; - } + const routeId = route.gtfsId.split(':')[1]; + + // From YYYYMMDD to YYYY-MM-DD + const formattedDate = date.replace(/(\d{4})(\d{2})(\d{2})/g, '$1-$2-$3'); - const url = new URL(`${baseURL}${routePDFUrlName}.pdf`); - if (subscriptionParam && subscriptionToken) { - url.searchParams.set(subscriptionParam, subscriptionToken); - } + const defaultSearchParams = + 'props[showPrintButton]=true&props[redirect]=false'; + const url = new URL(`${baseURL}&${defaultSearchParams}`); + url.searchParams.append('props[lineId]', routeId); + url.searchParams.append('props[dateBegin]', formattedDate); + url.searchParams.append('props[dateEnd]', formattedDate); + url.searchParams.append('props[lang]', lang); return url; }, - setAvailableRouteTimetables: function setAvailableRouteTimetables( - timetables, + stopTimetableUrlResolver: function stopTimetableUrlResolver( + baseURL, + stop, + date, + lang, ) { - this.availableRouteTimetables = timetables; - }, - stopPdfUrlResolver: function stopPdfUrlResolver(baseURL, stop, date, lang) { const stopId = stop.gtfsId.split(':')[1]; - // From YYYYMMDD to YYYY-MM-DD const formattedDate = date.replace(/(\d{4})(\d{2})(\d{2})/g, '$1-$2-$3'); const defaultSearchParams = 'props[isSummerTimetable]=false&props[printTimetablesAsA4]=true&props[printTimetablesAsGreyscale]=false&props[template]=default&props[showAddressInfo]=false&props[showPrintButton]=true&props[redirect]=false&template=default'; @@ -49,16 +41,21 @@ export default { }, }, tampere: { - timetableUrlResolver: function timetableUrlResolver( + routeTimetableUrlResolver: function routeTimetableUrlResolver( baseURL, route, - subscriptionParam, - subscriptionToken, + date, + lang, ) { const routeNumber = route.shortName.replace(/\D/g, ''); return new URL(`${baseURL}${routeNumber}.html`); }, - stopPdfUrlResolver: function stopPdfUrlResolver(baseURL, stop, date, lang) { + stopTimetableUrlResolver: function stopTimetableUrlResolver( + baseURL, + stop, + date, + lang, + ) { const stopIdSplitted = stop.gtfsId.split(':'); return new URL(`${baseURL}${parseInt(stopIdSplitted[1], 10)}.pdf`); }, diff --git a/server/server.js b/server/server.js index 91f6555e2b..68a796e00a 100644 --- a/server/server.js +++ b/server/server.js @@ -152,61 +152,6 @@ function setUpRoutes() { app.enable('trust proxy'); } -function setUpAvailableRouteTimetables() { - return new Promise(resolve => { - // Stores available route pdf names to config.availableRouteTimetables.HSL - // All routes don't have available pdf and some have their timetable inside other route - // so there is a mapping between route's gtfsId (without HSL: part) and similar gtfsId of - // route that contains timetables - if (config.timetables.HSL) { - // try to fetch available route timetables every four seconds with 4 retries - retryFetch( - `${config.URL.ROUTE_TIMETABLES.HSL}routes.json`, - 4, - 4000, - {}, - config, - ) - .then(res => res.json()) - .then( - result => { - config.timetables.HSL.setAvailableRouteTimetables(result); - console.log('availableRouteTimetables.HSL loaded'); - resolve(); - }, - err => { - console.log(err); - // If after 5 tries no timetable data is found, start server anyway - resolve(); - console.log('availableRouteTimetables.HSL loader failed'); - // Continue attempts to fetch available routes in the background for one day once every minute - retryFetch( - `${config.URL.ROUTE_TIMETABLES.HSL}routes.json`, - 1440, - 60000, - {}, - config, - ) - .then(res => res.json()) - .then( - result => { - config.timetables.HSL.setAvailableRouteTimetables(result); - console.log( - 'availableRouteTimetables.HSL loaded after retry', - ); - }, - error => { - console.log(error); - }, - ); - }, - ); - } else { - resolve(); - } - }); -} - function processTicketTypeResult(result) { const resultData = result.data; if (config.availableTickets) { @@ -445,7 +390,6 @@ setUpMiddleware(); setUpRoutes(); setUpErrorHandling(); Promise.all([ - setUpAvailableRouteTimetables(), setUpAvailableTickets(), collectGeoJsonZones(), fetchCitybikeConfigurations(), diff --git a/test/unit/util/timetableConfigUtils.test.js b/test/unit/util/timetableConfigUtils.test.js index 67c31980f8..088b3ffad7 100644 --- a/test/unit/util/timetableConfigUtils.test.js +++ b/test/unit/util/timetableConfigUtils.test.js @@ -3,47 +3,42 @@ import { describe, it } from 'mocha'; import * as timetables from '../../../app/configurations/timetableConfigUtils'; describe('timetableConfigUtils', () => { - const baseTimetableURL = 'https://timetabletest.com/timetables/'; - describe('timetableUrlResolver', () => { + describe('routeTimetableUrlResolver', () => { it('should resolve URL correctly for HSL instance', () => { + const baseTimetableURL = 'https://timetabletest.com/?foo=bar'; const timetableHandler = timetables.default.HSL; - timetableHandler.setAvailableRouteTimetables({ 2550: '2550' }); const route = { gtfsId: 'HSL:2550' }; - const url = timetableHandler.timetableUrlResolver( + const url = timetableHandler.routeTimetableUrlResolver( baseTimetableURL, route, + '20231031', + 'en', ); - expect(url.href).to.equal(`${baseTimetableURL}2550.pdf`); - }); - it('should resolve URL correctly for HSL instance with authentication param', () => { - const timetableHandler = timetables.default.HSL; - const route = { gtfsId: 'HSL:2550' }; - const url = timetableHandler.timetableUrlResolver( - baseTimetableURL, - route, - 'foo', - 'bar', + expect(url.href).to.equal( + `${baseTimetableURL}&props%5BshowPrintButton%5D=true&props%5Bredirect%5D=false&props%5BlineId%5D=2550&props%5BdateBegin%5D=2023-10-31&props%5BdateEnd%5D=2023-10-31&props%5Blang%5D=en`, ); - expect(url.href).to.equal(`${baseTimetableURL}2550.pdf?foo=bar`); }); it('should resolve URL for bus lines correctly for tampere instance', () => { + const baseTimetableURL = 'https://timetabletest.com/timetables/'; const timetableHandler = timetables.default.tampere; const route = { shortName: '11C', mode: 'BUS' }; - const url = timetableHandler.timetableUrlResolver( + const url = timetableHandler.routeTimetableUrlResolver( baseTimetableURL, route, + '20231031', + 'en', ); expect(url.href).to.equal(`${baseTimetableURL}11.html`); }); }); - describe('stopPdfUrlResolver', () => { + describe('stopTimetableUrlResolver', () => { it('should resolve correctly for HSL instance', () => { const hslStopTimetableURL = 'https://timetabletest.com/?foo=bar'; const timetableHandler = timetables.default.HSL; const stop = { gtfsId: 'HSL:1122127' }; const date = '20231031'; const lang = 'en'; - const url = timetableHandler.stopPdfUrlResolver( + const url = timetableHandler.stopTimetableUrlResolver( hslStopTimetableURL, stop, date, @@ -54,9 +49,13 @@ describe('timetableConfigUtils', () => { ); }); it('should resolve correctly for tampere instance', () => { + const baseTimetableURL = 'https://timetabletest.com/timetables/'; const timetableHandler = timetables.default.tampere; const stop = { gtfsId: 'tampere:0053' }; - const url = timetableHandler.stopPdfUrlResolver(baseTimetableURL, stop); + const url = timetableHandler.stopTimetableUrlResolver( + baseTimetableURL, + stop, + ); expect(url.href).to.equal(`${baseTimetableURL}53.pdf`); }); });