Skip to content

Commit

Permalink
fix: Discord avatars
Browse files Browse the repository at this point in the history
  • Loading branch information
simonknittel committed Jan 31, 2025
1 parent 9aff300 commit 6bb2f70
Show file tree
Hide file tree
Showing 13 changed files with 144 additions and 61 deletions.
57 changes: 5 additions & 52 deletions app/src/auth/server/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type { PermissionSet } from "@/auth/common";
import { getPermissionSetsByRoles } from "@/auth/server";
import { requestEmailConfirmation } from "@/auth/utils/emailConfirmation";
import { prisma } from "@/db";
import { getDiscordAvatar } from "@/discord/utils/getDiscordAvatar";
import { getGuildMember } from "@/discord/utils/getGuildMember";
import { env } from "@/env";
import { log } from "@/logging";
import { getUserById } from "@/users/queries";
Expand All @@ -12,59 +14,10 @@ import {
type NextAuthOptions,
type User,
} from "next-auth";
import DiscordProvider, {
type DiscordProfile,
} from "next-auth/providers/discord";
import DiscordProvider from "next-auth/providers/discord";
import { serializeError } from "serialize-error";
import { z } from "zod";
import { type UserRole } from "../../types";

const guildMemberResponseSchema = z.union([
z.object({
avatar: z.string().nullable(),
}),

z.object({
message: z.string(),
}),
]);

async function getGuildMember(access_token: string) {
const headers = new Headers();
headers.set("Authorization", `Bearer ${access_token}`);

const response = await fetch(
`https://discord.com/api/v10/users/@me/guilds/${env.DISCORD_GUILD_ID}/member`,
{
headers,
next: {
revalidate: 0,
},
},
);

const body: unknown = await response.json();
const data = guildMemberResponseSchema.parse(body);

return data;
}

function getAvatar(
profile: DiscordProfile,
guildMember: z.infer<typeof guildMemberResponseSchema>,
) {
if ("avatar" in guildMember && guildMember.avatar) {
const format = guildMember.avatar.startsWith("a_") ? "gif" : "png";
return `https://cdn.discordapp.com/avatars/${profile.id}/${guildMember.avatar}.${format}`;
} else if (profile.avatar) {
const format = profile.avatar.startsWith("a_") ? "gif" : "png";
return `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.${format}`;
}

const defaultAvatarNumber = parseInt(profile.discriminator) % 5;
return `https://cdn.discordapp.com/embed/avatars/${defaultAvatarNumber}.png`;
}

/**
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
* object and keep type safety.
Expand Down Expand Up @@ -204,7 +157,7 @@ export const authOptions: NextAuthOptions = {
throw new Error(guildMember.message);
}

const avatar = getAvatar(profile, guildMember);
const avatar = getDiscordAvatar(profile, guildMember);

await prisma.$transaction([
prisma.account.update({
Expand Down Expand Up @@ -247,7 +200,7 @@ export const authOptions: NextAuthOptions = {

user.email = profile.email!.toLocaleLowerCase();

const avatar = getAvatar(profile, guildMember);
const avatar = getDiscordAvatar(profile, guildMember);
user.image = avatar;

user.name = null;
Expand Down
12 changes: 7 additions & 5 deletions app/src/common/components/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ interface Props {
}

const Avatar = ({ className, name, image, size }: Readonly<Props>) => {
const imageSize = size || 64;

return (
<span
className={clsx(
Expand All @@ -40,16 +42,16 @@ const Avatar = ({ className, name, image, size }: Readonly<Props>) => {
: name
? stringToColor(name)
: "#dedfe0",
width: size || 64,
height: size || 64,
width: imageSize,
height: imageSize,
}}
>
{image ? (
<Image
src={image}
src={`${image}?size=${imageSize}`}
alt={name ? `Image of ${name}` : ""}
width={size || 64}
height={size || 64}
width={imageSize}
height={imageSize}
/>
) : name ? (
name.replace(/\s/g, "").substring(0, 2)
Expand Down
23 changes: 23 additions & 0 deletions app/src/discord/utils/getDiscordAvatar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { env } from "@/env";
import type { DiscordProfile } from "next-auth/providers/discord";
import { type z } from "zod";
import type { guildMemberResponseSchema } from "./schemas";

export const getDiscordAvatar = (
profile: DiscordProfile,
guildMember: z.infer<typeof guildMemberResponseSchema>,
) => {
if ("avatar" in guildMember && guildMember.avatar) {
const format = getFormat(guildMember.avatar);
return `https://cdn.discordapp.com/guilds/${env.DISCORD_GUILD_ID}/users/${profile.id}/avatars/${guildMember.avatar}.${format}`;
} else if (profile.avatar) {
const format = getFormat(profile.avatar);
return `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.${format}`;
}

const defaultAvatarNumber = parseInt(profile.discriminator) % 5;
return `https://cdn.discordapp.com/embed/avatars/${defaultAvatarNumber}.png`;
};

const getFormat = (avatar: string) =>
avatar.startsWith("a_") ? "gif" : "webp";
22 changes: 22 additions & 0 deletions app/src/discord/utils/getGuildMember.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { env } from "@/env";
import { guildMemberResponseSchema } from "./schemas";

export const getGuildMember = async (access_token: string) => {
const headers = new Headers();
headers.set("Authorization", `Bearer ${access_token}`);

const response = await fetch(
`https://discord.com/api/v10/users/@me/guilds/${env.DISCORD_GUILD_ID}/member`,
{
headers,
next: {
revalidate: 0,
},
},
);

const body: unknown = await response.json();
const data = guildMemberResponseSchema.parse(body);

return data;
};
10 changes: 10 additions & 0 deletions app/src/discord/utils/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,13 @@ export const memberSchema = z.object({
nick: z.string().optional().nullable(),
avatar: z.string().optional().nullable(),
});

export const guildMemberResponseSchema = z.union([
z.object({
avatar: z.string().nullable(),
}),

z.object({
message: z.string(),
}),
]);
3 changes: 2 additions & 1 deletion app/src/events/components/ParticipantsTab.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { requireAuthentication } from "@/auth/server";
import { RolesCell } from "@/citizen/components/RolesCell";
import { Link } from "@/common/components/Link";
import { getDiscordAvatar } from "@/discord/utils/getDiscordAvatar";
import { type getEvent } from "@/discord/utils/getEvent";
import type { memberSchema, userSchema } from "@/discord/utils/schemas";
import type { Entity } from "@prisma/client";
Expand Down Expand Up @@ -183,7 +184,7 @@ const DiscordUser = ({
>
<div className="rounded overflow-hidden">
<Image
src={`https://cdn.discordapp.com/avatars/${discord.user.id}/${discord.member?.avatar || discord.user.avatar}.png`}
src={`${getDiscordAvatar(discord.user, discord.member)}?size=32`}
alt=""
width={32}
height={32}
Expand Down
15 changes: 15 additions & 0 deletions bruno-collection/Discord/@me Guild member.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
meta {
name: @me Guild member
type: http
seq: 4
}

get {
url: https://discord.com/api/v10/users/@me/guilds/{{DISCORD_GUILD_ID}}/member
body: none
auth: none
}

headers {
Authorization: Bearer {{DISCORD_ACCESS_TOKEN}}
}
15 changes: 15 additions & 0 deletions bruno-collection/Discord/Guild member (index).bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
meta {
name: Guild member (index)
type: http
seq: 5
}

get {
url: https://discord.com/api/v10/guilds/{{DISCORD_GUILD_ID}}/members/117890449187930113
body: none
auth: none
}

headers {
Authorization: Bot {{DISCORD_TOKEN}}
}
15 changes: 15 additions & 0 deletions bruno-collection/Discord/Guild member (savior0815).bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
meta {
name: Guild member (savior0815)
type: http
seq: 7
}

get {
url: https://discord.com/api/v10/guilds/{{DISCORD_GUILD_ID}}/members/318138407794507776
body: none
auth: none
}

headers {
Authorization: Bot {{DISCORD_TOKEN}}
}
15 changes: 15 additions & 0 deletions bruno-collection/Discord/Guild member (xionlunix).bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
meta {
name: Guild member (xionlunix)
type: http
seq: 6
}

get {
url: https://discord.com/api/v10/guilds/{{DISCORD_GUILD_ID}}/members/158574115719086080
body: none
auth: none
}

headers {
Authorization: Bot {{DISCORD_TOKEN}}
}
2 changes: 1 addition & 1 deletion bruno-collection/Pusher/Publish notification.bru
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ meta {
}

post {
url: https:/{{PUSHER_ENDPOINT}}/publishes
url: https:/{{PUSHER_HOST}}/publishes
body: json
auth: none
}
Expand Down
11 changes: 11 additions & 0 deletions bruno-collection/environments/prod.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
vars {
emailFunctionEndpoint: https://sinister-api-test.simonknittel.de/email-function
appBaseUrl: https://sam.sinister-incorporated.de
DISCORD_GUILD_ID: 91935440050851840
}
vars:secret [
DISCORD_TOKEN,
PUSHER_HOST,
PUSHER_KEY,
DISCORD_ACCESS_TOKEN
]
5 changes: 3 additions & 2 deletions bruno-collection/environments/test.bru
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ vars {
}
vars:secret [
DISCORD_TOKEN,
PUSHER_ENDPOINT,
PUSHER_KEY
PUSHER_HOST,
PUSHER_KEY,
DISCORD_ACCESS_TOKEN
]

0 comments on commit 6bb2f70

Please sign in to comment.