Skip to content

Commit

Permalink
Merge pull request #2929 from HSLdevcom/DT-2167
Browse files Browse the repository at this point in the history
Dt 2167
  • Loading branch information
vesameskanen authored Oct 16, 2019
2 parents a7ae182 + 31e04e7 commit 55c9cd4
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 54 deletions.
13 changes: 9 additions & 4 deletions app/component/LangSelect.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
import PropTypes from 'prop-types';
import React from 'react';
import { routerShape } from 'react-router';
import connectToStores from 'fluxible-addons-react/connectToStores';
import moment from 'moment';
import ComponentUsageExample from './ComponentUsageExample';
import { setLanguage } from '../action/userPreferencesActions';
import { isBrowser } from '../util/browser';
import { replaceQueryParams } from '../util/queryUtils';

const selectLanguage = (executeAction, lang) => () => {
const selectLanguage = (executeAction, lang, router) => () => {
executeAction(setLanguage, lang);
if (lang !== 'en') {
// eslint-disable-next-line global-require, import/no-dynamic-require
require(`moment/locale/${lang}`);
}
moment.locale(lang);
replaceQueryParams(router, { locale: lang });
};

const language = (lang, currentLanguage, highlight, executeAction) => (
const language = (lang, currentLanguage, highlight, executeAction, router) => (
<button
id={`lang-${lang}`}
key={lang}
className={`${(highlight && 'selected') || ''} noborder lang`}
onClick={selectLanguage(executeAction, lang)}
onClick={selectLanguage(executeAction, lang, router)}
>
{lang}
</button>
);

const LangSelect = ({ currentLanguage }, { executeAction, config }) => {
const LangSelect = ({ currentLanguage }, { executeAction, config, router }) => {
if (isBrowser) {
return (
<div key="lang-select" id="lang-select">
Expand All @@ -36,6 +39,7 @@ const LangSelect = ({ currentLanguage }, { executeAction, config }) => {
currentLanguage,
lang === currentLanguage,
executeAction,
router,
),
)}
</div>
Expand Down Expand Up @@ -64,6 +68,7 @@ LangSelect.propTypes = {
LangSelect.contextTypes = {
executeAction: PropTypes.func.isRequired,
config: PropTypes.object.isRequired,
router: routerShape.isRequired,
};

const connected = connectToStores(
Expand Down
5 changes: 4 additions & 1 deletion app/component/SummaryPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
/* eslint-disable react/no-array-index-key */
import React from 'react';
import Relay from 'react-relay/classic';
import cookie from 'react-cookie';
import moment from 'moment';
import findIndex from 'lodash/findIndex';
import get from 'lodash/get';
Expand Down Expand Up @@ -485,7 +486,8 @@ const containerComponent = Relay.createContainer(SummaryPageWithBreakpoint, {
preferred: $preferred,
unpreferred: $unpreferred,
allowedBikeRentalNetworks: $allowedBikeRentalNetworks,
),
locale: $locale,
),
{
${SummaryPlanContainer.getFragment('plan')}
${ItineraryTab.getFragment('searchTime')}
Expand Down Expand Up @@ -542,6 +544,7 @@ const containerComponent = Relay.createContainer(SummaryPageWithBreakpoint, {
walkSpeed: null,
wheelchair: null,
allowedBikeRentalNetworks: null,
locale: cookie.load('lang') || 'fi',
},
...defaultRoutingSettings,
},
Expand Down
2 changes: 2 additions & 0 deletions app/component/SummaryPlanContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ class SummaryPlanContainer extends React.Component {
$itineraryFiltering: Float!,
$modeWeight: InputModeWeight!,
$allowedBikeRentalNetworks: [String]!,
$locale: String!,
) { viewer {
plan(
fromPlace:$fromPlace,
Expand Down Expand Up @@ -390,6 +391,7 @@ class SummaryPlanContainer extends React.Component {
itineraryFiltering: $itineraryFiltering,
modeWeight: $modeWeight,
allowedBikeRentalNetworks: $allowedBikeRentalNetworks,
locale: $locale,
) {itineraries {startTime,endTime}}
}
}`;
Expand Down
2 changes: 2 additions & 0 deletions app/util/planParamUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ export const preparePlanParams = config => (
walkReluctance,
walkSpeed,
allowedBikeRentalNetworks,
locale,
},
},
},
Expand Down Expand Up @@ -401,6 +402,7 @@ export const preparePlanParams = config => (
settings,
intermediatePlaceLocations,
),
locale,
},
nullOrUndefined,
),
Expand Down
63 changes: 42 additions & 21 deletions server/reittiopasParameterMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,25 @@ import isFinite from 'lodash/isFinite';
import oldParamParser from '../app/util/oldParamParser';
import { getConfiguration } from '../app/config';

function formatQuery(query) {
const params = Object.keys(query)
.map(k => `${k}=${query[k]}`)
.join('&');

return `?${params}`;
}

function formatUrl(req) {
const query = formatQuery(req.query);
return `${req.path}?${query}`;
}

function removeUrlParam(req, param) {
if (req.query[param]) {
delete req.query[param];
}
const params = Object.keys(req.query)
.map(k => `${k}=${req.query[k]}`)
.join('&');
const url = `${req.path}?${params}`;

return url;
return formatUrl(req);
}

export function validateParams(req, config) {
Expand Down Expand Up @@ -55,14 +64,24 @@ export function validateParams(req, config) {
return url;
}

export const langParamParser = path => {
if (path.includes('/slangi/')) {
const newPath = path.replace('/slangi/', '/');
return newPath;
}
const lang = path.substring(0, 4);
const newPath = path.replace(lang, '/');
return newPath;
const fixLocaleParam = (req, lang) => {
// override locale query param with the selected language
req.query.locale = lang === 'slangi' ? 'fi' : lang;
return formatQuery(req.query);
};

export const dropPathLanguageAndFixLocaleParam = (req, lang) => {
return req.path.replace(`/${lang}/`, '/') + fixLocaleParam(req, lang);
};

const dropPathLanguageAndRedirect = (req, res, lang) => {
const trimmedUrl = dropPathLanguageAndFixLocaleParam(req, lang);
res.redirect(trimmedUrl);
};

const fixLocaleParamAndRedirect = (req, res, lang) => {
const fixedUrl = req.path + fixLocaleParam(req, lang);
res.redirect(fixedUrl);
};

export default function reittiopasParameterMiddleware(req, res, next) {
Expand All @@ -87,15 +106,17 @@ export default function reittiopasParameterMiddleware(req, res, next) {
req.query.to_in
) {
oldParamParser(req.query, config).then(url => res.redirect(url));
} else if (
['/fi/', '/en/', '/sv/', '/ru/', '/slangi/'].some(param =>
req.path.includes(param),
)
) {
const redirectPath = langParamParser(req.url);
res.redirect(redirectPath);
} else if (['fi', 'en', 'sv', 'ru', 'slangi'].includes(lang)) {
dropPathLanguageAndRedirect(req, res, lang);
} else {
next();
const { locale } = req.query;
const cookieLang = req.cookies.lang;

if (cookieLang && locale && cookieLang !== locale) {
fixLocaleParamAndRedirect(req, res, cookieLang);
} else {
next();
}
}
} else {
next();
Expand Down
8 changes: 7 additions & 1 deletion test/unit/component/LangSelect.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,15 @@ describe('LangSelect', () => {
'Europe/Helsinki|EET EEST|-20 -30|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 ' +
'WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|35e5',
};

const mockRouter = {
getCurrentLocation: () => '/',
replace: () => true,
};

configureMoment('sv', configWithMoment);
expect(moment.locale()).to.equal('sv');
selectLanguage(() => true, 'fi')();
selectLanguage(() => true, 'fi', mockRouter)();
expect(moment.locale()).to.equal('fi');
});
});
Expand Down
70 changes: 43 additions & 27 deletions test/unit/reittiopasParameterMiddleware.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@ import { expect } from 'chai';
import { describe, it } from 'mocha';
import {
validateParams,
langParamParser,
dropPathLanguageAndFixLocaleParam,
} from '../../server/reittiopasParameterMiddleware';

import config from '../../app/configurations/config.default';

const req = {
query: {
minTransferTime: '60',
modes: 'BUS,TRAM,RAIL,SUBWAY,FERRY,WALK,CITYBIKE',
transferPenalty: '0',
walkBoardCost: '540',
walkReluctance: '1.5',
walkSpeed: '1.5',
},
};

// validateParams returns an url if it is modified and it removes invalid
// parameteres from req.query => two ways to check if it did what it should

describe('reittiopasParameterMiddleware', () => {
describe('validateParams', () => {
const req = {
query: {
minTransferTime: '60',
modes: 'BUS,TRAM,RAIL,SUBWAY,FERRY,WALK,CITYBIKE',
transferPenalty: '0',
walkBoardCost: '540',
walkReluctance: '1.5',
walkSpeed: '1.5',
},
};

it('should not modify valid url', () => {
const url = validateParams(req, config);
expect(url).to.be.a('undefined');
Expand All @@ -44,28 +44,44 @@ describe('reittiopasParameterMiddleware', () => {
expect(req.query.modes).to.be.an('undefined');
});
});
describe('langParamParser', () => {
it('should return empty path', () => {
const path = '/en/';
const newPath = langParamParser(path);
expect(newPath).to.equal('/');

describe('dropLanguageAndSetLocaleParam', () => {
const req = {
path: '/en/',
query: {
locale: 'fi',
},
};

it('should return empty path with "locale" query param', () => {
const relativeUrl = dropPathLanguageAndFixLocaleParam(req, 'en');
expect(relativeUrl).to.equal('/?locale=en');
});

it('should return path without language parameter', () => {
const path =
it('should return path without language', () => {
req.path =
'/sv/reitti/Rautatientori%2C%20Helsinki%3A%3A60.171283%2C24.942572/Pasila%2C%20Helsinki%3A%3A60.199017%2C24.933973';
const newPath = langParamParser(path);
expect(newPath).to.equal(
'/reitti/Rautatientori%2C%20Helsinki%3A%3A60.171283%2C24.942572/Pasila%2C%20Helsinki%3A%3A60.199017%2C24.933973',
const relativeUrl = dropPathLanguageAndFixLocaleParam(req, 'sv');
expect(relativeUrl).to.equal(
'/reitti/Rautatientori%2C%20Helsinki%3A%3A60.171283%2C24.942572/Pasila%2C%20Helsinki%3A%3A60.199017%2C24.933973?locale=sv',
);
});

it('should not ignore URL parameters', () => {
const path =
'/en/reitti/Otaniemi,%20Espoo::60.187938,24.83182/Rautatientori,%20Asemanaukio%202,%20Helsinki::60.170384,24.939846?time=1565074800&arriveBy=false&utm_campaign=hsl.fi&utm_source=etusivu-reittihaku&utm_medium=referral';
const newPath = langParamParser(path);
expect(newPath).to.equal(
'/reitti/Otaniemi,%20Espoo::60.187938,24.83182/Rautatientori,%20Asemanaukio%202,%20Helsinki::60.170384,24.939846?time=1565074800&arriveBy=false&utm_campaign=hsl.fi&utm_source=etusivu-reittihaku&utm_medium=referral',
req.path =
'/en/reitti/Otaniemi,%20Espoo::60.187938,24.83182/Rautatientori,%20Asemanaukio%202,%20Helsinki::60.170384,24.939846';
req.query = {
time: 1565074800,
arriveBy: false,
utm_campaign: 'hsl.fi',
utm_source: 'etusivu-reittihaku',
utm_medium: 'referral',
locale: 'fi',
};

const relativeUrl = dropPathLanguageAndFixLocaleParam(req, 'en');
expect(relativeUrl).to.equal(
'/reitti/Otaniemi,%20Espoo::60.187938,24.83182/Rautatientori,%20Asemanaukio%202,%20Helsinki::60.170384,24.939846?time=1565074800&arriveBy=false&utm_campaign=hsl.fi&utm_source=etusivu-reittihaku&utm_medium=referral&locale=en',
);
});
});
Expand Down

0 comments on commit 55c9cd4

Please sign in to comment.