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[], 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); }), };