import type { z } from "zod"; import { adminProcedure, createTRPCRouter, managerProcedure, protectedProcedure, publicProcedure, } from "../trpc.js"; import { autoLinkUsersByEmail, countActiveUsers, CreateUserInputSchema, createUser, deactivateUser, reactivateUser, deleteUser, disableTotp, getEffectiveUserPermissions, LinkUserResourceInputSchema, linkUserResource, listAssignableUsers, listUsers, SetUserPasswordInputSchema, setUserPassword, SetUserPermissionsInputSchema, setUserPermissions, UpdateUserNameInputSchema, updateUserName, UpdateUserRoleInputSchema, updateUserRole, UserIdInputSchema, resetUserPermissions, } from "./user-procedure-support.js"; import { generateTotpSecret, getColumnPreferences, getCurrentMfaStatus, getCurrentUserProfile, getDashboardLayout, getFavoriteProjectIds, SaveDashboardLayoutInputSchema, saveDashboardLayout, SetColumnPreferencesInputSchema, setColumnPreferences, regenerateBackupCodes, ToggleFavoriteProjectInputSchema, toggleFavoriteProject, verifyAndEnableTotp as verifyAndEnableTotpSelfService, VerifyAndEnableTotpInputSchema, verifyTotp, VerifyTotpInputSchema, } from "./user-self-service-procedure-support.js"; export const userRouter = createTRPCRouter({ /** Lightweight user list for task assignment (ADMIN + MANAGER) */ listAssignable: managerProcedure.query(({ ctx }) => listAssignableUsers(ctx)), list: adminProcedure.query(({ ctx }) => listUsers(ctx)), /** Count of users active in the last 5 minutes */ activeCount: adminProcedure.query(({ ctx }) => countActiveUsers(ctx)), me: protectedProcedure.query(({ ctx }) => getCurrentUserProfile(ctx)), create: adminProcedure .input(CreateUserInputSchema) .mutation(({ ctx, input }) => createUser(ctx, input)), setPassword: adminProcedure .input(SetUserPasswordInputSchema) .mutation(({ ctx, input }) => setUserPassword(ctx, input)), updateRole: adminProcedure .input(UpdateUserRoleInputSchema) .mutation(({ ctx, input }) => updateUserRole(ctx, input)), updateName: adminProcedure .input(UpdateUserNameInputSchema) .mutation(({ ctx, input }) => updateUserName(ctx, input)), // ─── Resource Linking ────────────────────────────────────────────────── linkResource: adminProcedure .input(LinkUserResourceInputSchema) .mutation(({ ctx, input }) => linkUserResource(ctx, input)), autoLinkAllByEmail: adminProcedure.mutation(({ ctx }) => autoLinkUsersByEmail(ctx)), getDashboardLayout: protectedProcedure.query(({ ctx }) => getDashboardLayout(ctx)), saveDashboardLayout: protectedProcedure .input(SaveDashboardLayoutInputSchema) .mutation(({ ctx, input }) => saveDashboardLayout(ctx, input)), // ─── Favorite Projects ────────────────────────────────────────────────── getFavoriteProjectIds: protectedProcedure.query(({ ctx }) => getFavoriteProjectIds(ctx)), toggleFavoriteProject: protectedProcedure .input(ToggleFavoriteProjectInputSchema) .mutation(({ ctx, input }) => toggleFavoriteProject(ctx, input)), setPermissions: adminProcedure .input( SetUserPermissionsInputSchema as z.ZodType>, ) .mutation(({ ctx, input }) => setUserPermissions(ctx, input)), resetPermissions: adminProcedure .input(UserIdInputSchema) .mutation(({ ctx, input }) => resetUserPermissions(ctx, input)), getColumnPreferences: protectedProcedure.query(({ ctx }) => getColumnPreferences(ctx)), setColumnPreferences: protectedProcedure .input(SetColumnPreferencesInputSchema) .mutation(({ ctx, input }) => setColumnPreferences(ctx, input)), getEffectivePermissions: adminProcedure .input(UserIdInputSchema) .query(({ ctx, input }) => getEffectiveUserPermissions(ctx, input)), // ─── TOTP / MFA ───────────────────────────────────────────────────────────── /** Generate a new TOTP secret for the current user (not yet enabled). */ generateTotpSecret: protectedProcedure.mutation(({ ctx }) => generateTotpSecret(ctx)), /** Verify a TOTP token and enable MFA for the current user. */ verifyAndEnableTotp: protectedProcedure .input(VerifyAndEnableTotpInputSchema) .mutation(({ ctx, input }) => verifyAndEnableTotpSelfService(ctx, input)), deactivate: adminProcedure .input(UserIdInputSchema) .mutation(({ ctx, input }) => deactivateUser(ctx, input)), reactivate: adminProcedure .input(UserIdInputSchema) .mutation(({ ctx, input }) => reactivateUser(ctx, input)), delete: adminProcedure .input(UserIdInputSchema) .mutation(({ ctx, input }) => deleteUser(ctx, input)), /** Admin override: disable TOTP for a specific user. */ disableTotp: adminProcedure .input(UserIdInputSchema) .mutation(({ ctx, input }) => disableTotp(ctx, input)), /** Verify a TOTP token (used during the login flow — public procedure). */ verifyTotp: publicProcedure .input(VerifyTotpInputSchema) .mutation(({ ctx, input }) => verifyTotp(ctx, input)), /** Get MFA status for the current user. */ getMfaStatus: protectedProcedure.query(({ ctx }) => getCurrentMfaStatus(ctx)), /** Generate a fresh set of MFA backup codes, invalidating any previous set. */ regenerateBackupCodes: protectedProcedure.mutation(({ ctx }) => regenerateBackupCodes(ctx)), });