refactor(api): extract resource read procedures
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { findUniqueOrThrow } from "../db/helpers.js";
|
||||
import { ROLE_BRIEF_SELECT } from "../db/selects.js";
|
||||
import {
|
||||
anonymizeResource,
|
||||
getAnonymizationDirectory,
|
||||
} from "../lib/anonymization.js";
|
||||
import { assertCanReadResource } from "../lib/resource-access.js";
|
||||
import { protectedProcedure } from "../trpc.js";
|
||||
import {
|
||||
mapResourceDetail,
|
||||
readResourceByIdentifierDetailSnapshot,
|
||||
resolveResourceIdentifierSnapshot,
|
||||
} from "./resource-read-shared.js";
|
||||
|
||||
export const resourceIdentifierReadProcedures = {
|
||||
resolveByIdentifier: protectedProcedure
|
||||
.input(z.object({ identifier: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const resource = await resolveResourceIdentifierSnapshot(
|
||||
ctx,
|
||||
input.identifier,
|
||||
"You can only resolve your own resource unless you have staff access",
|
||||
);
|
||||
if ("error" in resource) {
|
||||
throw new TRPCError({ code: "NOT_FOUND", message: "Resource not found" });
|
||||
}
|
||||
return resource;
|
||||
}),
|
||||
|
||||
getHoverCard: protectedProcedure
|
||||
.input(z.object({ id: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const resource = await findUniqueOrThrow(
|
||||
ctx.db.resource.findUnique({
|
||||
where: { id: input.id },
|
||||
select: {
|
||||
id: true,
|
||||
displayName: true,
|
||||
eid: true,
|
||||
email: true,
|
||||
chapter: true,
|
||||
lcrCents: true,
|
||||
ucrCents: true,
|
||||
currency: true,
|
||||
chargeabilityTarget: true,
|
||||
skills: true,
|
||||
availability: true,
|
||||
isActive: true,
|
||||
areaRole: { select: ROLE_BRIEF_SELECT },
|
||||
country: { select: { name: true, code: true } },
|
||||
managementLevel: { select: { name: true } },
|
||||
resourceType: true,
|
||||
},
|
||||
}),
|
||||
"Resource",
|
||||
);
|
||||
await assertCanReadResource(
|
||||
ctx,
|
||||
resource.id,
|
||||
"You can only view hover details for your own resource unless you have staff access",
|
||||
);
|
||||
const directory = await getAnonymizationDirectory(ctx.db);
|
||||
const anon = anonymizeResource(resource, directory);
|
||||
return {
|
||||
id: anon.id,
|
||||
displayName: anon.displayName ?? "",
|
||||
eid: anon.eid ?? "",
|
||||
chapter: resource.chapter,
|
||||
lcrCents: resource.lcrCents,
|
||||
ucrCents: resource.ucrCents,
|
||||
currency: resource.currency,
|
||||
chargeabilityTarget: resource.chargeabilityTarget,
|
||||
skills: resource.skills as Record<string, unknown>[],
|
||||
isActive: resource.isActive,
|
||||
resourceType: resource.resourceType,
|
||||
areaRole: resource.areaRole,
|
||||
country: resource.country,
|
||||
managementLevel: resource.managementLevel,
|
||||
};
|
||||
}),
|
||||
|
||||
getByIdentifier: protectedProcedure
|
||||
.input(z.object({ identifier: z.string() }))
|
||||
.query(async ({ ctx, input }) => resolveResourceIdentifierSnapshot(ctx, input.identifier)),
|
||||
|
||||
getByIdentifierDetail: protectedProcedure
|
||||
.input(z.object({ identifier: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const resource = await readResourceByIdentifierDetailSnapshot(ctx, input.identifier);
|
||||
if ("error" in resource) {
|
||||
return resource;
|
||||
}
|
||||
return mapResourceDetail(resource);
|
||||
}),
|
||||
|
||||
getById: protectedProcedure
|
||||
.input(z.object({ id: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const resource = await findUniqueOrThrow(
|
||||
ctx.db.resource.findUnique({
|
||||
where: { id: input.id },
|
||||
include: {
|
||||
blueprint: true,
|
||||
resourceRoles: {
|
||||
include: { role: { select: ROLE_BRIEF_SELECT } },
|
||||
},
|
||||
areaRole: { select: { id: true, name: true } },
|
||||
},
|
||||
}),
|
||||
"Resource",
|
||||
);
|
||||
await assertCanReadResource(
|
||||
ctx,
|
||||
resource.id,
|
||||
"You can only view your own resource unless you have staff access",
|
||||
);
|
||||
|
||||
const directory = await getAnonymizationDirectory(ctx.db);
|
||||
return {
|
||||
...anonymizeResource(resource, directory),
|
||||
isOwnedByCurrentUser: Boolean(resource.userId && ctx.dbUser?.id && resource.userId === ctx.dbUser.id),
|
||||
};
|
||||
}),
|
||||
|
||||
getByEid: protectedProcedure
|
||||
.input(z.object({ eid: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const directory = await getAnonymizationDirectory(ctx.db);
|
||||
let resource = await ctx.db.resource.findUnique({ where: { eid: input.eid } });
|
||||
if (!resource && directory) {
|
||||
const resourceId = directory.byAliasEid.get(input.eid.trim().toLowerCase());
|
||||
if (resourceId) {
|
||||
resource = await ctx.db.resource.findUnique({ where: { id: resourceId } });
|
||||
}
|
||||
}
|
||||
if (!resource) {
|
||||
throw new TRPCError({ code: "NOT_FOUND", message: "Resource not found" });
|
||||
}
|
||||
await assertCanReadResource(
|
||||
ctx,
|
||||
resource.id,
|
||||
"You can only view your own resource unless you have staff access",
|
||||
);
|
||||
return anonymizeResource(resource, directory);
|
||||
}),
|
||||
};
|
||||
Reference in New Issue
Block a user