migrate unlink discord to pokerogue-api

This commit is contained in:
flx-sta 2024-10-04 10:41:44 -07:00
parent 70f78d1060
commit 8ac7ad4221
9 changed files with 143 additions and 78 deletions

View File

@ -1,4 +1,4 @@
VITE_BYPASS_LOGIN=0
VITE_BYPASS_LOGIN=0 # TODO: revert to `1`
VITE_BYPASS_TUTORIAL=0
VITE_SERVER_URL=http://localhost:8001
VITE_DISCORD_CLIENT_ID=1234567890

View File

@ -1,5 +1,5 @@
import { bypassLogin } from "./battle-scene";
import { pokerogueApi } from "./plugins/api/pokerogue-api";
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
import * as Utils from "./utils";
export interface UserInfo {

74
src/plugins/api/api.ts Normal file
View File

@ -0,0 +1,74 @@
import { SESSION_ID_COOKIE_NAME } from "#app/constants";
import { getCookie } from "#app/utils";
type DataType = "json" | "form-urlencoded";
export abstract class Api {
//#region Fields
protected readonly base: string;
//#region Public
constructor(base: string) {
this.base = base;
}
//#region Protected
/**
* Send a GET request.
* @param path The path to send the request to.
*/
protected async doGet(path: string) {
return this.doFetch(path, { method: "GET" });
}
/**
* Send a POST request.
* @param path THe path to send the request to.
* @param bodyData The body-data to send.
* @param dataType The data-type of the {@linkcode bodyData}.
*/
protected async doPost<D = undefined>(path: string, bodyData?: D, dataType: DataType = "json") {
let body: string | undefined = undefined;
const headers: HeadersInit = {};
if (bodyData) {
if (dataType === "json") {
body = typeof bodyData === "string" ? bodyData : JSON.stringify(bodyData);
headers["Content-Type"] = "application/json";
} else if (dataType === "form-urlencoded") {
if (bodyData instanceof Object) {
body = new URLSearchParams(Object.entries<any>(bodyData).map(([k, v]) => [k, v.toString()])).toString();
} else {
console.warn("Could not add body data to form-urlencoded!", bodyData);
}
headers["Content-Type"] = "application/x-www-form-urlencoded";
} else {
console.warn(`Unsupported data type: ${dataType}`);
body = String(bodyData);
headers["Content-Type"] = "text/plain";
}
}
return await this.doFetch(path, { method: "POST", body, headers });
}
/**
* A generic request helper.
* @param path The path to send the request to.
* @param config The request {@linkcode RequestInit | Configuration}.
*/
protected async doFetch(path: string, config: RequestInit): Promise<Response> {
config.headers = {
...config.headers,
Authorization: getCookie(SESSION_ID_COOKIE_NAME),
"Content-Type": config.headers?.["Content-Type"] ?? "application/json",
};
console.log(`Sending ${config.method ?? "GET"} request to: `, this.base + path, config);
return await fetch(this.base + path, config);
}
}

View File

@ -0,0 +1,4 @@
export interface LinkAccountToDiscordIdRequest {
username: string;
discordId: string;
}

View File

@ -0,0 +1,27 @@
import { Api } from "#app/plugins/api/api";
import type { LinkAccountToDiscordIdRequest } from "#app/plugins/api/models/LinkAccountToDiscordId";
export class PokerogueAdminApi extends Api {
/**
* Links an account to a discord id.
* @param linkData The {@linkcode LinkAccountToDiscordIdRequest} to send
* @returns `true` if successful, `false` if not
*/
public async linkAccountToDiscordId(linkData: LinkAccountToDiscordIdRequest) {
try {
const linkArr = Object.entries(linkData).map(([key, value]) => [key, String(value)]);
const params = new URLSearchParams(linkArr);
const response = await this.doPost("/admin/account/discord-link", params, "form-urlencoded");
if (response.ok) {
return true;
} else {
console.warn("Could not link account with discord!", response.status, response.statusText);
}
} catch (err) {
console.warn("Could not link account with discord!", err);
}
return false;
}
}

View File

@ -1,28 +1,29 @@
import type { PokerogueApiClearSessionData } from "#app/@types/pokerogue-api";
import { loggedInUser } from "#app/account";
import { MAX_INT_ATTR_VALUE, SESSION_ID_COOKIE_NAME } from "#app/constants";
import { Api } from "#app/plugins/api/api";
import type { AccountInfoResponse } from "#app/plugins/api/models/AccountInfo";
import type { AccountLoginRequest, AccountLoginResponse } from "#app/plugins/api/models/AccountLogin";
import type { TitleStatsResponse } from "#app/plugins/api/models/TitleStats";
import type { UpdateAllSavedataRequest } from "#app/plugins/api/models/UpdateAllSavedata";
import type { UpdateSessionSavedataRequest } from "#app/plugins/api/models/UpdateSessionSavedata";
import type { UpdateSystemSavedataRequest } from "#app/plugins/api/models/UpdateSystemSavedata";
import type { VerifySavedataResponse } from "#app/plugins/api/models/VerifySavedata";
import type { SessionSaveData } from "#app/system/game-data";
import type { RankingEntry, ScoreboardCategory } from "#app/ui/daily-run-scoreboard";
import { getCookie, removeCookie, setCookie } from "#app/utils";
import type { AccountInfoResponse } from "./models/AccountInfo";
import type { AccountLoginRequest, AccountLoginResponse } from "./models/AccountLogin";
import type { TitleStatsResponse } from "./models/TitleStats";
import type { UpdateAllSavedataRequest } from "./models/UpdateAllSavedata";
import type { UpdateSessionSavedataRequest } from "./models/UpdateSessionSavedata";
import type { UpdateSystemSavedataRequest } from "./models/UpdateSystemSavedata";
import type { VerifySavedataResponse } from "./models/VerifySavedata";
import { removeCookie, setCookie } from "#app/utils";
import { PokerogueAdminApi } from "#app/plugins/api/pokerogue-admin-api";
type DataType = "json" | "form-urlencoded";
export class PokerogueApi {
export class PokerogueApi extends Api {
//#region Fields
private readonly base: string;
public readonly admin: PokerogueAdminApi;
//#region Public
constructor(base: string) {
this.base = base;
super(base);
this.admin = new PokerogueAdminApi(base);
}
/**
@ -370,61 +371,26 @@ export class PokerogueApi {
}
}
//#region Private
/**
* Send a GET request.
* @param path The path to send the request to.
* Unlink the currently logged in user from Discord.
* @returns `true` if unlinking was successful, `false` if not
*/
private async doGet(path: string) {
return this.doFetch(path, { method: "GET" });
}
/**
* Send a POST request.
* @param path THe path to send the request to.
* @param bodyData The body-data to send.
* @param dataType The data-type of the {@linkcode bodyData}.
*/
private async doPost<D>(path: string, bodyData: D, dataType: DataType = "json") {
let body: string = "";
const headers: HeadersInit = {};
if (dataType === "json") {
body = typeof bodyData === "string" ? bodyData : JSON.stringify(bodyData);
headers["Content-Type"] = "application/json";
} else if (dataType === "form-urlencoded") {
if (bodyData instanceof Object) {
body = new URLSearchParams(Object.entries<any>(bodyData).map(([k, v]) => [k, v.toString()])).toString();
public async unlinkDiscord() {
try {
const response = await this.doPost("/unlink/discord");
if (response.ok) {
return true;
} else {
console.warn("Could not add body data to form-urlencoded!", bodyData);
console.warn(`Unlink failed (${response.status}: ${response.statusText})`);
}
headers["Content-Type"] = "application/x-www-form-urlencoded";
} else {
console.warn(`Unsupported data type: ${dataType}`);
body = String(bodyData);
headers["Content-Type"] = "text/plain";
} catch (err) {
console.warn("Could not unlink discord!", err);
}
return await this.doFetch(path, { method: "POST", body, headers });
return false;
}
/**
* A generic request helper.
* @param path The path to send the request to.
* @param config The request {@linkcode RequestInit | Configuration}.
*/
private async doFetch(path: string, config: RequestInit): Promise<Response> {
config.headers = {
...config.headers,
Authorization: getCookie(SESSION_ID_COOKIE_NAME),
"Content-Type": config.headers?.["Content-Type"] ?? "application/json",
};
console.log(`Sending ${config.method ?? "GET"} request to: `, this.base + path, config);
return await fetch(this.base + path, config);
}
//#region Private
private async isLocalMode(): Promise<boolean> {
return (

View File

@ -1,9 +1,9 @@
import BattleScene from "#app/battle-scene";
import { ModalConfig } from "./modal-ui-handler";
import { Mode } from "./ui";
import * as Utils from "../utils";
import { FormModalUiHandler } from "./form-modal-ui-handler";
import { Button } from "#app/enums/buttons";
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
export default class AdminUiHandler extends FormModalUiHandler {
@ -61,17 +61,14 @@ export default class AdminUiHandler extends FormModalUiHandler {
if (!this.inputs[1].text) {
return onFail("Discord Id is required");
}
Utils.apiPost("admin/account/discord-link", `username=${encodeURIComponent(this.inputs[0].text)}&discordId=${encodeURIComponent(this.inputs[1].text)}`, "application/x-www-form-urlencoded", true)
.then(response => {
if (!response.ok) {
console.error(response);
const [ usernameInput, discordIdInput ] = this.inputs;
pokerogueApi.admin.linkAccountToDiscordId({ username: usernameInput.text, discordId: discordIdInput.text })
.then(isSuccess => {
if (isSuccess) {
usernameInput.setText("");
discordIdInput.setText("");
}
this.inputs[0].setText("");
this.inputs[1].setText("");
this.scene.ui.revertMode();
})
.catch((err) => {
console.error(err);
this.scene.ui.revertMode();
});
return false;

View File

@ -514,10 +514,7 @@ export default class MenuUiHandler extends MessageUiHandler {
window.open(discordUrl, "_self");
return true;
} else {
Utils.apiPost("/auth/discord/logout", undefined, undefined, true).then(res => {
if (!res.ok) {
console.error(`Unlink failed (${res.status}: ${res.statusText})`);
}
pokerogueApi.unlinkDiscord().then(_isSuccess => {
updateUserInfo().then(() => this.scene.reset(true, true));
});
return true;

View File

@ -1,7 +1,7 @@
import { MoneyFormat } from "#enums/money-format";
import { Moves } from "#enums/moves";
import i18next from "i18next";
import { pokerogueApi } from "./plugins/api/pokerogue-api";
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
export type nil = null | undefined;