1df208dbcc
Allocation bars that have active optimistic overrides (post-drag, awaiting server confirmation) now pulse subtly via animate-pulse. The pending set is derived from the existing optimisticAllocations map keys, requiring no additional state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
67 lines
1.7 KiB
TypeScript
67 lines
1.7 KiB
TypeScript
import { TRPCError } from "@trpc/server";
|
|
import { isAdminOrManager } from "@capakraken/shared";
|
|
import type { TRPCContext } from "../trpc.js";
|
|
|
|
export type OwnedResourceReadContext = Pick<TRPCContext, "db" | "dbUser">;
|
|
|
|
export function canManageOwnedResourceReads(ctx: { dbUser: { systemRole: string } | null }): boolean {
|
|
return isAdminOrManager(ctx.dbUser?.systemRole);
|
|
}
|
|
|
|
export async function findOwnedReadResourceId(
|
|
ctx: OwnedResourceReadContext,
|
|
): Promise<string | null> {
|
|
if (!ctx.dbUser?.id) {
|
|
return null;
|
|
}
|
|
|
|
if (!ctx.db.resource || typeof ctx.db.resource.findFirst !== "function") {
|
|
return null;
|
|
}
|
|
|
|
const resource = await ctx.db.resource.findFirst({
|
|
where: { userId: ctx.dbUser.id },
|
|
select: { id: true },
|
|
});
|
|
|
|
return resource?.id ?? null;
|
|
}
|
|
|
|
export async function assertCanReadOwnedResource(
|
|
ctx: OwnedResourceReadContext,
|
|
resourceId: string,
|
|
forbiddenMessage: string,
|
|
): Promise<void> {
|
|
if (canManageOwnedResourceReads(ctx)) {
|
|
return;
|
|
}
|
|
|
|
const ownedResourceId = await findOwnedReadResourceId(ctx);
|
|
if (!ownedResourceId || ownedResourceId !== resourceId) {
|
|
throw new TRPCError({
|
|
code: "FORBIDDEN",
|
|
message: forbiddenMessage,
|
|
});
|
|
}
|
|
}
|
|
|
|
export async function resolveOwnedResourceReadFilter(
|
|
ctx: OwnedResourceReadContext,
|
|
requestedResourceId: string | undefined,
|
|
forbiddenMessage: string,
|
|
): Promise<string | null | undefined> {
|
|
if (canManageOwnedResourceReads(ctx)) {
|
|
return requestedResourceId;
|
|
}
|
|
|
|
const ownedResourceId = await findOwnedReadResourceId(ctx);
|
|
if (requestedResourceId && requestedResourceId !== ownedResourceId) {
|
|
throw new TRPCError({
|
|
code: "FORBIDDEN",
|
|
message: forbiddenMessage,
|
|
});
|
|
}
|
|
|
|
return ownedResourceId;
|
|
}
|