perbaikan tambah akun dan akses setiap role
This commit is contained in:
+1
-1
@@ -112,7 +112,7 @@ export async function seedLocalUserIfMissing() {
|
||||
}
|
||||
// Check existence without selecting `password_hash` to avoid failures on older schemas
|
||||
try {
|
||||
const [rows] = await db.execute(sql`SELECT id FROM users WHERE unionId = ${LocalAuth.defaultAdminEmail} LIMIT 1`);
|
||||
await db.execute(sql`SELECT id FROM users WHERE unionId = ${LocalAuth.defaultAdminEmail} LIMIT 1`);
|
||||
} catch (err) {
|
||||
console.warn('[seed] existence check failed, will attempt to insert anyway', err);
|
||||
}
|
||||
|
||||
@@ -50,3 +50,39 @@ export async function upsertUser(data: InsertUser) {
|
||||
.values(values)
|
||||
.onDuplicateKeyUpdate({ set: updateSet });
|
||||
}
|
||||
|
||||
export async function findAllUsers() {
|
||||
return getDb()
|
||||
.select({
|
||||
id: schema.users.id,
|
||||
unionId: schema.users.unionId,
|
||||
name: schema.users.name,
|
||||
email: schema.users.email,
|
||||
role: schema.users.role,
|
||||
avatar: schema.users.avatar,
|
||||
createdAt: schema.users.createdAt,
|
||||
updatedAt: schema.users.updatedAt,
|
||||
lastSignInAt: schema.users.lastSignInAt,
|
||||
})
|
||||
.from(schema.users)
|
||||
.orderBy(schema.users.createdAt);
|
||||
}
|
||||
|
||||
export async function createUser(data: InsertUser) {
|
||||
const [result] = await getDb().insert(schema.users).values(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function updateUser(id: number, data: Partial<InsertUser>) {
|
||||
const result = await getDb()
|
||||
.update(schema.users)
|
||||
.set(data)
|
||||
.where(eq(schema.users.id, id));
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function deleteUser(id: number) {
|
||||
await getDb()
|
||||
.delete(schema.users)
|
||||
.where(eq(schema.users.id, id));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { recipientRouter } from "./recipientRouter";
|
||||
import { distributionRouter } from "./distributionRouter";
|
||||
import { dashboardRouter } from "./dashboardRouter";
|
||||
import { seedRouter } from "./seedRouter";
|
||||
import { userRouter } from "./userRouter";
|
||||
import { createRouter, publicQuery } from "./middleware";
|
||||
|
||||
export const appRouter = createRouter({
|
||||
@@ -14,6 +15,7 @@ export const appRouter = createRouter({
|
||||
distribution: distributionRouter,
|
||||
dashboard: dashboardRouter,
|
||||
seed: seedRouter,
|
||||
user: userRouter,
|
||||
});
|
||||
|
||||
export type AppRouter = typeof appRouter;
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
import { z } from "zod";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { createRouter, adminQuery } from "./middleware";
|
||||
import {
|
||||
findAllUsers,
|
||||
createUser,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
findUserByLoginIdentifier,
|
||||
} from "./queries/users";
|
||||
import { hashPassword } from "./auth";
|
||||
import { createActivityLog } from "./queries/activityLogs";
|
||||
|
||||
async function logActivitySafe(payload: Parameters<typeof createActivityLog>[0]) {
|
||||
try {
|
||||
await createActivityLog(payload);
|
||||
} catch (error) {
|
||||
console.warn("[activity] failed to write user activity", error);
|
||||
}
|
||||
}
|
||||
|
||||
export const userRouter = createRouter({
|
||||
list: adminQuery.query(async () => {
|
||||
return findAllUsers();
|
||||
}),
|
||||
|
||||
create: adminQuery
|
||||
.input(
|
||||
z.object({
|
||||
name: z.string().min(1),
|
||||
email: z.string().email(),
|
||||
password: z.string().min(6),
|
||||
role: z.enum(["admin", "officer", "manager"]),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const existing = await findUserByLoginIdentifier(input.email);
|
||||
if (existing) {
|
||||
throw new TRPCError({
|
||||
code: "CONFLICT",
|
||||
message: "Email sudah terdaftar di sistem.",
|
||||
});
|
||||
}
|
||||
|
||||
const result = await createUser({
|
||||
unionId: input.email,
|
||||
name: input.name,
|
||||
email: input.email,
|
||||
passwordHash: hashPassword(input.password),
|
||||
role: input.role,
|
||||
lastSignInAt: new Date(),
|
||||
});
|
||||
|
||||
const insertedId = result.insertId;
|
||||
|
||||
await logActivitySafe({
|
||||
userId: ctx.user.id,
|
||||
action: "CREATE",
|
||||
entityType: "user",
|
||||
entityId: insertedId,
|
||||
details: `Membuat akun baru: ${input.name} (${input.role})`,
|
||||
});
|
||||
|
||||
return { success: true, id: insertedId };
|
||||
}),
|
||||
|
||||
update: adminQuery
|
||||
.input(
|
||||
z.object({
|
||||
id: z.number(),
|
||||
name: z.string().min(1).optional(),
|
||||
email: z.string().email().optional(),
|
||||
password: z.string().min(6).optional(),
|
||||
role: z.enum(["admin", "officer", "manager"]).optional(),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const updatedFields: Record<string, any> = {};
|
||||
|
||||
if (input.name !== undefined) updatedFields.name = input.name;
|
||||
if (input.email !== undefined) {
|
||||
const existing = await findUserByLoginIdentifier(input.email);
|
||||
if (existing && existing.id !== input.id) {
|
||||
throw new TRPCError({
|
||||
code: "CONFLICT",
|
||||
message: "Email sudah terdaftar untuk pengguna lain.",
|
||||
});
|
||||
}
|
||||
updatedFields.email = input.email;
|
||||
updatedFields.unionId = input.email;
|
||||
}
|
||||
if (input.password !== undefined) {
|
||||
updatedFields.passwordHash = hashPassword(input.password);
|
||||
}
|
||||
if (input.role !== undefined) updatedFields.role = input.role;
|
||||
|
||||
await updateUser(input.id, updatedFields);
|
||||
|
||||
await logActivitySafe({
|
||||
userId: ctx.user.id,
|
||||
action: "UPDATE",
|
||||
entityType: "user",
|
||||
entityId: input.id,
|
||||
details: `Memperbarui akun pengguna ID ${input.id}`,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
}),
|
||||
|
||||
delete: adminQuery
|
||||
.input(z.object({ id: z.number() }))
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (input.id === ctx.user.id) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Anda tidak dapat menghapus akun Anda sendiri.",
|
||||
});
|
||||
}
|
||||
|
||||
await deleteUser(input.id);
|
||||
|
||||
await logActivitySafe({
|
||||
userId: ctx.user.id,
|
||||
action: "DELETE",
|
||||
entityType: "user",
|
||||
entityId: input.id,
|
||||
details: `Menghapus akun pengguna ID ${input.id}`,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
}),
|
||||
});
|
||||
Reference in New Issue
Block a user