updated Nav-Search + removed string-sanitizer + added csgo-sharecode
Some checks failed
CSGOWTF/csgowtf/pipeline/head There was a failure building this commit
Some checks failed
CSGOWTF/csgowtf/pipeline/head There was a failure building this commit
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
"axios": "^0.26.1",
|
"axios": "^0.26.1",
|
||||||
"bootstrap": "^5.1.3",
|
"bootstrap": "^5.1.3",
|
||||||
"bootstrap-icons": "^1.8.1",
|
"bootstrap-icons": "^1.8.1",
|
||||||
|
"csgo-sharecode": "^3.0.1",
|
||||||
"echarts": "^5.3.1",
|
"echarts": "^5.3.1",
|
||||||
"fork-awesome": "^1.2.0",
|
"fork-awesome": "^1.2.0",
|
||||||
"http-status-codes": "^2.2.0",
|
"http-status-codes": "^2.2.0",
|
||||||
@@ -21,7 +22,6 @@
|
|||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"luxon": "^2.3.1",
|
"luxon": "^2.3.1",
|
||||||
"pinia": "^2.0.12",
|
"pinia": "^2.0.12",
|
||||||
"string-sanitizer": "^2.0.2",
|
|
||||||
"vue": "^3.2.31",
|
"vue": "^3.2.31",
|
||||||
"vue-matomo": "^4.1.0",
|
"vue-matomo": "^4.1.0",
|
||||||
"vue-router": "^4.0.14",
|
"vue-router": "^4.0.14",
|
||||||
|
@@ -32,7 +32,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<form
|
<form
|
||||||
id="searchform"
|
id="search-form"
|
||||||
class="d-flex"
|
class="d-flex"
|
||||||
@keydown.enter.prevent="parseSearch"
|
@keydown.enter.prevent="parseSearch"
|
||||||
@submit.prevent="parseSearch"
|
@submit.prevent="parseSearch"
|
||||||
@@ -47,8 +47,8 @@
|
|||||||
aria-label="Search"
|
aria-label="Search"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="form-control bg-transparent border-0"
|
class="form-control bg-transparent border-0"
|
||||||
placeholder="SteamID64, Profile Link or Custom URL"
|
placeholder="SteamID, Profile Link or ShareCode"
|
||||||
title="SteamID64, Profile Link or Custom URL"
|
title="SteamID, Profile Link or ShareCode"
|
||||||
type="search"
|
type="search"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
@@ -67,11 +67,24 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from "vue";
|
import { reactive } from "vue";
|
||||||
import { closeNav, closeNavEventListener, GetUser, GoToPlayer } from "@/utils";
|
|
||||||
import {
|
import {
|
||||||
CUSTOM_URL_PATTERN,
|
closeNav,
|
||||||
|
closeNavEventListener,
|
||||||
|
GetMatchDetails,
|
||||||
|
GetUser,
|
||||||
|
GoToMatch,
|
||||||
|
GoToPlayer,
|
||||||
|
ParseMatch,
|
||||||
|
parseShareCode,
|
||||||
|
sleep,
|
||||||
|
stringSanitizer,
|
||||||
|
} from "@/utils";
|
||||||
|
import {
|
||||||
|
CUSTOM_URL_BASE,
|
||||||
ID64_PATTERN,
|
ID64_PATTERN,
|
||||||
PROFILE_URL_PATTERN,
|
MATCH_SHARE_URL_BASE,
|
||||||
|
PROFILE_URL_BASE,
|
||||||
|
SHARECODE_REGEX,
|
||||||
VANITY_PATTERN,
|
VANITY_PATTERN,
|
||||||
} from "@/constants";
|
} from "@/constants";
|
||||||
import { StatusCodes as STATUS } from "http-status-codes";
|
import { StatusCodes as STATUS } from "http-status-codes";
|
||||||
@@ -89,46 +102,57 @@ const data = reactive({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const parseSearch = async () => {
|
const parseSearch = async () => {
|
||||||
const input = data.searchInput;
|
let input = data.searchInput;
|
||||||
|
|
||||||
searchParamsStore.vanity_url = "";
|
searchParamsStore.$reset();
|
||||||
searchParamsStore.id64 = "";
|
|
||||||
|
|
||||||
if (data.searchInput !== "") {
|
if (data.searchInput !== "") {
|
||||||
if (ID64_PATTERN.test(input)) {
|
// remove various base-urls + cut excess parameters
|
||||||
searchParamsStore.id64 = input;
|
input = input
|
||||||
} else if (input.match(CUSTOM_URL_PATTERN)) {
|
.replace(MATCH_SHARE_URL_BASE, "")
|
||||||
searchParamsStore.vanity_url = input.split("/")[4].split("?")[0];
|
.replace(CUSTOM_URL_BASE, "")
|
||||||
} else if (input.match(PROFILE_URL_PATTERN)) {
|
.replace(PROFILE_URL_BASE, "")
|
||||||
const tmp = input.split("/")[4].split("?")[0];
|
.split("/")[0]
|
||||||
if (ID64_PATTERN.test(tmp)) {
|
.split("?")[0];
|
||||||
searchParamsStore.id64 = tmp;
|
|
||||||
|
// process shareCode
|
||||||
|
const tmpShareCode = Array.from(input.matchAll(SHARECODE_REGEX));
|
||||||
|
const inputShareCode = tmpShareCode.length > 0 ? tmpShareCode[0][0] : "";
|
||||||
|
searchParamsStore.shareCode = SHARECODE_REGEX.test(inputShareCode)
|
||||||
|
? inputShareCode
|
||||||
|
: "";
|
||||||
|
|
||||||
|
// process id64
|
||||||
|
const tmpId64 = Array.from(input.matchAll(ID64_PATTERN));
|
||||||
|
const inputId64 = tmpId64.length > 0 ? tmpId64[0][0] : "";
|
||||||
|
searchParamsStore.id64 = ID64_PATTERN.test(inputId64) ? inputId64 : "";
|
||||||
|
|
||||||
|
// process vanityUrl
|
||||||
|
if (searchParamsStore.shareCode === "" && searchParamsStore.id64 === "") {
|
||||||
|
if (input.includes(CUSTOM_URL_BASE)) {
|
||||||
|
input = input.replace(CUSTOM_URL_BASE, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VANITY_PATTERN.test(input)) {
|
||||||
|
searchParamsStore.vanityUrl = stringSanitizer(input);
|
||||||
|
} else {
|
||||||
|
const info: infoState = {
|
||||||
|
statusCode: STATUS.NOT_ACCEPTABLE,
|
||||||
|
message:
|
||||||
|
'Only alphanumeric symbols, "_", and "-", between 3-32 characters',
|
||||||
|
type: "warning",
|
||||||
|
};
|
||||||
|
infoStateStore.addInfo(info);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
searchParamsStore.vanity_url = input;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
// GetUser
|
||||||
searchParamsStore.vanity_url !== "" &&
|
if (searchParamsStore.id64 !== "" || searchParamsStore.vanityUrl !== "") {
|
||||||
!VANITY_PATTERN.test(searchParamsStore.vanity_url)
|
const [resData, info] = await GetUser(
|
||||||
) {
|
searchParamsStore.vanityUrl || searchParamsStore.id64
|
||||||
const info: infoState = {
|
|
||||||
statusCode: STATUS.NOT_ACCEPTABLE,
|
|
||||||
message:
|
|
||||||
'Only alphanumeric symbols, "_", and "-", between 3-32 characters',
|
|
||||||
type: "warning",
|
|
||||||
};
|
|
||||||
infoStateStore.addInfo(info);
|
|
||||||
searchParamsStore.vanity_url = "";
|
|
||||||
data.searchInput = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchParamsStore.id64 !== "" || searchParamsStore.vanity_url !== "") {
|
|
||||||
const resData = await GetUser(
|
|
||||||
playerDetailsStore,
|
|
||||||
searchParamsStore.vanity_url || searchParamsStore.id64
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (info.message !== "") infoStateStore.addInfo(info);
|
||||||
if (resData !== null) {
|
if (resData !== null) {
|
||||||
data.searchInput = "";
|
data.searchInput = "";
|
||||||
const activeElem = document.activeElement as HTMLInputElement;
|
const activeElem = document.activeElement as HTMLInputElement;
|
||||||
@@ -136,15 +160,38 @@ const parseSearch = async () => {
|
|||||||
|
|
||||||
playerDetailsStore.playerDetails = resData;
|
playerDetailsStore.playerDetails = resData;
|
||||||
|
|
||||||
if (searchParamsStore.vanity_url) {
|
if (searchParamsStore.vanityUrl) {
|
||||||
closeNav("mainNav");
|
closeNav("mainNav");
|
||||||
GoToPlayer(searchParamsStore.vanity_url);
|
GoToPlayer(searchParamsStore.vanityUrl);
|
||||||
} else if (searchParamsStore.id64) {
|
} else if (searchParamsStore.id64) {
|
||||||
closeNav("mainNav");
|
closeNav("mainNav");
|
||||||
GoToPlayer(searchParamsStore.id64);
|
GoToPlayer(searchParamsStore.id64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseMatch
|
||||||
|
if (searchParamsStore.shareCode !== "") {
|
||||||
|
data.searchInput = "";
|
||||||
|
|
||||||
|
const matchId = parseShareCode(searchParamsStore.shareCode);
|
||||||
|
let info = await ParseMatch(searchParamsStore.shareCode);
|
||||||
|
|
||||||
|
if (info.message !== "") infoStateStore.addInfo(info);
|
||||||
|
if (info.statusCode === STATUS.OK) GoToMatch(matchId);
|
||||||
|
|
||||||
|
if (info.statusCode === STATUS.ACCEPTED) {
|
||||||
|
let [res, info] = await GetMatchDetails(matchId);
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
if (res !== null && res.parsed) break;
|
||||||
|
[res, info] = await GetMatchDetails(matchId);
|
||||||
|
|
||||||
|
sleep(2000);
|
||||||
|
}
|
||||||
|
GoToMatch(matchId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,13 +1,15 @@
|
|||||||
export const SHARECODE_REGEX =
|
export const SHARECODE_REGEX =
|
||||||
/^CSGO(?:-?[ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789]{5}){5}$/;
|
/^CSGO(?:-?[ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789]{5}){5}$/g;
|
||||||
export const AUTHCODE_REGEX =
|
export const AUTHCODE_REGEX =
|
||||||
/^[ABCDEFGHJKLMNOPQRSTUVWXYZ23456789]{4}-[ABCDEFGHJKLMNOPQRSTUVWXYZ23456789]{5}-[ABCDEFGHJKLMNOPQRSTUVWXYZ23456789]{4}$/;
|
/^[ABCDEFGHJKLMNOPQRSTUVWXYZ23456789]{4}-[ABCDEFGHJKLMNOPQRSTUVWXYZ23456789]{5}-[ABCDEFGHJKLMNOPQRSTUVWXYZ23456789]{4}$/g;
|
||||||
|
|
||||||
export const ID64_PATTERN = /^\d{17}$/;
|
export const ID64_PATTERN = /^\d{17}$/g;
|
||||||
export const VANITY_PATTERN = /^[A-Za-z0-9-_]{3,32}$/;
|
export const VANITY_PATTERN = /^[A-Za-z0-9-_]{3,32}$/g;
|
||||||
|
|
||||||
export const CUSTOM_URL_PATTERN = "https://steamcommunity.com/id/";
|
export const CUSTOM_URL_BASE = "https://steamcommunity.com/id/";
|
||||||
export const PROFILE_URL_PATTERN = "https://steamcommunity.com/profiles/";
|
export const PROFILE_URL_BASE = "https://steamcommunity.com/profiles/";
|
||||||
|
export const MATCH_SHARE_URL_BASE =
|
||||||
|
"steam://rungame/730/76561202255233023/+csgo_download_match%20";
|
||||||
|
|
||||||
export const NAV_HEIGHT = 70;
|
export const NAV_HEIGHT = 70;
|
||||||
export const FOOTER_HEIGHT = 200;
|
export const FOOTER_HEIGHT = 200;
|
||||||
|
@@ -2,7 +2,8 @@ import { defineStore } from "pinia";
|
|||||||
|
|
||||||
export type RootState = {
|
export type RootState = {
|
||||||
id64: string;
|
id64: string;
|
||||||
vanity_url: string;
|
vanityUrl: string;
|
||||||
|
shareCode: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSearchParamsStore = defineStore({
|
export const useSearchParamsStore = defineStore({
|
||||||
@@ -10,7 +11,8 @@ export const useSearchParamsStore = defineStore({
|
|||||||
state: () =>
|
state: () =>
|
||||||
({
|
({
|
||||||
id64: "",
|
id64: "",
|
||||||
vanity_url: "",
|
vanityUrl: "",
|
||||||
|
shareCode: "",
|
||||||
} as RootState),
|
} as RootState),
|
||||||
actions: {},
|
actions: {},
|
||||||
getters: {},
|
getters: {},
|
||||||
|
@@ -443,3 +443,43 @@ export const LoadMoreMatchesExplore = async (
|
|||||||
|
|
||||||
return [response, info];
|
return [response, info];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// /match/parse/<shareCode>
|
||||||
|
export const ParseMatch = async (shareCode: string): Promise<infoState> => {
|
||||||
|
const info = reactive<infoState>({
|
||||||
|
statusCode: 0,
|
||||||
|
message: "",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
|
||||||
|
await axios
|
||||||
|
.get(`${API_URL}/match/parse/${shareCode}`)
|
||||||
|
.then((res) => {
|
||||||
|
switch (res.status) {
|
||||||
|
case STATUS.OK:
|
||||||
|
info.statusCode = STATUS.OK;
|
||||||
|
info.message = "";
|
||||||
|
break;
|
||||||
|
case STATUS.ACCEPTED:
|
||||||
|
info.statusCode = STATUS.ACCEPTED;
|
||||||
|
info.message = "Match will be parsed";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
switch (err.response.status) {
|
||||||
|
case STATUS.BAD_REQUEST:
|
||||||
|
info.message = "Bad request";
|
||||||
|
break;
|
||||||
|
case STATUS.SERVICE_UNAVAILABLE:
|
||||||
|
info.message = "Unable to parse match";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
info.message = "An unknown error occurred";
|
||||||
|
}
|
||||||
|
info.statusCode = err.response.status;
|
||||||
|
info.type = "error";
|
||||||
|
});
|
||||||
|
|
||||||
|
return info;
|
||||||
|
};
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
import { GoToError } from "@/utils/GoTo";
|
import { GoToError } from "@/utils/GoTo";
|
||||||
import type { MatchStats, Player } from "@/types";
|
import type { MatchStats, Player } from "@/types";
|
||||||
|
import { decodeMatchShareCode } from "csgo-sharecode";
|
||||||
|
|
||||||
enum ErrorPage {
|
enum ErrorPage {
|
||||||
INTERNAL_SERVER_ERROR = 500,
|
INTERNAL_SERVER_ERROR = 500,
|
||||||
BAD_GATEWAY = 502,
|
BAD_GATEWAY = 502,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const errorHandling = (code: number): void => {
|
export const errorHandling = (code: number): void => {
|
||||||
if (code === ErrorPage.INTERNAL_SERVER_ERROR) {
|
if (code === ErrorPage.INTERNAL_SERVER_ERROR) {
|
||||||
GoToError("500");
|
GoToError("500");
|
||||||
@@ -41,6 +43,7 @@ enum WLD {
|
|||||||
LOSS = "loss",
|
LOSS = "loss",
|
||||||
DRAW = "draw",
|
DRAW = "draw",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GetWinLoss = (matchResult: number, teamId: number): WLD => {
|
export const GetWinLoss = (matchResult: number, teamId: number): WLD => {
|
||||||
if (matchResult === teamId) {
|
if (matchResult === teamId) {
|
||||||
return WLD.WIN;
|
return WLD.WIN;
|
||||||
@@ -168,3 +171,20 @@ export const setAppDivBackground = (value: string, type: any): void => {
|
|||||||
const appDiv = document.getElementById("app") as typeof type;
|
const appDiv = document.getElementById("app") as typeof type;
|
||||||
appDiv.style.background = value;
|
appDiv.style.background = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const stringSanitizer = (input: string): string => {
|
||||||
|
return input
|
||||||
|
.replaceAll(/[^a-zA-Z0-9;=-\\\\/]/g, "")
|
||||||
|
.replaceAll(/\s{2,}/g, "")
|
||||||
|
.replaceAll(/\r/g, "")
|
||||||
|
.replaceAll(/\n/g, "");
|
||||||
|
};
|
||||||
|
|
||||||
|
export const parseShareCode = (shareCode: string): string => {
|
||||||
|
return decodeMatchShareCode(shareCode).matchId.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sleep = (delay: number) => {
|
||||||
|
const start = new Date().getTime();
|
||||||
|
while (new Date().getTime() < start + delay);
|
||||||
|
};
|
||||||
|
16
yarn.lock
16
yarn.lock
@@ -907,6 +907,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"csgo-sharecode@npm:^3.0.1":
|
||||||
|
version: 3.0.1
|
||||||
|
resolution: "csgo-sharecode@npm:3.0.1"
|
||||||
|
checksum: b0b7929e258f4e323641ffc527e6e4e34ad7ac722ea02a1a5b4414bc3e880891488b8f17e4ff9e105becc66899dc238d6c0935ea01ae4a1663310334867e1b42
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"csgowtf@workspace:.":
|
"csgowtf@workspace:.":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "csgowtf@workspace:."
|
resolution: "csgowtf@workspace:."
|
||||||
@@ -923,6 +930,7 @@ __metadata:
|
|||||||
axios: ^0.26.1
|
axios: ^0.26.1
|
||||||
bootstrap: ^5.1.3
|
bootstrap: ^5.1.3
|
||||||
bootstrap-icons: ^1.8.1
|
bootstrap-icons: ^1.8.1
|
||||||
|
csgo-sharecode: ^3.0.1
|
||||||
echarts: ^5.3.1
|
echarts: ^5.3.1
|
||||||
eslint: ^8.11.0
|
eslint: ^8.11.0
|
||||||
eslint-plugin-vue: ^8.5.0
|
eslint-plugin-vue: ^8.5.0
|
||||||
@@ -934,7 +942,6 @@ __metadata:
|
|||||||
pinia: ^2.0.12
|
pinia: ^2.0.12
|
||||||
prettier: ^2.6.0
|
prettier: ^2.6.0
|
||||||
sass: ^1.49.9
|
sass: ^1.49.9
|
||||||
string-sanitizer: ^2.0.2
|
|
||||||
typescript: ~4.6.2
|
typescript: ~4.6.2
|
||||||
vite: ^2.8.6
|
vite: ^2.8.6
|
||||||
vue: ^3.2.31
|
vue: ^3.2.31
|
||||||
@@ -2695,13 +2702,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"string-sanitizer@npm:^2.0.2":
|
|
||||||
version: 2.0.2
|
|
||||||
resolution: "string-sanitizer@npm:2.0.2"
|
|
||||||
checksum: 978be8325ee29c6ca97b97e86a578eea637db3da35fe6f1b260f917e984a8520c3f58bc4c83c0c2000da3cd5d6405117ef3e20af3feae5be44f90d7d1a12fe42
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.2.3":
|
"string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.2.3":
|
||||||
version: 4.2.3
|
version: 4.2.3
|
||||||
resolution: "string-width@npm:4.2.3"
|
resolution: "string-width@npm:4.2.3"
|
||||||
|
Reference in New Issue
Block a user