migration

This commit is contained in:
Théo LAGACHE
2025-05-16 15:54:17 +02:00
parent 01019fe1a3
commit 6f2523e524
285 changed files with 15492 additions and 46090 deletions
+30
View File
@@ -0,0 +1,30 @@
import { createAuthClient } from "better-auth/react";
import { adminClient, organizationClient } from "better-auth/client/plugins";
import { env } from "@/env.mjs";
import { ac, user, admin as adminRole, pending, superadmin, orgAdmin, orgMember, orgOwner } from "./permissions";
export const authClient = createAuthClient({
baseURL: env.NEXT_PUBLIC_PROJECT_URL,
plugins: [
organizationClient({
ac,
roles: {
orgOwner,
orgAdmin,
orgMember,
},
}),
adminClient({
ac,
roles: {
adminRole,
user,
pending,
superadmin,
},
}),
],
});
export const { signIn, signOut, signUp, useSession, listAccounts, admin } = authClient;
+299
View File
@@ -0,0 +1,299 @@
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db";
import { env } from "@/env.mjs";
import { nextCookies } from "better-auth/next-js";
import { admin as adminPlugin, openAPI, organization } from "better-auth/plugins";
import { ac, admin, user, pending, superadmin, orgOwner, orgAdmin, orgMember } from "@/lib/auth/permissions";
import { headers } from "next/headers";
import { count, eq } from "drizzle-orm";
import * as drizzleUser from "@/db/schema/01_user";
import * as drizzleOrganization from "@/db/schema/02_organization";
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
schema: {
...drizzleUser,
...drizzleOrganization,
},
}),
emailAndPassword: {
enabled: true,
requireEmailVerification: false,
/*async sendResetPassword(data, request) {
// Send an email to the user with a link to reset their password
},
async sendVerificationEmail(data, request) {
// Send an email to the user with a link to verify their email
},
async verifyEmail(data, request) {
// Verify the email address
},*/
},
socialProviders: {
google: {
clientId: env.AUTH_GOOGLE_ID!,
clientSecret: env.AUTH_GOOGLE_SECRET!,
},
},
plugins: [
openAPI(),
nextCookies(),
organization({
ac,
roles: {
orgOwner,
orgAdmin,
orgMember,
},
}),
adminPlugin({
adminRoles: ["admin", "superadmin"],
defaultRole: (await db.select({ count: count() }).from(drizzleUser["user"]))[0].count === 0 ? "superadmin" : "pending",
ac,
roles: {
admin,
user,
pending,
superadmin,
},
}),
],
advanced: {
database: {
generateId: false,
},
},
user: {
additionalFields: {
deletedAt: {
type: "number", //pg timestamp
nullable: true,
required: false,
},
},
},
session: {
additionalFields: {
activeOrganizationId: {
type: "string",
required: false,
},
},
},
/* databaseHooks: {
session: {
create: {
before: async (session) => {
const organizationId = await getLastOrganizationOrFirst(session.userId);
if (!organizationId) {
return {
...session,
};
}
console.log("sessionId", session.id);
const [aa] = await db
.update(drizzleUser.session)
.set({ activeOrganizationId: organizationId })
.where(eq(drizzleUser.session.id, session.id))
.returning();
console.log("aaaaa", aa);
return {
...session,
activeOrganizationId: organizationId,
};
},
},
},
},*/
trustedOrigins: [env.NEXT_PUBLIC_PROJECT_URL, "http://app"],
});
/*export const signUpUser = async (email: string, password: string, name: string) => {
const user = await auth.api.signUpEmail({
body: {
email,
password,
name,
},
});
return user;
};
export const signInUser = async (email: string, password: string) => {
const user = await auth.api.signInEmail({
body: {
email,
password,
},
});
return user;
};*/
export const createUser = async (name: string, email: string, password: string, role: "user" | "pending" | "admin" | "superadmin" = "pending") => {
const user = await auth.api.createUser({
headers: await headers(),
body: {
name,
email,
password,
role,
},
});
return user;
};
export const getSessions = async () => {
const sessions = await auth.api.listSessions({
headers: await headers(),
});
return sessions;
};
export const getSession = async () => {
const session = await auth.api.getSession({
headers: await headers(),
});
return session;
};
export const revokeSession = async (e: string) => {
try {
const { status } = await auth.api.revokeSession({
body: {
token: e,
},
headers: await headers(),
});
return status;
} catch (e) {}
};
export const getAccounts = async () => {
const sessions = await auth.api.listUserAccounts({
headers: await headers(),
});
return sessions;
};
export const unlinkAccount = async (provider: string, account: string) => {
try {
const { status } = await auth.api.unlinkAccount({
body: {
providerId: provider,
accountId: account,
},
headers: await headers(),
});
return status;
} catch (e) {}
};
export const getOrganization = async (organizationSlug?: string) => {
try {
const organization = await auth.api.getFullOrganization({
headers: await headers(),
query: {
organizationSlug,
},
});
return organization;
} catch (e) {}
};
export const listOrganizations = async () => {
try {
const organizations = await auth.api.listOrganizations({
headers: await headers(),
});
return organizations;
} catch (e) {}
};
export const getLastOrganizationOrFirst = async (userId: string) => {
try {
const organizations = await db.query.organizationMember.findMany({
where: eq(drizzleOrganization.member.userId, userId),
});
if (organizations.length > 0) {
return organizations[0].id;
}
return null;
} catch (e) {
return null;
}
};
export const createOrganization = async (name: string, slug: string) => {
try {
const organization = await auth.api.createOrganization({
headers: await headers(),
body: {
name,
slug,
},
});
return organization;
} catch (e) {
console.log("err", e);
}
};
export const checkSlugOrganization = async (slug: string) => {
try {
const { status } = await auth.api.checkOrganizationSlug({
headers: await headers(),
body: {
slug,
},
});
return status;
} catch (e) {
console.log("err", e);
}
};
export const getActiveMember = async () => {
try {
const member = await auth.api.getActiveMember({
headers: await headers(),
});
return member;
} catch (e) {
console.log("err", e);
}
};
export const setActiveOrganization = async (slug: string) => {
try {
const organization = await auth.api.setActiveOrganization({
headers: await headers(),
body: {
organizationSlug: slug,
},
});
return organization;
} catch (e) {
console.log("error", e);
}
};
+15
View File
@@ -0,0 +1,15 @@
"use server";
import { auth } from "@/lib/auth/auth";
import { headers } from "next/headers";
export const currentUser = async () => {
const session = await auth.api.getSession({
headers: await headers(),
});
if (!session?.user) {
return null;
}
return session.user;
};
+59
View File
@@ -0,0 +1,59 @@
import { createAccessControl } from "better-auth/plugins/access";
import { defaultStatements, adminAc } from "better-auth/plugins/admin/access";
import { defaultStatements as orgDefaultStatements, adminAc as orgAdminAc } from "better-auth/plugins/organization/access";
const statement = {
...defaultStatements,
...orgDefaultStatements,
project: ["create", "list", "update", "delete"],
database: ["create", "list", "update", "delete", "backup"],
agent: ["create", "list", "update", "delete"],
} as const;
const ac = createAccessControl(statement);
const superadmin = ac.newRole({
project: ["create", "list", "update", "delete"],
database: ["create", "list", "update", "delete"],
agent: ["create", "list", "update", "delete"],
...adminAc.statements,
...orgAdminAc.statements,
});
const admin = ac.newRole({
project: ["create", "list", "update", "delete"],
database: ["create", "list", "update", "delete"],
agent: ["create", "list", "update", "delete"],
...adminAc.statements,
});
const user = ac.newRole({
project: [],
database: [],
agent: [],
});
const pending = ac.newRole({
project: [],
database: [],
agent: [],
});
//org
const orgMember = ac.newRole({
project: ["list"],
database: ["list"],
agent: ["list"],
});
const orgAdmin = ac.newRole({
project: ["create", "update"],
...orgAdminAc.statements,
});
const orgOwner = ac.newRole({
project: ["create", "update", "delete"],
...orgAdminAc.statements,
});
export { ac, admin, superadmin, user, pending, orgAdmin, orgMember, orgOwner };