forked from simrail/simrail.pro
fix(backend): escape regex search
This commit is contained in:
parent
10a5fa7556
commit
14be22c46f
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Aleksander <alekswilc> 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!')
|
||||
})();
|
@ -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({
|
||||
|
@ -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[] = [];
|
||||
|
||||
|
@ -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[] = [];
|
||||
|
@ -101,12 +101,19 @@ export const trainsList = [
|
||||
],
|
||||
},
|
||||
{
|
||||
train: "EN96",
|
||||
train: "EN76",
|
||||
pattern: [
|
||||
"Elf/EN76-*",
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
train: 'EN96',
|
||||
pattern: [
|
||||
'Elf/EN96-*',
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
train: "EP07",
|
||||
pattern: [
|
||||
|
@ -22,4 +22,10 @@ export const removeProperties = <T>(data: any, names: string[]) =>
|
||||
delete data[ name ];
|
||||
}
|
||||
return data as T;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
|
||||
export const escapeRegexString = (str: string) => {
|
||||
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
@ -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 <div
|
||||
@ -39,7 +40,8 @@ export const ProfileCard = ({ data }: { data: TProfileData }) =>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<h3 className="mb-1.5 text-2xl font-semibold text-black dark:text-white">
|
||||
{ data.steam.personname } { data.player.verified && <FaCheck className={ "inline text-meta-3 ml-1" }/> }
|
||||
{ data.steam.personname } { data.player.verified &&
|
||||
<FaCheck className={ "inline text-meta-3 ml-1" }/> }
|
||||
</h3>
|
||||
|
||||
<div
|
||||
@ -76,24 +78,27 @@ export const ProfileCard = ({ data }: { data: TProfileData }) =>
|
||||
{ t("profile.trains.train") }
|
||||
</h5>
|
||||
</div>
|
||||
<div className="p-2.5 text-center xl:p-5">
|
||||
<div className="p-2.5 text-center xl:p-5 cursor-pointer"
|
||||
onClick={ () => setSortTrainsBy("distance") }>
|
||||
<h5 className="text-sm font-medium uppercase xsm:text-base">
|
||||
{ t("profile.trains.distance") }
|
||||
</h5>
|
||||
</div>
|
||||
<div className="hidden sm:block p-2.5 text-center xl:p-5">
|
||||
<div className="hidden sm:block p-2.5 text-center xl:p-5 cursor-pointer"
|
||||
onClick={ () => setSortTrainsBy("score") }>
|
||||
<h5 className="text-sm font-medium uppercase xsm:text-base">
|
||||
{ t("profile.trains.points") }
|
||||
</h5>
|
||||
</div>
|
||||
<div className="p-2.5 text-center xl:p-5">
|
||||
<div className="p-2.5 text-center xl:p-5 cursor-pointer"
|
||||
onClick={ () => setSortTrainsBy("time") }>
|
||||
<h5 className="text-sm font-medium uppercase xsm:text-base">
|
||||
{ t("profile.trains.time") }
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ 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 }) =>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
{ 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 <div
|
||||
@ -160,7 +165,7 @@ export const ProfileCard = ({ data }: { data: TProfileData }) =>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center p-2.5 lg:p-5">
|
||||
<p className="text-meta-3">{formatTime(station.time) }</p>
|
||||
<p className="text-meta-3">{ formatTime(station.time) }</p>
|
||||
</div>
|
||||
</div>;
|
||||
}) }
|
||||
|
Loading…
x
Reference in New Issue
Block a user