Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions lib/Auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import ResendUtils from "./ResendUtils";
import CollectionId from "./client/CollectionId";
import { AdapterUser } from "next-auth/adapters";
import { wait } from "./client/ClientUtils";

const adapter = MongoDBAdapter(clientPromise, { databaseName: process.env.DB });
import MongoAuthAdapter from "./DbInterfaceAuthAdapter";

const cachedDb = getDatabase();
const adapter = MongoAuthAdapter(cachedDb);

export const AuthenticationOptions: AuthOptions = {
secret: process.env.NEXTAUTH_SECRET,
Expand Down Expand Up @@ -83,9 +83,7 @@ export const AuthenticationOptions: AuthOptions = {
],
callbacks: {
async session({ session, user }) {
session.user = await (
await cachedDb
).findObjectById(CollectionId.Users, new ObjectId(user.id));
session.user = user;

return session;
},
Expand Down
268 changes: 268 additions & 0 deletions lib/DbInterfaceAuthAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
import { format, MongoDBAdapter } from "@next-auth/mongodb-adapter";
import {
Adapter,
AdapterAccount,
AdapterSession,
AdapterUser,
VerificationToken,
} from "next-auth/adapters";
import DbInterface from "./client/dbinterfaces/DbInterface";
import CollectionId from "./client/CollectionId";
import { User, Session } from "./Types";
import { GenerateSlug } from "./Utils";
import { ObjectId } from "bson";

export default function DbInterfaceAuthAdapter(
dbPromise: Promise<DbInterface>,
): Adapter {
const adapter: Adapter = {
createUser: async (data: Record<string, unknown>) => {
const db = await dbPromise;

const adapterUser = format.to<AdapterUser>(data);

const user = new User(
adapterUser.name ?? "Unknown",
adapterUser.email,
adapterUser.image ?? process.env.DEFAULT_IMAGE,
false,
await GenerateSlug(
db,
CollectionId.Users,
adapterUser.name ?? "Unknown",
),
[],
[],
undefined,
0,
1,
);

user._id = new ObjectId(adapterUser._id) as any;

await db.addObject(CollectionId.Users, user);
return format.from<AdapterUser>(adapterUser);
},
getUser: async (id: string) => {
const db = await dbPromise;

if (id.length !== 24) return null;

const user = await db.findObjectById(
CollectionId.Users,
new ObjectId(id),
);

if (!user) return null;
return format.from<AdapterUser>(user);
},
getUserByEmail: async (email: string) => {
const db = await dbPromise;

const account = await db.findObject(CollectionId.Users, { email });

if (!account) return null;
return format.from<AdapterUser>(account);
},
getUserByAccount: async (
providerAccountId: Pick<AdapterAccount, "provider" | "providerAccountId">,
) => {
const db = await dbPromise;

const account = await db.findObject(CollectionId.Accounts, {
providerAccountId: providerAccountId.providerAccountId,
});

if (!account) return null;

const user = await db.findObjectById(
CollectionId.Users,
account.userId as any as ObjectId,
);

if (!user) return null;
return format.from<AdapterUser>(user);
},
updateUser: async (
data: Partial<AdapterUser> & Pick<AdapterUser, "id">,
) => {
const db = await dbPromise;
const { _id, ...user } = format.to<AdapterUser>(data);

const existing = await db.findObjectById(
CollectionId.Users,
new ObjectId(_id),
);

const result = await db.updateObjectById(
CollectionId.Users,
new ObjectId(_id),
user as Partial<User>,
);

return format.from<AdapterUser>({ ...existing, ...user, _id: _id });
},
deleteUser: async (id: string) => {
const db = await dbPromise;

const user = await db.findObjectById(
CollectionId.Users,
new ObjectId(id),
);
if (!user) return null;

const account = await db.findObject(CollectionId.Accounts, {
userId: user._id,
});

const session = await db.findObject(CollectionId.Sessions, {
userId: user._id,
});

const promises = [
db.deleteObjectById(CollectionId.Users, new ObjectId(id)),
];

if (account) {
promises.push(
db.deleteObjectById(CollectionId.Accounts, new ObjectId(account._id)),
);
}

if (session) {
promises.push(
db.deleteObjectById(CollectionId.Sessions, new ObjectId(session._id)),
);
}

await Promise.all(promises);

return format.from<AdapterUser>(user);
},
linkAccount: async (data: Record<string, unknown>) => {
const db = await dbPromise;
const account = format.to<AdapterAccount>(data);

await db.addObject(CollectionId.Accounts, account);

return account;
},
unlinkAccount: async (
providerAccountId: Pick<AdapterAccount, "provider" | "providerAccountId">,
) => {
const db = await dbPromise;

const account = await db.findObject(CollectionId.Accounts, {
providerAccountId: providerAccountId.providerAccountId,
});

if (!account) return null;

await db.deleteObjectById(
CollectionId.Accounts,
new ObjectId(account._id),
);

return format.from<AdapterAccount>(account);
},
getSessionAndUser: async (sessionToken: string) => {
const db = await dbPromise;

const session = await db.findObject(CollectionId.Sessions, {
sessionToken,
});

if (!session) return null;

const user = await db.findObjectById(
CollectionId.Users,
new ObjectId(session.userId),
);

if (!user) return null;
return {
session: format.from<AdapterSession>(session),
user: format.from<AdapterUser>(user),
};
},
createSession: async (data: Record<string, unknown>) => {
const db = await dbPromise;

const session = format.to<AdapterSession>(data);
session.userId = new ObjectId(session.userId) as any;

await db.addObject(CollectionId.Sessions, session as unknown as Session);

return format.from<AdapterSession>(session);
},
updateSession: async (
data: Partial<AdapterSession> & Pick<AdapterSession, "sessionToken">,
) => {
const db = await dbPromise;
const { _id, ...session } = format.to<AdapterSession>(data);

const existing = await db.findObject(CollectionId.Sessions, {
sessionToken: session.sessionToken,
});

if (!existing) return null;

if (session.userId) {
session.userId = new ObjectId(session.userId) as any;
}

await db.updateObjectById(
CollectionId.Sessions,
new ObjectId(existing._id),
session as unknown as Partial<Session>,
);

return format.from<AdapterSession>({ ...existing, ...data });
},
deleteSession: async (sessionToken: string) => {
const db = await dbPromise;

const session = await db.findObject(CollectionId.Sessions, {
sessionToken,
});

if (!session) return null;

await db.deleteObjectById(
CollectionId.Sessions,
new ObjectId(session._id),
);

return format.from<AdapterSession>(session);
},
createVerificationToken: async (token: VerificationToken) => {
const db = await dbPromise;
await db.addObject(
CollectionId.VerificationTokens,
format.to(token) as VerificationToken,
);
return token;
},
useVerificationToken: async (token: {
identifier: string;
token: string;
}) => {
const db = await dbPromise;

const existing = await db.findObject(CollectionId.VerificationTokens, {
token: token.token,
});

if (!existing) return null;

await db.deleteObjectById(
CollectionId.VerificationTokens,
new ObjectId(existing._id),
);

return format.from<VerificationToken>(existing);
},
};

return adapter;
}
3 changes: 3 additions & 0 deletions lib/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export interface Account extends NextAuthAccount {

export interface Session extends NextAuthSession {
_id: string;
sessionToken: string;
userId: ObjectId;
expires: string;
}

export class User implements NextAuthUser {
Expand Down
27 changes: 16 additions & 11 deletions lib/client/CollectionId.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { VerificationToken } from "next-auth/adapters";
import {
Season,
Competition,
Expand All @@ -12,6 +13,7 @@ import {
CompPicklistGroup,
WebhookHolder,
} from "../Types";
import { ObjectId } from "bson";

enum CollectionId {
Seasons = "Seasons",
Expand All @@ -22,6 +24,7 @@ enum CollectionId {
Users = "users",
Accounts = "accounts",
Sessions = "sessions",
VerificationTokens = "verification_tokens",
Forms = "Forms",
PitReports = "Pitreports",
Picklists = "Picklists",
Expand Down Expand Up @@ -51,14 +54,16 @@ export type CollectionIdToType<Id extends CollectionId> =
? Account
: Id extends CollectionId.Sessions
? Session
: Id extends CollectionId.PitReports
? Pitreport
: Id extends CollectionId.Picklists
? CompPicklistGroup
: Id extends CollectionId.SubjectiveReports
? SubjectiveReport
: Id extends CollectionId.Webhooks
? WebhookHolder
: Id extends CollectionId.Misc
? any
: any;
: Id extends CollectionId.VerificationTokens
? VerificationToken & { _id: ObjectId }
: Id extends CollectionId.PitReports
? Pitreport
: Id extends CollectionId.Picklists
? CompPicklistGroup
: Id extends CollectionId.SubjectiveReports
? SubjectiveReport
: Id extends CollectionId.Webhooks
? WebhookHolder
: Id extends CollectionId.Misc
? any
: any;
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sj3",
"version": "1.2.3",
"version": "1.2.4",
"private": true,
"repository": "https://github.com/Decatur-Robotics/Gearbox",
"license": "CC BY-NC-SA 4.0",
Expand Down
Loading