diff --git a/apps/website/auth.config.ts b/apps/website/auth.config.ts index 8223e6f..dab32e6 100644 --- a/apps/website/auth.config.ts +++ b/apps/website/auth.config.ts @@ -1,5 +1,6 @@ import Discord from "@auth/core/providers/discord"; import { defineConfig } from "auth-astro"; +import type { User } from "~/env"; export default defineConfig({ providers: [ @@ -15,6 +16,9 @@ export default defineConfig({ if (account && profile) { token.accessToken = account.access_token; token.id = profile.id; + + token.name = profile.username as string; + token.global_name = profile.global_name; } return token; @@ -22,15 +26,20 @@ export default defineConfig({ async session({ session, token }) { if (session.user) { session.user.id = token.id as string; + (session.user as unknown as User).global_name = + token.global_name as string; - const guilds = await fetch("https://discord.com/api/users/@me/guilds", { - headers: { - Authorization: `Bearer ${token.accessToken as string}`, - "Cache-Control": "max-age=300", - }, - }); + const guilds = await fetch( + "https://discord.com/api/v10/users/@me/guilds", + { + headers: { + Authorization: `Bearer ${token.accessToken as string}`, + "Cache-Control": "max-age=300", + }, + } + ); - session.user.guilds = await guilds.json(); + (session.user as unknown as User).guilds = await guilds.json(); } return session; diff --git a/apps/website/src/env.d.ts b/apps/website/src/env.d.ts index 320a19a..47ddad0 100644 --- a/apps/website/src/env.d.ts +++ b/apps/website/src/env.d.ts @@ -3,9 +3,14 @@ import type { User as AuthCoreUser } from "@auth/core/types"; export type User = AuthCoreUser & { - guilds: { - id: string; - name: string; - icon: string; - }[]; + global_name: string; + guilds: Guild[]; }; + +export interface Guild { + id: string; + name: string; + icon: string; + permissions: string; + owner: boolean; +} diff --git a/apps/website/src/lib/guilds.ts b/apps/website/src/lib/guilds.ts new file mode 100644 index 0000000..6f4220a --- /dev/null +++ b/apps/website/src/lib/guilds.ts @@ -0,0 +1,43 @@ +import type { Guild } from "~/env"; + +// Checks if user has AMDINISTRATOR permissions in the guild +export async function filterUserGuilds(guilds: Guild[]): Promise< + { + mutual: boolean; + guild: Guild; + }[] +> { + const filtered = guilds + .filter((g) => (BigInt(g.permissions) & 0x8n) == 0x8n) + .sort((a, b) => Number(b.owner) - Number(a.owner)); + + const result: { + mutual: boolean; + guild: Guild; + }[] = []; + + for (const guild of filtered) { + const mutual = await isMutualGuild(guild); + + result.push({ mutual, guild }); + } + + result.sort((a, b) => Number(b.mutual) - Number(a.mutual)); + + return result; +} + +export async function isMutualGuild(guild: Guild): Promise { + const res = await fetch( + `https://discord.com/api/v10/guilds/${guild.id}/members/${ + import.meta.env.DISCORD_CLIENT_ID + }`, + { + headers: { + Authorization: `Bot ${import.meta.env.DISCORD_BOT_TOKEN}`, + }, + } + ); + + return res.ok; +} diff --git a/apps/website/src/pages/api/user/guilds.ts b/apps/website/src/pages/api/user/guilds.ts new file mode 100644 index 0000000..9f28f00 --- /dev/null +++ b/apps/website/src/pages/api/user/guilds.ts @@ -0,0 +1,23 @@ +import type { APIRoute } from "astro"; +import { getSession } from "auth-astro/server"; +import type { User } from "~/env"; + +export const GET: APIRoute = async ({ request }) => { + const session = await getSession(request); + if (!session || !session.user) { + return new Response(null, { + status: 401, + }); + } + + const user = session.user as User; + + return Response.json( + user.guilds.map((g) => ({ + id: g.id, + name: g.name, + owner: g.owner, + permissions: g.permissions, + })) + ); +}; diff --git a/apps/website/src/pages/api/user/index.ts b/apps/website/src/pages/api/user/index.ts new file mode 100644 index 0000000..6736781 --- /dev/null +++ b/apps/website/src/pages/api/user/index.ts @@ -0,0 +1,21 @@ +import type { APIRoute } from "astro"; +import { getSession } from "auth-astro/server"; +import type { User } from "~/env"; + +export const GET: APIRoute = async ({ request }) => { + const session = await getSession(request); + if (!session || !session.user) { + return new Response(null, { + status: 401, + }); + } + + const user = session.user as User; + + return Response.json({ + id: user.id, + username: user.name, + global_name: user.global_name, + avatar_url: user.image, + }); +}; diff --git a/apps/website/src/pages/dashboard/index.astro b/apps/website/src/pages/dashboard/index.astro index 252269a..dca9c9f 100644 --- a/apps/website/src/pages/dashboard/index.astro +++ b/apps/website/src/pages/dashboard/index.astro @@ -1,5 +1,6 @@ --- import type { User } from "~/env"; +import { filterUserGuilds } from "~/lib/guilds"; import { getSession } from "auth-astro/server"; import Layout from "~/layouts/Layout.astro"; import Container from "~/components/Container.astro"; @@ -11,6 +12,7 @@ if (!session || !session.user) { } const user = session.user as User; +const guilds = await filterUserGuilds(user.guilds); --- @@ -33,8 +35,12 @@ const user = session.user as User; class="flex flex-wrap items-center justify-center gap-12 pb-4 text-white" > { - user.guilds.map((guild) => ( -
+ guilds.map(({ guild, mutual }) => ( +