import { db } from "@/database/db"; import { task, user } from "@/database/schema"; import { dbGetAll } from "@/lib/db/drizzle-client"; import { getRangeValue } from "@/lib/utils"; import { and, eq, gte, lte, ne } from "drizzle-orm"; import { SendInvitation, UpdateUserMetadata, User, UserById, UserId, } from "../domain/models"; import { FilterTasks } from "@/server/task/domain/models"; import { createLogRecord } from "@/server/log"; import { UserRepository } from "../domain/repositories"; import { createClerkClient } from "@clerk/backend"; import { VARIABLES_CONFIG } from "@/lib/db/util"; const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY, }); class UserRepositoryImpl implements UserRepository { async getAll(userId: UserId): Promise { const data = await dbGetAll("user", { where: and(ne(user.id, userId.value), ne(user.isDeleted, true)), }); return data as User[]; } async getBy(params: Partial): Promise { const whereClouse = Object.entries(params).map(([key, value]) => eq(user[key as keyof unknown], value) ); const data = await db.query.user.findFirst({ where: and(...whereClouse), columns: { id: true, firstName: true, lastName: true, email: true, createdAt: true, rol: true, }, }); return data as User; } async getWithTaskById( userId: UserId, filter: FilterTasks ): Promise { const taskRange = filter?.range ? getRangeValue(filter.range!) : undefined; const data = await db.query.user.findFirst({ where: eq(user.id, userId.value), columns: { id: true, firstName: true, lastName: true, email: true, createdAt: true, rol: true, }, with: { tasks: { columns: { id: true, status: true, priority: true, startDate: true, floorName: true, projectName: true, projectId: true, areaName: true, startedTime: true, endedTime: true, expireDate: true, comments: true, createdAT: true, updatedAt: true, areaId: true, userId: true, }, where: and( taskRange ? and( gte(task.createdAT, taskRange.start), lte(task.createdAT, taskRange.end) ) : undefined, filter?.status ? eq(task.status, filter.status! as any) : undefined ), }, userTool: { columns: { id: true, quantity: true }, with: { tool: { columns: { id: true, name: true, quantity: true } } }, }, }, }); const filteredUserTools = data?.userTool.filter( (item) => item.quantity > 0 ); return { ...data, userTools: filteredUserTools, } as UserById; } async createDb(data: User): Promise { return await db.transaction(async (tx) => { const [userCreated] = await tx .insert(user) .values({ ...data, rol: data.rol as any, id: data.id }) .returning() .onConflictDoUpdate({ target:user.email, set: { isDeleted: false }, }); if (userCreated) { await createLogRecord(tx, { userId: data.id, eventType: "crear", tableName: "user", item: data, modifiedItem: `${data.firstName} ${data.lastName}`, }); } return userCreated as User; }); } async sendInvitation(data: SendInvitation): Promise { const response = await clerkClient.invitations.createInvitation({ emailAddress: data.emailAddress, redirectUrl: `${VARIABLES_CONFIG.APP_URL}/auth/accept-invitation`, publicMetadata: { role: data.rol, }, ignoreExisting: true, notify: true, }); return (await response) as any; } async banUser(userId: UserId): Promise { try { await clerkClient.users.lockUser(userId.value); await db .update(user) .set({ isActive: false }) .where(eq(user.id, userId.value)); } catch (error) { throw error; } } async unbanUser(userId: UserId): Promise { try { await clerkClient.users.unlockUser(userId.value); await db .update(user) .set({ isActive: true }) .where(eq(user.id, userId.value)); } catch (error) { throw error; } } async updateClerk(data: Partial): Promise { try { await clerkClient.users.updateUser(data.id!, { ...data, publicMetadata: { role: data.rol }, }); return data as any; } catch (error) { throw error; } } async updateUserMetadataClerk(data: UpdateUserMetadata): Promise { try { await clerkClient.users.updateUserMetadata(data.seccionId, { publicMetadata: { ...(data.existInDb && { existInDb: data.existInDb }), ...(data.rol && { role: data.rol }), }, }); } catch (error) { throw error; } } async updateDb(data: User): Promise { await db.transaction(async (tx) => { const updateDbPromise = tx .update(user) .set({ ...data }) .where(eq(user.id, data.id)); const createLogRecordPrimise = createLogRecord(tx, { userId: data.id!, eventType: "modificar", tableName: "user", item: data, modifiedItem: `${data?.firstName} ${data?.lastName}`, }); await Promise.all([updateDbPromise, createLogRecordPrimise]); }); return data; } async deleteClerk(userId: UserId): Promise { await clerkClient.users.deleteUser(userId.value); } async deleteDb(userId: UserId): Promise { return await db.transaction(async (tx) => { const [deletedUser] = await tx .update(user) .set({ isDeleted: true }) .where(eq(user.id, userId.value)) .returning(); if (deletedUser) { await createLogRecord(tx, { userId: userId.value!, eventType: "eliminar", tableName: "user", item: deletedUser, modifiedItem: `usuario ${deletedUser.firstName} ${deletedUser.lastName} eliminado`, }); } return deletedUser as User; }); } } export const defaultUserRepository = new UserRepositoryImpl();