mirror of
https://github.com/smogon/pokemon-showdown-loginserver.git
synced 2026-03-21 17:34:38 -05:00
Support copying teams into one's builder
Some checks are pending
Node.js CI / build (22.x) (push) Waiting to run
Some checks are pending
Node.js CI / build (22.x) (push) Waiting to run
This commit is contained in:
parent
ddcacf0f94
commit
bc0886b12f
|
|
@ -112,7 +112,7 @@ export function checkSuspectVerified(
|
|||
userData.coil = coilNum;
|
||||
break;
|
||||
case 'elo': case 'gxe':
|
||||
if (suspect[k] && rating[k] >= suspect[k]) {
|
||||
if (suspect[k] && rating[k] >= suspect[k]!) {
|
||||
reqsMet++;
|
||||
}
|
||||
userData[k] = rating[k];
|
||||
|
|
@ -139,6 +139,14 @@ export function checkSuspectVerified(
|
|||
return false;
|
||||
}
|
||||
|
||||
function exportTeam(team: string) {
|
||||
if (!Config.pspath) return team;
|
||||
const { Teams } = require(Config.pspath);
|
||||
const teamData = Teams.unpack(team);
|
||||
if (!teamData) return team;
|
||||
return Teams.export(teamData);
|
||||
}
|
||||
|
||||
export const actions: { [k: string]: QueryHandler } = {
|
||||
async register(params) {
|
||||
this.verifyCrossDomainRequest();
|
||||
|
|
@ -849,7 +857,7 @@ export const actions: { [k: string]: QueryHandler } = {
|
|||
return { loggedIn: this.user.id, teams };
|
||||
},
|
||||
async getteam(params) {
|
||||
let { teamid, password, full } = params;
|
||||
let { teamid, password, full, raw } = params;
|
||||
teamid = toID(teamid);
|
||||
password = toID(password);
|
||||
if (!teamid) {
|
||||
|
|
@ -873,6 +881,7 @@ export const actions: { [k: string]: QueryHandler } = {
|
|||
await tables.teams.query()`UPDATE teams SET views = views + 1 WHERE teamid = ${teamid}`;
|
||||
data.views += 1;
|
||||
}
|
||||
if (raw) data.team = exportTeam(data.team) || data.team;
|
||||
return data;
|
||||
} catch (e) {
|
||||
Server.crashlog(e, 'a teams database request', params);
|
||||
|
|
@ -900,13 +909,11 @@ export const actions: { [k: string]: QueryHandler } = {
|
|||
if (![1, 0].includes(priv)) {
|
||||
throw new ActionError(`Invalid privacy setting: ${params.private || "none"}`);
|
||||
}
|
||||
if (priv !== team.private) {
|
||||
if (team.private === 1) {
|
||||
edit.password = null;
|
||||
edit.private = 0;
|
||||
if (Boolean(priv) !== !!team.private) {
|
||||
if (priv === 1) {
|
||||
edit.private = Replays.generatePassword(20);
|
||||
} else {
|
||||
edit.password = Replays.generatePassword(20);
|
||||
edit.private = 1;
|
||||
edit.private = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -923,6 +930,35 @@ export const actions: { [k: string]: QueryHandler } = {
|
|||
}
|
||||
return { success: true, team: await tables.teams.get(team.teamid) };
|
||||
},
|
||||
async copyteam(params) {
|
||||
let { teamid, password } = params;
|
||||
if (!this.user.loggedIn) {
|
||||
throw new ActionError("Must be logged in to copy teams.");
|
||||
}
|
||||
teamid = toID(teamid);
|
||||
password = toID(password);
|
||||
if (!teamid) {
|
||||
throw new ActionError("Invalid team ID");
|
||||
}
|
||||
const data = await tables.teams.selectOne(
|
||||
SQL`team, private, ownerid, format, title`
|
||||
)`WHERE teamid = ${teamid}`;
|
||||
const owns = data?.ownerid === this.user.id;
|
||||
if (!data || (owns ? false : (data.private && (password !== toID(data.private))))) {
|
||||
throw new ActionError("Access denied");
|
||||
}
|
||||
const newPw = Replays.generatePassword(20);
|
||||
const result = await tables.teams.query()`INSERT INTO teams (${{
|
||||
team: data.team,
|
||||
private: newPw,
|
||||
format: data.format,
|
||||
title: `Copy of '${data.title}' by ${data.ownerid}`,
|
||||
views: 0,
|
||||
ownerid: this.user.id,
|
||||
date: new Date().toISOString(),
|
||||
}}) RETURNING *;`;
|
||||
return { teamid: `${result[0].teamid}-${newPw}` };
|
||||
},
|
||||
async searchteams(params) {
|
||||
let count = Number(params.count) || 20;
|
||||
if (!this.user.loggedIn || this.user.id === 'guest') {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
import { toID, time } from './utils';
|
||||
import { replayPlayers, replays } from './tables';
|
||||
import { SQL } from './database';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
// must be a type and not an interface to qualify as an SQLRow
|
||||
export type ReplayRow = {
|
||||
|
|
@ -132,7 +133,7 @@ export const Replays = new class {
|
|||
generatePassword(length = 31) {
|
||||
let password = '';
|
||||
for (let i = 0; i < length; i++) {
|
||||
password += this.passwordCharacters[Math.floor(Math.random() * this.passwordCharacters.length)];
|
||||
password += this.passwordCharacters[crypto.randomInt(0, this.passwordCharacters.length - 1)];
|
||||
}
|
||||
|
||||
return password;
|
||||
|
|
@ -157,32 +158,32 @@ export const Replays = new class {
|
|||
if (args.usernames.length > 1) {
|
||||
const userid2 = toID(args.usernames[1]);
|
||||
if (format) {
|
||||
return replays.query()`SELECT
|
||||
p1.uploadtime AS uploadtime, p1.id AS id, p1.format AS format, p1.players AS players,
|
||||
p1.rating AS rating, p1.password AS password, p1.private AS private
|
||||
FROM replayplayers p1 INNER JOIN replayplayers p2 ON p2.id = p1.id
|
||||
return replays.query()`SELECT
|
||||
p1.uploadtime AS uploadtime, p1.id AS id, p1.format AS format, p1.players AS players,
|
||||
p1.rating AS rating, p1.password AS password, p1.private AS private
|
||||
FROM replayplayers p1 INNER JOIN replayplayers p2 ON p2.id = p1.id
|
||||
WHERE p1.playerid = ${userid} AND p1.formatid = ${format} AND p1.private = ${isPrivate}
|
||||
AND p2.playerid = ${userid2}
|
||||
AND p2.playerid = ${userid2}
|
||||
${before} ${order} ${paginate};`.then(this.toReplays);
|
||||
} else {
|
||||
return replays.query()`SELECT
|
||||
p1.uploadtime AS uploadtime, p1.id AS id, p1.format AS format, p1.players AS players,
|
||||
p1.rating AS rating, p1.password AS password, p1.private AS private
|
||||
FROM replayplayers p1 INNER JOIN replayplayers p2 ON p2.id = p1.id
|
||||
return replays.query()`SELECT
|
||||
p1.uploadtime AS uploadtime, p1.id AS id, p1.format AS format, p1.players AS players,
|
||||
p1.rating AS rating, p1.password AS password, p1.private AS private
|
||||
FROM replayplayers p1 INNER JOIN replayplayers p2 ON p2.id = p1.id
|
||||
WHERE p1.playerid = ${userid} AND p1.private = ${isPrivate}
|
||||
AND p2.playerid = ${userid2}
|
||||
AND p2.playerid = ${userid2}
|
||||
${before} ${order} ${paginate};`.then(this.toReplays);
|
||||
}
|
||||
} else {
|
||||
if (format) {
|
||||
return replays.query()`SELECT
|
||||
uploadtime, id, format, players, rating, private, password FROM replayplayers
|
||||
WHERE playerid = ${userid} AND formatid = ${format} AND "private" = ${isPrivate}
|
||||
return replays.query()`SELECT
|
||||
uploadtime, id, format, players, rating, private, password FROM replayplayers
|
||||
WHERE playerid = ${userid} AND formatid = ${format} AND "private" = ${isPrivate}
|
||||
${before} ${order} ${paginate};`.then(this.toReplays);
|
||||
} else {
|
||||
return replays.query()`SELECT
|
||||
uploadtime, id, format, players, rating, private, password FROM replayplayers
|
||||
WHERE playerid = ${userid} AND private = ${isPrivate}
|
||||
return replays.query()`SELECT
|
||||
uploadtime, id, format, players, rating, private, password FROM replayplayers
|
||||
WHERE playerid = ${userid} AND private = ${isPrivate}
|
||||
${before} ${order} ${paginate};`.then(this.toReplays);
|
||||
}
|
||||
}
|
||||
|
|
@ -191,13 +192,13 @@ export const Replays = new class {
|
|||
if (!format) return this.recent(args);
|
||||
|
||||
if (args.byRating) {
|
||||
return replays.query()`SELECT uploadtime, id, format, players, rating, private, password
|
||||
FROM replays
|
||||
return replays.query()`SELECT uploadtime, id, format, players, rating, private, password
|
||||
FROM replays
|
||||
WHERE private = ${isPrivate} AND formatid = ${format} ${before} ORDER BY rating DESC ${paginate}`
|
||||
.then(this.toReplays);
|
||||
} else {
|
||||
return replays.query()`SELECT uploadtime, id, format, players, rating, private, password
|
||||
FROM replays
|
||||
return replays.query()`SELECT uploadtime, id, format, players, rating, private, password
|
||||
FROM replays
|
||||
WHERE private = ${isPrivate} AND formatid = ${format} ${before} ORDER BY uploadtime DESC ${paginate}`
|
||||
.then(this.toReplays);
|
||||
}
|
||||
|
|
@ -215,8 +216,8 @@ export const Replays = new class {
|
|||
const secondPattern = patterns.length >= 2 ? SQL`AND log LIKE ${patterns[1]} ` : SQL``;
|
||||
|
||||
const HOUR = 60 * 60;
|
||||
return replays.query()`SELECT
|
||||
uploadtime, id, format, players, rating FROM replays
|
||||
return replays.query()`SELECT
|
||||
uploadtime, id, format, players, rating FROM replays
|
||||
WHERE private = 0 AND uploadtime > ${time() - HOUR} AND log LIKE ${patterns[0]} ${secondPattern}
|
||||
ORDER BY uploadtime DESC LIMIT 50;`.then(this.toReplays);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ export const teams = pgdb.getTable<{
|
|||
team: string,
|
||||
format: string,
|
||||
title: string,
|
||||
private: number,
|
||||
private: string,
|
||||
views: number,
|
||||
}>('teams', 'teamid');
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user