import { Injectable } from '@nestjs/common'; import { IssuesService, ProjectsService, WorkflowsService, } from '@task-stream/api/tracker/application'; import { IssueReadModel, ProjectReadModel, } from '@task-stream/api/tracker/domain'; import { toSettingsPayload } from '../common/settings'; const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; /** * REST routes accept a project or ticket by id or by key (`WEB`, `WEB-12`), * which is what other apps usually have. Keys are looked up in the read model; * ids go straight to the command (the service still checks membership). */ @Injectable() export class Refs { constructor( private readonly projects: ProjectsService, private readonly issues: IssuesService, private readonly workflows: WorkflowsService, ) {} async projectId(viewerId: string | null, ref: string): Promise { if (UUID.test(ref)) return ref; return (await this.projects.findOne(viewerId, ref)).id; } async issueId(viewerId: string | null, ref: string): Promise { if (UUID.test(ref)) return ref; return (await this.issues.findOne(viewerId, ref)).id; } /** The ticket as the REST API returns it: read model + allowed transitions. */ async issueDto(issue: IssueReadModel) { return { ...issue, allowedTransitions: await this.workflows.allowedTransitions(issue), }; } issueDtos(issues: IssueReadModel[]) { return Promise.all(issues.map((issue) => this.issueDto(issue))); } } /** The project as the REST API returns it: transitions as a list. */ export function toProjectDto(project: ProjectReadModel) { return { ...project, settings: toSettingsPayload(project.settings) }; }