mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 13:50:43 +00:00
Discord login (#611)
## Description: ## Please complete the following: - [ ] I have added screenshots for all UI updates - [ ] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [ ] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: <DISCORD USERNAME> --------- Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const UserMeResponseSchema = z.object({
|
||||
user: z.object({
|
||||
id: z.string(),
|
||||
avatar: z.string(),
|
||||
username: z.string(),
|
||||
global_name: z.string(),
|
||||
discriminator: z.string(),
|
||||
locale: z.string(),
|
||||
}),
|
||||
});
|
||||
export type UserMeResponse = z.infer<typeof UserMeResponseSchema>;
|
||||
@@ -5,6 +5,7 @@ import { GameRecord, GameStartInfo } from "../core/Schemas";
|
||||
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
|
||||
import { GameType } from "../core/game/Game";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
import { UserMeResponse, UserMeResponseSchema } from "./ApiSchemas";
|
||||
import { joinLobby } from "./ClientGameRunner";
|
||||
import "./DarkModeButton";
|
||||
import { DarkModeButton } from "./DarkModeButton";
|
||||
@@ -58,6 +59,21 @@ class Client {
|
||||
constructor() {}
|
||||
|
||||
initialize(): void {
|
||||
const { hash } = window.location;
|
||||
if (hash.startsWith("#")) {
|
||||
const params = new URLSearchParams(hash.slice(1));
|
||||
const token = params.get("token");
|
||||
if (token) {
|
||||
localStorage.setItem("token", token);
|
||||
}
|
||||
// Clean the URL
|
||||
history.replaceState(
|
||||
null,
|
||||
"",
|
||||
window.location.pathname + window.location.search,
|
||||
);
|
||||
}
|
||||
|
||||
const langSelector = document.querySelector(
|
||||
"lang-selector",
|
||||
) as LangSelector;
|
||||
@@ -90,6 +106,22 @@ class Client {
|
||||
consolex.warn("Random name button element not found");
|
||||
}
|
||||
|
||||
const loginDiscordButton = document.getElementById("login-discord");
|
||||
isLoggedIn().then((loggedIn) => {
|
||||
if (loggedIn !== false) {
|
||||
console.log("Logged in", JSON.stringify(loggedIn, null, 2));
|
||||
const { user } = loggedIn;
|
||||
const { id, avatar, username, global_name, discriminator } = user;
|
||||
const avatarUrl = avatar
|
||||
? `https://cdn.discordapp.com/avatars/${id}/${avatar}.${avatar.startsWith("a_") ? "gif" : "png"}`
|
||||
: `https://cdn.discordapp.com/embed/avatars/${Number(discriminator) % 5}.png`;
|
||||
// TODO: Update the page for logged in user
|
||||
} else {
|
||||
localStorage.removeItem("token");
|
||||
loginDiscordButton.addEventListener("click", discordLogin);
|
||||
}
|
||||
});
|
||||
|
||||
this.usernameInput = document.querySelector(
|
||||
"username-input",
|
||||
) as UsernameInput;
|
||||
@@ -283,6 +315,32 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
new Client().initialize();
|
||||
});
|
||||
|
||||
async function isLoggedIn(): Promise<UserMeResponse | false> {
|
||||
try {
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) return false;
|
||||
const response = await fetch(getApiBase() + "/users/@me", {
|
||||
headers: {
|
||||
authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
if (response.status !== 200) return false;
|
||||
const body = await response.json();
|
||||
const result = UserMeResponseSchema.safeParse(body);
|
||||
if (!result.success) {
|
||||
console.error(
|
||||
"Invalid response",
|
||||
JSON.stringify(body),
|
||||
JSON.stringify(result.error),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return result.data;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function setFavicon(): void {
|
||||
const link = document.createElement("link");
|
||||
link.type = "image/x-icon";
|
||||
@@ -316,3 +374,15 @@ export function getPersistentIDFromCookie(): string {
|
||||
|
||||
return newID;
|
||||
}
|
||||
|
||||
function getApiBase() {
|
||||
const { hostname } = new URL(window.location.href);
|
||||
const domainname = hostname.split(".").slice(-2).join(".");
|
||||
return domainname === "localhost"
|
||||
? "http://localhost:8787"
|
||||
: `https://api.${domainname}`;
|
||||
}
|
||||
|
||||
function discordLogin() {
|
||||
window.location.href = `${getApiBase()}/login/discord?redirect_uri=${window.location.href}`;
|
||||
}
|
||||
|
||||
@@ -212,6 +212,13 @@
|
||||
<!-- Main container with responsive padding -->
|
||||
<main class="flex justify-center flex-grow">
|
||||
<div class="container pt-12">
|
||||
<o-button
|
||||
id="login-discord"
|
||||
title="Login"
|
||||
translationKey="main.login_discord"
|
||||
block
|
||||
></o-button>
|
||||
|
||||
<div class="container__row">
|
||||
<flag-input class="w-[20%] md:w-[15%]"></flag-input>
|
||||
<username-input class="w-full"></username-input>
|
||||
|
||||
Reference in New Issue
Block a user