88 lines
2.7 KiB
TypeScript
88 lines
2.7 KiB
TypeScript
import { getPayload as _getPayload } from "payload";
|
|
import type { SanitizedConfig } from "payload";
|
|
import type { AuditLogProtocol } from "@repo/core-shared/di";
|
|
import type { IProcessingRestriction } from "./processing-restriction.interface";
|
|
|
|
type PayloadDoc = Record<string, unknown>;
|
|
|
|
type PayloadAPI = {
|
|
find(args: {
|
|
collection: string;
|
|
where: Record<string, unknown>;
|
|
overrideAccess: true;
|
|
limit: number;
|
|
}): Promise<{ docs: PayloadDoc[] }>;
|
|
update(args: {
|
|
collection: string;
|
|
id: string;
|
|
data: Record<string, unknown>;
|
|
overrideAccess: true;
|
|
}): Promise<PayloadDoc>;
|
|
};
|
|
|
|
type GetPayload = (args: { config: SanitizedConfig }) => Promise<PayloadAPI>;
|
|
|
|
const USERS_COLLECTION = "users";
|
|
const RESTRICTION_FIELD = "processingRestrictedAt";
|
|
|
|
/**
|
|
* Payload-backed IProcessingRestriction. Toggles and reads the
|
|
* `processingRestrictedAt` date field on the subject's user record.
|
|
*
|
|
* Emits RESTRICT or UNRESTRICT audit entries on every state change.
|
|
* The `subjectId` is the document ID in the `users` collection.
|
|
*/
|
|
export class PayloadProcessingRestriction implements IProcessingRestriction {
|
|
constructor(
|
|
private readonly config: SanitizedConfig,
|
|
private readonly auditLog: AuditLogProtocol,
|
|
private readonly getPayloadFn: GetPayload = _getPayload as unknown as GetPayload,
|
|
) {}
|
|
|
|
async setRestriction(subjectId: string, granted: boolean): Promise<void> {
|
|
const payload = await this.getPayloadFn({ config: this.config });
|
|
|
|
await payload.update({
|
|
collection: USERS_COLLECTION,
|
|
id: subjectId,
|
|
data: { [RESTRICTION_FIELD]: granted ? new Date().toISOString() : null },
|
|
overrideAccess: true,
|
|
});
|
|
|
|
await this.auditLog.record({
|
|
actorId: subjectId,
|
|
actorType: "user",
|
|
actorRoles: [],
|
|
action: granted ? "RESTRICT" : "UNRESTRICT",
|
|
resource: { type: USERS_COLLECTION, id: subjectId },
|
|
changedFields: [RESTRICTION_FIELD],
|
|
at: new Date(),
|
|
scope: {
|
|
feature: "core-dsr",
|
|
environment: process.env["NODE_ENV"] ?? "development",
|
|
tenant: "default",
|
|
},
|
|
from: { ipTruncated: "system", userAgent: "system" },
|
|
containsPii: false,
|
|
outcome: "success",
|
|
});
|
|
}
|
|
|
|
async isRestricted(subjectId: string): Promise<boolean> {
|
|
const payload = await this.getPayloadFn({ config: this.config });
|
|
|
|
const result = await payload.find({
|
|
collection: USERS_COLLECTION,
|
|
where: { id: { equals: subjectId } },
|
|
overrideAccess: true,
|
|
limit: 1,
|
|
});
|
|
|
|
const doc = result.docs[0];
|
|
if (!doc) return false;
|
|
|
|
const restrictedAt = doc[RESTRICTION_FIELD];
|
|
return restrictedAt !== null && restrictedAt !== undefined;
|
|
}
|
|
}
|