141 lines
3.8 KiB
TypeScript
141 lines
3.8 KiB
TypeScript
import { prisma } from '@/db';
|
|
import { User } from '@/generated/prisma/client';
|
|
import { SessionModel } from '@/generated/prisma/models';
|
|
import {
|
|
acOrg,
|
|
adminOrg,
|
|
member,
|
|
owner,
|
|
} from '@/lib/auth/organization-permissions';
|
|
import { ac, admin, user } from '@/lib/auth/permissions';
|
|
import { createAuditLog } from '@/service/audit.api';
|
|
import { betterAuth } from 'better-auth';
|
|
import { prismaAdapter } from 'better-auth/adapters/prisma';
|
|
import { admin as adminPlugin, organization } from 'better-auth/plugins';
|
|
|
|
export interface Session {
|
|
session: SessionModel | null | undefined;
|
|
user?: User;
|
|
}
|
|
|
|
export const auth = betterAuth({
|
|
database: prismaAdapter(prisma, {
|
|
provider: 'postgresql',
|
|
}),
|
|
experimental: { joins: true },
|
|
emailAndPassword: {
|
|
enabled: true,
|
|
requireEmailVerification: false,
|
|
},
|
|
trustedOrigins: ['http://localhost:3001'],
|
|
advanced: {
|
|
database: {
|
|
generateId: false,
|
|
},
|
|
},
|
|
plugins: [
|
|
adminPlugin({
|
|
ac,
|
|
roles: { admin, user },
|
|
defaultRole: 'user',
|
|
}),
|
|
organization({
|
|
ac: acOrg,
|
|
roles: { owner, admin: adminOrg, member },
|
|
schema: {
|
|
organization: {
|
|
additionalFields: {
|
|
color: {
|
|
type: 'string',
|
|
defaultValue: '#000000',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
],
|
|
databaseHooks: {
|
|
user: {
|
|
create: {
|
|
after: async (user) => {
|
|
await auth.api.createOrganization({
|
|
body: {
|
|
name: `${user.name || 'User'}'s Organization`,
|
|
slug: `${user.name?.toLowerCase().replace(/\s+/g, '-')}-${Date.now()}`,
|
|
userId: user.id,
|
|
color: '#000000',
|
|
},
|
|
});
|
|
},
|
|
},
|
|
update: {
|
|
before: async (user, ctx) => {
|
|
if (ctx?.context.session && ctx?.path === '/update-user') {
|
|
const newUser = JSON.parse(JSON.stringify(user));
|
|
const keys = Object.keys(newUser);
|
|
const oldUser = Object.fromEntries(
|
|
Object.entries(ctx?.context.session?.user).filter(([key]) =>
|
|
keys.includes(key),
|
|
),
|
|
);
|
|
await createAuditLog({
|
|
action: 'update',
|
|
tableName: 'user',
|
|
recordId: ctx?.context.session?.user.id,
|
|
oldValue: JSON.stringify(oldUser),
|
|
newValue: JSON.stringify(newUser),
|
|
userId: ctx?.context.session?.user.id,
|
|
});
|
|
}
|
|
},
|
|
},
|
|
},
|
|
account: {
|
|
update: {
|
|
after: async (account, context) => {
|
|
if (context?.path === '/change-password') {
|
|
await createAuditLog({
|
|
action: 'change_password',
|
|
tableName: 'account',
|
|
recordId: account.id,
|
|
oldValue: 'Change Password',
|
|
newValue: 'Change Password',
|
|
userId: account.userId,
|
|
});
|
|
}
|
|
},
|
|
},
|
|
},
|
|
session: {
|
|
create: {
|
|
after: async (session, context) => {
|
|
if (context?.path.includes('/sign-in')) {
|
|
await createAuditLog({
|
|
action: 'sign_in',
|
|
tableName: 'session',
|
|
recordId: session.id,
|
|
oldValue: '',
|
|
newValue: JSON.stringify(session),
|
|
userId: session.userId,
|
|
});
|
|
}
|
|
},
|
|
},
|
|
delete: {
|
|
after: async (session, context) => {
|
|
if (context?.path === '/sign-out') {
|
|
await createAuditLog({
|
|
action: 'sign_out',
|
|
tableName: 'session',
|
|
recordId: session.id,
|
|
oldValue: JSON.stringify(session),
|
|
newValue: '',
|
|
userId: session.userId,
|
|
});
|
|
}
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|