149 lines
5.0 KiB
TypeScript
149 lines
5.0 KiB
TypeScript
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);
|
|
}),
|
|
};
|