mirror of
https://github.com/arthur-pbty/binouz.git
synced 2026-06-03 15:07:17 +02:00
b7010a1704
- Implemented AuthButton component for Discord sign-in and sign-out functionality. - Created CopyButton component for copying server IP addresses. - Developed EventCard and GradeCard components for displaying events and grades. - Added Footer and Navbar components for site navigation and information. - Introduced PurchaseButton for handling grade purchases with Stripe integration. - Created SectionHeader component for consistent section titles. - Implemented session management with SessionProvider for NextAuth. - Set up PostgreSQL database with Docker and Prisma for data management. - Added admin guard functionality to restrict access to certain routes. - Configured NextAuth with Discord provider for user authentication. - Defined Prisma schema for user, admin, grade, event, and purchase models. - Seeded database with initial grades and events data. - Added SVG hero image for the landing page. - Extended NextAuth types to include additional user properties.
100 lines
2.8 KiB
TypeScript
100 lines
2.8 KiB
TypeScript
import type { NextAuthOptions } from "next-auth";
|
|
import DiscordProvider from "next-auth/providers/discord";
|
|
import { PrismaAdapter } from "@next-auth/prisma-adapter";
|
|
import { db } from "@/lib/db";
|
|
|
|
const adminDiscordId = process.env.ADMIN_DISCORD_ID;
|
|
const discordRedirectUrl = process.env.DISCORD_REDIRECT_URL;
|
|
|
|
const resolveAdmin = async (discordId?: string) => {
|
|
if (!discordId) return false;
|
|
if (adminDiscordId && discordId === adminDiscordId) return true;
|
|
const admin = await db.admin.findUnique({ where: { discordId } });
|
|
return Boolean(admin);
|
|
};
|
|
|
|
export const authOptions: NextAuthOptions = {
|
|
adapter: PrismaAdapter(db),
|
|
session: {
|
|
strategy: "jwt",
|
|
},
|
|
providers: [
|
|
DiscordProvider({
|
|
clientId: process.env.DISCORD_CLIENT_ID ?? "",
|
|
clientSecret: process.env.DISCORD_CLIENT_SECRET ?? "",
|
|
authorization: {
|
|
params: {
|
|
scope: "identify email",
|
|
...(discordRedirectUrl
|
|
? { redirect_uri: discordRedirectUrl }
|
|
: {}),
|
|
},
|
|
},
|
|
}),
|
|
],
|
|
callbacks: {
|
|
async jwt({ token, account, profile }) {
|
|
if (account && profile) {
|
|
const discordProfile = profile as {
|
|
id?: string;
|
|
username?: string;
|
|
avatar?: string;
|
|
};
|
|
token.discordId = discordProfile.id;
|
|
token.discordUsername = discordProfile.username;
|
|
token.discordAvatar = discordProfile.avatar;
|
|
}
|
|
|
|
token.isAdmin = await resolveAdmin(token.discordId as string | undefined);
|
|
|
|
return token;
|
|
},
|
|
async session({ session, token }) {
|
|
if (session.user) {
|
|
session.user.id = token.sub ?? "";
|
|
session.user.discordId = (token.discordId as string | undefined) ?? "";
|
|
session.user.discordUsername =
|
|
(token.discordUsername as string | undefined) ?? "";
|
|
session.user.discordAvatar =
|
|
(token.discordAvatar as string | undefined) ?? "";
|
|
session.user.isAdmin = token.isAdmin === true;
|
|
}
|
|
return session;
|
|
},
|
|
},
|
|
events: {
|
|
async signIn({ user, account, profile }) {
|
|
if (!account || account.provider !== "discord" || !profile) return;
|
|
|
|
const discordId = (profile as { id?: string }).id;
|
|
const discordUsername = (profile as { username?: string }).username;
|
|
const discordAvatar = (profile as { avatar?: string }).avatar;
|
|
|
|
if (!discordId) return;
|
|
|
|
await db.user.update({
|
|
where: { id: user.id },
|
|
data: {
|
|
discordId,
|
|
discordUsername,
|
|
discordAvatar,
|
|
},
|
|
});
|
|
|
|
if (adminDiscordId && discordId === adminDiscordId) {
|
|
await db.admin.upsert({
|
|
where: { discordId },
|
|
update: {},
|
|
create: {
|
|
discordId,
|
|
userId: user.id,
|
|
},
|
|
});
|
|
}
|
|
},
|
|
},
|
|
pages: {
|
|
signIn: "/auth/signin",
|
|
},
|
|
};
|