diff --git a/packages/backend/scripts/mongo-migration.js b/packages/backend/scripts/mongo-migration.js deleted file mode 100644 index 09cc3ea..0000000 --- a/packages/backend/scripts/mongo-migration.js +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2024 Aleksander WilczyƄski (aleks@alekswilc.dev) - * - * 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. - * - * See LICENSE for more. - */ - -import { connect } from 'mongoose'; -import { Model, model, Schema } from 'mongoose'; - - - - -(async () => { - await connect(process.env.MONGO_URI); - // #region model - const schema = new Schema({ - id: { - type: String, - required: true - }, - steam: { - type: String, - required: true - }, - steamName: { - type: String, - required: true - }, - - trainStats: { - type: Object, - required: false, - default: {} - }, - dispatcherStats: { - type: Object, - required: false, - default: {} - }, - trainTime: { - type: Number, - required: false, - default: 0 - }, - trainPoints: { - type: Number, - required: false, - default: 0 - }, - trainDistance: { - type: Number, - required: false, - default: 0 - }, - dispatcherTime: { - type: Number, - required: false, - default: 0 - }, - }); - - const MProfile = model('profile', schema); - // #endregion - const _ = await MProfile.find({}); - - for (const x of _) { - /* - dispatcherTime: number; - trainTime: number - trainPoints: number - trainDistance: number*/ - x.trainPoints = Object.values(x.trainStats).length === 1 ? - Object.values(x.trainStats)[0].score : - Object.values(x.trainStats).reduce((acc, curr) => acc + curr.score, 0) - - x.trainDistance = Object.values(x.trainStats).length === 1 ? - Object.values(x.trainStats)[0].distance : - Object.values(x.trainStats).reduce((acc, curr) => acc + curr.distance, 0) - - x.trainTime = Object.values(x.trainStats).length === 1 ? - Object.values(x.trainStats)[0].trainTime : - Object.values(x.trainStats).reduce((acc, curr) => acc + curr.trainTime, 0) - - x.dispatcherTime = Object.values(x.dispatcherStats).length === 1 ? - Object.values(x.dispatcherStats)[0].time : - Object.values(x.dispatcherStats).reduce((acc, curr) => acc + curr.time, 0) - - console.log('updated ' + x.steamName) - await MProfile.updateOne({ id: x.id }, { trainPoints: x.trainPoints, trainDistance: x.trainDistance, dispatcherTime: x.dispatcherTime, trainTime: x.trainTime }) - }; - - - console.log('done!') -})(); \ No newline at end of file diff --git a/packages/backend/src/http/routes/leaderboard.ts b/packages/backend/src/http/routes/leaderboard.ts index f7a1cf7..a119ea6 100644 --- a/packages/backend/src/http/routes/leaderboard.ts +++ b/packages/backend/src/http/routes/leaderboard.ts @@ -18,7 +18,7 @@ import { Router } from "express"; import { PipelineStage } from "mongoose"; import { IProfile, MProfile, raw_schema } from "../../mongo/profile.js"; import { SuccessResponseBuilder } from "../responseBuilder.js"; -import { removeProperties } from "../../util/functions.js"; +import { escapeRegexString, removeProperties } from "../../util/functions.js"; const generateSearch = (regex: RegExp) => [ { @@ -37,7 +37,7 @@ export class LeaderboardRoute app.get("/train", async (req, res) => { - const s = req.query.q?.toString().split(",").map(x => new RegExp(x, "i")); + const s = req.query.q?.toString().split(",").map(x => new RegExp(escapeRegexString(x), "i")); const filter: PipelineStage[] = []; @@ -64,7 +64,7 @@ export class LeaderboardRoute app.get("/station", async (req, res) => { - const s = req.query.q?.toString().split(",").map(x => new RegExp(x, "i")); + const s = req.query.q?.toString().split(",").map(x => new RegExp(escapeRegexString(x), "i")); const filter: PipelineStage[] = []; s && filter.push({ diff --git a/packages/backend/src/http/routes/stations.ts b/packages/backend/src/http/routes/stations.ts index f374c19..11976a1 100644 --- a/packages/backend/src/http/routes/stations.ts +++ b/packages/backend/src/http/routes/stations.ts @@ -22,7 +22,7 @@ import { PipelineStage } from "mongoose"; import { MBlacklist } from "../../mongo/blacklist.js"; import { SteamUtil } from "../../util/SteamUtil.js"; import { GitUtil } from "../../util/git.js"; -import { removeProperties } from "../../util/functions.js"; +import { escapeRegexString, removeProperties } from "../../util/functions.js"; import { SuccessResponseBuilder } from "../responseBuilder.js"; import { MProfile } from "../../mongo/profile.js"; @@ -52,7 +52,7 @@ export class StationsRoute app.get("/", async (req, res) => { - const s = req.query.q?.toString().split(",").map(x => new RegExp(x, "i")); + const s = req.query.q?.toString().split(",").map(x => new RegExp(escapeRegexString(x), "i")); const profiles = await MProfile.find({ verified: true }); const filter: PipelineStage[] = []; diff --git a/packages/backend/src/http/routes/trains.ts b/packages/backend/src/http/routes/trains.ts index 5414c2f..571b2a2 100644 --- a/packages/backend/src/http/routes/trains.ts +++ b/packages/backend/src/http/routes/trains.ts @@ -23,7 +23,7 @@ import { MBlacklist } from "../../mongo/blacklist.js"; import { SteamUtil } from "../../util/SteamUtil.js"; import { GitUtil } from "../../util/git.js"; import { SuccessResponseBuilder } from "../responseBuilder.js"; -import { removeProperties } from "../../util/functions.js"; +import { escapeRegexString, removeProperties } from "../../util/functions.js"; import { MProfile } from "../../mongo/profile.js"; const generateSearch = (regex: RegExp) => [ @@ -49,7 +49,7 @@ export class TrainsRoute app.get("/", async (req, res) => { - const s = req.query.q?.toString().split(",").map(x => new RegExp(x, "i")); + const s = req.query.q?.toString().split(",").map(x => new RegExp(escapeRegexString(x), "i")); const profiles = await MProfile.find({ verified: true }); const filter: PipelineStage[] = []; diff --git a/packages/backend/src/util/contants.ts b/packages/backend/src/util/contants.ts index 62ea05c..4412671 100644 --- a/packages/backend/src/util/contants.ts +++ b/packages/backend/src/util/contants.ts @@ -101,12 +101,19 @@ export const trainsList = [ ], }, { - train: "EN96", + train: "EN76", pattern: [ "Elf/EN76-*", ], }, + { + train: 'EN96', + pattern: [ + 'Elf/EN96-*', + ] + }, + { train: "EP07", pattern: [ diff --git a/packages/backend/src/util/functions.ts b/packages/backend/src/util/functions.ts index f497a85..03d2621 100644 --- a/packages/backend/src/util/functions.ts +++ b/packages/backend/src/util/functions.ts @@ -22,4 +22,10 @@ export const removeProperties = (data: any, names: string[]) => delete data[ name ]; } return data as T; -}; \ No newline at end of file +}; + + +// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex +export const escapeRegexString = (str: string) => { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} \ No newline at end of file diff --git a/packages/frontend/src/components/pages/profile/Profile.tsx b/packages/frontend/src/components/pages/profile/Profile.tsx index d2ccbd8..724dfb3 100644 --- a/packages/frontend/src/components/pages/profile/Profile.tsx +++ b/packages/frontend/src/components/pages/profile/Profile.tsx @@ -19,13 +19,14 @@ import { TProfileData } from "../../../types/profile.ts"; import { useTranslation } from "react-i18next"; import { ArrowIcon } from "../../mini/icons/ArrowIcon.tsx"; import { formatTime } from "../../../util/time.ts"; -import { FaCheck } from 'react-icons/fa6'; +import { FaCheck } from "react-icons/fa6"; export const ProfileCard = ({ data }: { data: TProfileData }) => { const [ showTrains, setShowTrains ] = useState(false); const [ showStations, setShowStations ] = useState(false); + const [ sortTrainsBy, setSortTrainsBy ] = useState<"time" | "score" | "distance">("score"); const { t } = useTranslation(); return

- { data.steam.personname } { data.player.verified && } + { data.steam.personname } { data.player.verified && + }

{ t("profile.trains.train") }
-
+
setSortTrainsBy("distance") }>
{ t("profile.trains.distance") }
-
+
setSortTrainsBy("score") }>
{ t("profile.trains.points") }
-
+
setSortTrainsBy("time") }>
{ t("profile.trains.time") }
- { Object.keys(data.player.trainStats).map(trainName => + { Object.keys(data.player.trainStats).sort((a, b) => data.player.trainStats[ b ][ sortTrainsBy ] - data.player.trainStats[ a ][ sortTrainsBy ]).map(trainName => { const train = data.player.trainStats[ trainName ]; @@ -146,7 +151,7 @@ export const ProfileCard = ({ data }: { data: TProfileData }) =>
- { Object.keys(data.player.dispatcherStats).map(stationName => + { Object.keys(data.player.dispatcherStats).sort((a, b) => data.player.dispatcherStats[ b ].time - data.player.dispatcherStats[ a ].time).map(stationName => { const station = data.player.dispatcherStats[ stationName ]; return
-

{formatTime(station.time) }

+

{ formatTime(station.time) }

; }) }