On the releases page, «Página pública» (owners and admins) opens a
secret link to a page with the release's notes, readable without an
account, also for private projects: the notes written, or the draft
from its finished tickets while there are none (without repeating the
title the page already shows). The link can be copied, renewed (the old
one stops working) or withdrawn. Stored in Mongo (`release_note_shares`).
API: shareReleaseNotes / unshareReleaseNotes / releaseNotesShare,
publicReleaseNotes(token); GET/PUT/DELETE /api/releases/{id}/public-notes,
GET /api/shared/release-notes/{token}. Web: /notes/:token.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
96 lines
2.8 KiB
TypeScript
96 lines
2.8 KiB
TypeScript
import { CommandRunner } from '@task-stream/api/shared/application';
|
|
import { Injectable } from '@nestjs/common';
|
|
import { QueryBus } from '@nestjs/cqrs';
|
|
import {
|
|
DashboardShareReadModel,
|
|
SharedDashboardReadModel,
|
|
} from '@task-stream/api/tracker/domain';
|
|
import {
|
|
GetDashboardShareQuery,
|
|
GetSharedDashboardQuery,
|
|
ShareDashboardCommand,
|
|
UnshareDashboardCommand,
|
|
} from './sharing/dashboard-shares';
|
|
import { ReleaseNotesShare } from './ports/release-note-shares.repository';
|
|
import {
|
|
GetPublicReleaseNotesQuery,
|
|
GetReleaseNotesShareQuery,
|
|
PublicReleaseNotes,
|
|
ShareReleaseNotesCommand,
|
|
UnshareReleaseNotesCommand,
|
|
} from './sharing/release-notes-shares';
|
|
|
|
/** The project's dashboard and its releases' notes, behind secret links. */
|
|
@Injectable()
|
|
export class SharingService {
|
|
constructor(
|
|
private readonly commands: CommandRunner,
|
|
private readonly queryBus: QueryBus,
|
|
) {}
|
|
|
|
/** The project's link, if it has one (owners and admins). */
|
|
share(
|
|
viewerId: string,
|
|
projectId: string,
|
|
): Promise<DashboardShareReadModel | null> {
|
|
return this.queryBus.execute(
|
|
new GetDashboardShareQuery(projectId, viewerId),
|
|
);
|
|
}
|
|
|
|
/** Turns the link on or changes its blocks; `renew` makes a new secret. */
|
|
save(
|
|
actorId: string,
|
|
projectId: string,
|
|
blocks: string[],
|
|
renew = false,
|
|
): Promise<DashboardShareReadModel> {
|
|
return this.commands.execute(
|
|
new ShareDashboardCommand(projectId, actorId, blocks, renew),
|
|
);
|
|
}
|
|
|
|
remove(actorId: string, projectId: string): Promise<void> {
|
|
return this.commands.execute(
|
|
new UnshareDashboardCommand(projectId, actorId),
|
|
);
|
|
}
|
|
|
|
/** A release's public notes link, if any (owners and admins). */
|
|
releaseNotesShare(
|
|
viewerId: string,
|
|
releaseId: string,
|
|
): Promise<ReleaseNotesShare | null> {
|
|
return this.queryBus.execute(
|
|
new GetReleaseNotesShareQuery(viewerId, releaseId),
|
|
);
|
|
}
|
|
|
|
/** Turns a release's public notes on; `renew` makes a new secret. */
|
|
shareReleaseNotes(
|
|
actorId: string,
|
|
releaseId: string,
|
|
renew = false,
|
|
): Promise<ReleaseNotesShare> {
|
|
return this.commands.execute(
|
|
new ShareReleaseNotesCommand(actorId, releaseId, renew),
|
|
);
|
|
}
|
|
|
|
unshareReleaseNotes(actorId: string, releaseId: string): Promise<void> {
|
|
return this.commands.execute(
|
|
new UnshareReleaseNotesCommand(actorId, releaseId),
|
|
);
|
|
}
|
|
|
|
/** A release's notes for anyone with the link, or null. */
|
|
publicReleaseNotes(token: string): Promise<PublicReleaseNotes | null> {
|
|
return this.queryBus.execute(new GetPublicReleaseNotesQuery(token));
|
|
}
|
|
|
|
/** What a link shows now, or null if no project has it. */
|
|
shared(token: string): Promise<SharedDashboardReadModel | null> {
|
|
return this.queryBus.execute(new GetSharedDashboardQuery(token));
|
|
}
|
|
}
|