feat(housekeeping): deliver people account workflows
This commit is contained in:
1 parent
7920d4f46c
commit
e1b31ff773
45 files changed
+4290
-1243
No files matched your search
@@ -0,0 +1,138 @@
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { requirePermission } from "@/lib/admin/guard";
|
||||
|
||||
const { execute, staff } = vi.hoisted(() => ({
|
||||
execute: vi.fn(),
|
||||
staff: { id: 1, rank: 7, username: "admin" },
|
||||
}));
|
||||
|
||||
vi.mock("@/features/housekeeping/domains/people/services/mutations", () => ({
|
||||
createLegacyPeopleMutationContext: vi.fn(
|
||||
(actor, permission, correlationId) => ({
|
||||
actor,
|
||||
permission,
|
||||
correlationId,
|
||||
}),
|
||||
),
|
||||
peopleMutationService: { execute },
|
||||
}));
|
||||
vi.mock("@/lib/admin/guard", () => ({ requirePermission: vi.fn() }));
|
||||
vi.mock("@/lib/permissions", () => ({
|
||||
PERMS: {
|
||||
USERS_EDIT: "admin.users.edit",
|
||||
USERS_BAN: "admin.users.ban",
|
||||
USERS_RESET_PASSWORD: "admin.users.reset_password",
|
||||
WORDFILTER_EDIT: "admin.wordfilter.edit",
|
||||
},
|
||||
}));
|
||||
vi.mock("@/lib/safe-action", () => ({
|
||||
adminAction:
|
||||
(_options: unknown, handler: (context: unknown) => unknown) =>
|
||||
(data: unknown) =>
|
||||
handler({ data, session: { user: staff } }),
|
||||
}));
|
||||
vi.mock("@/lib/safe-action-shared", () => ({
|
||||
ActionError: class ActionError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "ActionError";
|
||||
}
|
||||
},
|
||||
actionOk: (data?: unknown) => ({ ok: true, data: data ?? {} }),
|
||||
actionError: (error: string) => ({ ok: false, error }),
|
||||
}));
|
||||
vi.mock("@/lib/auth/password", () => ({ hashPassword: vi.fn() }));
|
||||
vi.mock("@/lib/db", () => ({
|
||||
db: {},
|
||||
User: {},
|
||||
UsersBadges: {},
|
||||
UsersCurrency: {},
|
||||
UsersSettings: {},
|
||||
}));
|
||||
vi.mock("@/lib/services/audit", () => ({ logAudit: vi.fn() }));
|
||||
vi.mock("@/lib/services/rcon", () => ({ rcon: {} }));
|
||||
vi.mock("@/lib/services/webhook", () => ({ notify: vi.fn() }));
|
||||
vi.mock("next/cache", () => ({ revalidatePath: vi.fn() }));
|
||||
|
||||
import { dismissApplication } from "./admin-applications";
|
||||
import { addWord, deleteWord } from "./admin-wordfilter";
|
||||
import { banUser, resetPassword, updateUser } from "./users";
|
||||
|
||||
const form = (data: Record<string, string>) =>
|
||||
({ get: (key: string) => data[key] ?? null }) as FormData;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.mocked(requirePermission).mockResolvedValue(staff);
|
||||
execute.mockImplementation(async (context, operation) => ({
|
||||
ok: true,
|
||||
data: {
|
||||
before: {},
|
||||
after: operation === "word-filter.update" ? { id: 12 } : {},
|
||||
output:
|
||||
operation === "user.reset-password"
|
||||
? { newPassword: "temporary-password" }
|
||||
: undefined,
|
||||
},
|
||||
correlationId: context.correlationId,
|
||||
}));
|
||||
});
|
||||
|
||||
describe("legacy user safe-action wrappers", () => {
|
||||
it("preserves exact ACL-specific service delegation", async () => {
|
||||
await (updateUser as never as (input: unknown) => Promise<unknown>)({
|
||||
id: 7,
|
||||
motto: "Ready",
|
||||
});
|
||||
await (banUser as never as (input: unknown) => Promise<unknown>)({
|
||||
userId: 7,
|
||||
reason: "abuse",
|
||||
duration: 0,
|
||||
type: "account",
|
||||
});
|
||||
const reset = await (
|
||||
resetPassword as never as (input: unknown) => Promise<{
|
||||
ok: boolean;
|
||||
data: { newPassword: string };
|
||||
}>
|
||||
)({ userId: 7 });
|
||||
|
||||
expect(
|
||||
execute.mock.calls.map((call) => [call[0].permission, call[1]]),
|
||||
).toEqual([
|
||||
["admin.users.edit", "user.update"],
|
||||
["admin.users.ban", "user.ban"],
|
||||
["admin.users.reset_password", "user.reset-password"],
|
||||
]);
|
||||
expect(reset.data.newPassword).toBe("temporary-password");
|
||||
});
|
||||
});
|
||||
|
||||
describe("legacy application and word-filter wrappers", () => {
|
||||
it("keeps tolerant application dismissal and /admin revalidation", async () => {
|
||||
await dismissApplication(form({ id: "9" }));
|
||||
expect(execute).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ permission: "admin.users.edit" }),
|
||||
"application.decide",
|
||||
{ applicationId: 9, decision: "dismiss" },
|
||||
);
|
||||
expect(revalidatePath).toHaveBeenCalledWith("/admin/applications");
|
||||
});
|
||||
|
||||
it("preserves word-filter ActionResult shapes and /admin revalidation", async () => {
|
||||
await expect(addWord({ word: "spam" })).resolves.toEqual({
|
||||
ok: true,
|
||||
data: { id: "12" },
|
||||
});
|
||||
await expect(deleteWord({ id: "12" })).resolves.toEqual({
|
||||
ok: true,
|
||||
data: {},
|
||||
});
|
||||
expect(execute.mock.calls.slice(-2).map((call) => call[2])).toEqual([
|
||||
{ action: "add", word: "spam" },
|
||||
{ action: "delete", id: 12 },
|
||||
]);
|
||||
expect(revalidatePath).toHaveBeenCalledWith("/admin/wordfilter");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user