+
+This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements.
+
+You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see .
+Standard License Header
+Copyright (C) [year] [name of author]
+
+This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with this program. If not, see .
diff --git a/package.json b/package.json
index b779718e..15135dc9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "hsl-routemap-server",
- "version": "0.1.0",
+ "version": "1.1.0",
"description": "HSL Routemap server",
"main": "index.js",
"scripts": {
@@ -30,7 +30,7 @@
"url": "git+https://github.com/HSLdevcom/hsl-routemap-server.git"
},
"author": "",
- "license": "MIT",
+ "license": "AGPL-3.0-only",
"bugs": {
"url": "https://github.com/HSLdevcom/hsl-routemap-server/issues"
},
@@ -96,13 +96,14 @@
"pg": "^8.7.3",
"prop-types": "^15.6.0",
"puppeteer": "^15.4.1",
- "react": "16.8.6",
+ "react": "18.2.0",
"react-apollo": "^2.0.1",
- "react-dom": "16.8.6",
+ "react-dom": "18.2.0",
"recompose": "^0.30.0",
"segseg": "^0.2.2",
"serve": "^13.0.2",
"uuid": "^3.1.0",
+ "validator": "^13.15.0",
"viewport-mercator-project": "^4.1.1"
}
}
diff --git a/scripts/auth/authEndpoints.js b/scripts/auth/authEndpoints.js
index 44e4e009..9bfaf89f 100644
--- a/scripts/auth/authEndpoints.js
+++ b/scripts/auth/authEndpoints.js
@@ -1,19 +1,26 @@
const { get, last, clone } = require('lodash');
const AuthService = require('./authService');
+const validator = require('validator');
const { DOMAINS_ALLOWED_TO_LOGIN, ROUTEMAP_TEST_GROUP } = require('../../constants');
const allowedDomains = DOMAINS_ALLOWED_TO_LOGIN.split(',');
const hasAllowedDomain = async (userInfo) => {
- const groupNames = get(userInfo, 'groups');
- const domain = last(userInfo.email.toLowerCase().split('@')) || '';
+ const groups = get(userInfo, 'groups');
- if (groupNames.includes(ROUTEMAP_TEST_GROUP)) {
+ const emailValidationOptions = {
+ host_whitelist: allowedDomains,
+ };
+
+ if (groups.includes(ROUTEMAP_TEST_GROUP)) {
return true;
}
- if (!allowedDomains.includes(domain)) {
+ if (
+ !validator.isEmail(userInfo.email, emailValidationOptions) &&
+ !groups.includes(ROUTEMAP_TEST_GROUP)
+ ) {
console.log(`User does not have allowed domain. Logging out.`);
return false;
}
diff --git a/scripts/worker.js b/scripts/worker.js
index 46175a6f..1c7774a9 100644
--- a/scripts/worker.js
+++ b/scripts/worker.js
@@ -89,11 +89,14 @@ async function renderComponent(options) {
timeout: 5 * 60000,
};
- const contents = await page.pdf(printOptions);
-
- await fs.outputFile(pdfPath(id), contents);
- await page.close();
- await uploadPosterToCloud(pdfPath(id));
+ try {
+ const contents = await page.pdf(printOptions);
+ await fs.outputFile(pdfPath(id), contents);
+ await page.close();
+ await uploadPosterToCloud(pdfPath(id));
+ } catch (e) {
+ throw new Error('PDF Generation failed', e);
+ }
}
async function renderComponentRetry(options) {
diff --git a/src/components/labelPlacement/itemFixed.js b/src/components/labelPlacement/itemFixed.js
index c6d561b0..dabe87ba 100644
--- a/src/components/labelPlacement/itemFixed.js
+++ b/src/components/labelPlacement/itemFixed.js
@@ -6,6 +6,7 @@ class ItemFixed extends Component {
super(props);
this.state = { top: props.top, left: props.left };
this.visible = true;
+ this.root = React.createRef();
}
setPosition(top, left) {
@@ -46,10 +47,11 @@ class ItemFixed extends Component {
return (
{
+ ref={(ref) => {
this.root = ref;
}}
- style={style}>
+ style={style}
+ >
{this.props.children}
);
diff --git a/src/components/labelPlacement/itemPositioned.js b/src/components/labelPlacement/itemPositioned.js
index 68eb98e7..236ea9dc 100644
--- a/src/components/labelPlacement/itemPositioned.js
+++ b/src/components/labelPlacement/itemPositioned.js
@@ -10,6 +10,7 @@ class ItemPositioned extends Component {
left: props.x,
visible: props.visible || !props.allowHidden,
};
+ this.root = React.createRef();
}
setPosition(top, left, visible) {
@@ -59,10 +60,11 @@ class ItemPositioned extends Component {
if (this.state.visible) {
return (
{
+ ref={(ref) => {
this.root = ref;
}}
- style={style}>
+ style={style}
+ >
{this.props.children}
);
diff --git a/src/components/routeMap/routeMap.js b/src/components/routeMap/routeMap.js
index 9826f819..79e65fc7 100644
--- a/src/components/routeMap/routeMap.js
+++ b/src/components/routeMap/routeMap.js
@@ -188,11 +188,16 @@ const RouteMap = (props) => {
))}
{projectedSymbols &&
projectedSymbols.length > 0 &&
- projectedSymbols.map((symbol, index) => (
-
-
-
- ))}
+ projectedSymbols.map((symbol, index) => {
+ const matchValues = symbol.size.match(/\d+/);
+ const symbolSizeNumber = matchValues ? parseInt(matchValues[0], 10) : null;
+ const offset = symbolSizeNumber ? symbolSizeNumber / 2 : 0;
+ return (
+
+
+
+ );
+ })}
{props.projectedTerminuses.map((terminus, index) => (
WrappedComponent =>
- class PromiseWrapper extends Component {
- constructor(props) {
- super(props);
- this.state = { loading: !!props[propName] };
- }
-
- componentDidMount() {
- if (this.props[propName]) {
- this.handlePromise(this.props[propName]);
- }
- }
+const hocFactory = (propName) => (WrappedComponent) => (props) => {
+ const [state, setState] = useState({
+ loading: !!props[propName],
+ value: null,
+ error: null,
+ });
- componentWillReceiveProps(nextProps) {
- if (nextProps[propName] && nextProps[propName] !== this.props[propName]) {
- this.setState({ loading: true });
- this.handlePromise(nextProps[propName]);
- }
- }
-
- componentWillUnmount() {
- this.promise = null;
- }
+ useEffect(() => {
+ let isMounted = true;
+ const promise = props[propName];
- handlePromise(promise) {
- this.promise = promise;
+ if (promise) {
+ setState((prevState) => ({ ...prevState, loading: true }));
renderQueue.add(promise);
+
promise
- .then(value => {
- const callback = () => renderQueue.remove(promise);
- if (this.promise !== promise) {
- callback();
- } else {
- this.setState({ value, loading: false }, callback);
+ .then((value) => {
+ if (isMounted) {
+ setState({ value, loading: false, error: null });
+ renderQueue.remove(promise);
}
})
- .catch(error => {
- const callback = () => renderQueue.remove(promise, { error });
- if (this.promise !== promise) {
- callback();
- } else {
- this.setState({ error, loading: false }, callback);
+ .catch((error) => {
+ if (isMounted) {
+ setState({ error, loading: false });
+ renderQueue.remove(promise, { error });
}
});
}
- render() {
- if (this.state.loading || this.state.error) {
- return null;
- }
- const props = { ...this.props, [propName]: this.state.value };
- return ;
- }
- };
+ return () => {
+ isMounted = false;
+ renderQueue.remove(promise);
+ };
+ }, [props[propName]]);
+
+ const { loading, error, value } = state;
+
+ if (loading || error) {
+ return null;
+ }
+
+ const newProps = { ...props, [propName]: value };
+ return ;
+};
export default hocFactory;
diff --git a/yarn.lock b/yarn.lock
index c8cfdf89..0253b82f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4980,8 +4980,8 @@ hpack.js@^2.1.6:
wbuf "^1.1.0"
hsl-map-style@hsldevcom/hsl-map-style#master:
- version "1.1.2"
- resolved "https://codeload.github.com/hsldevcom/hsl-map-style/tar.gz/207a8de2664c9a50b5a5f886d30f5b1628f995c7"
+ version "1.2.0"
+ resolved "https://codeload.github.com/hsldevcom/hsl-map-style/tar.gz/68b1642ce364ebcea115bc3f20465d3c2ee83c0d"
dependencies:
lodash "^4.17.4"
@@ -7475,7 +7475,7 @@ prompt@0.2.14:
utile "0.2.x"
winston "0.8.x"
-prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
+prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -7687,15 +7687,13 @@ react-apollo@^2.0.1:
ts-invariant "^0.4.2"
tslib "^1.9.3"
-react-dom@16.8.6:
- version "16.8.6"
- resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f"
- integrity sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==
+react-dom@18.2.0:
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
+ integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
dependencies:
loose-envify "^1.1.0"
- object-assign "^4.1.1"
- prop-types "^15.6.2"
- scheduler "^0.13.6"
+ scheduler "^0.23.0"
react-hot-loader@^4.13.1:
version "4.13.1"
@@ -7721,15 +7719,12 @@ react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4:
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
-react@16.8.6:
- version "16.8.6"
- resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
- integrity sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==
+react@18.2.0:
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
+ integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
dependencies:
loose-envify "^1.1.0"
- object-assign "^4.1.1"
- prop-types "^15.6.2"
- scheduler "^0.13.6"
read@1.0.x:
version "1.0.7"
@@ -8149,13 +8144,12 @@ sax@>=0.6.0:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
-scheduler@^0.13.6:
- version "0.13.6"
- resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.6.tgz#466a4ec332467b31a91b9bf74e5347072e4cd889"
- integrity sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==
+scheduler@^0.23.0:
+ version "0.23.0"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
+ integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
dependencies:
loose-envify "^1.1.0"
- object-assign "^4.1.1"
schema-utils@^1.0.0:
version "1.0.0"
@@ -9408,6 +9402,11 @@ uuid@^9.0.0:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
+validator@^13.15.0:
+ version "13.15.0"
+ resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.0.tgz#2dc7ce057e7513a55585109eec29b2c8e8c1aefd"
+ integrity sha512-36B2ryl4+oL5QxZ3AzD0t5SsMNGvTtQHpjgFO5tbNxfXbMFkY822ktCDe1MnlqV3301QQI9SLHDNJokDI+Z9pA==
+
vary@^1.1.2, vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"