feat: guest role for clients and outsiders
A project member can be a GUEST. In a private project a guest only sees the tickets they take part in (opened, assigned or followed): every other ticket answers 404, also in my work, realtime changes, blockers and linked tickets, and project-wide views (activity, statistics, dashboard, releases, sprints, epics, trash) answer 403. Guests open tickets without assigning or planning them, and comment, attach, follow and vote on their own; they change nothing else. In a public project they see what anyone does. The web gives them only Tablero, Lista and Miembros and loads none of the project-wide data. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -200,6 +200,15 @@ export class Issue extends VersionedAggregateRoot implements IssueProps {
|
||||
this.apply(new IssueUpdatedEvent(actorId, this.id, this.projectId, patch));
|
||||
}
|
||||
|
||||
/** Opened it, has it, or follows it: what a guest may see. */
|
||||
involves(userId: string): boolean {
|
||||
return (
|
||||
this.reporterId === userId ||
|
||||
this.assigneeId === userId ||
|
||||
this.watchers.includes(userId)
|
||||
);
|
||||
}
|
||||
|
||||
/** Moves the ticket along its project's workflow. */
|
||||
changeStatus(
|
||||
actorId: string,
|
||||
|
||||
@@ -4,4 +4,9 @@ export enum ProjectRole {
|
||||
MEMBER = 'MEMBER',
|
||||
/** Read-only stakeholder (PM, client...). */
|
||||
VIEWER = 'VIEWER',
|
||||
/**
|
||||
* Someone from outside (a client): in a private project, sees only the
|
||||
* tickets they take part in, opens tickets and comments on theirs.
|
||||
*/
|
||||
GUEST = 'GUEST',
|
||||
}
|
||||
|
||||
@@ -102,9 +102,31 @@ export class Project extends VersionedAggregateRoot implements ProjectProps {
|
||||
if (this.roleOf(userId) === ProjectRole.VIEWER) {
|
||||
throw new ForbiddenError(`Viewers cannot modify project ${this.key}`);
|
||||
}
|
||||
if (this.roleOf(userId) === ProjectRole.GUEST) {
|
||||
throw new ForbiddenError(
|
||||
`Los invitados solo pueden abrir tickets en ${this.key} y comentar en los suyos`,
|
||||
);
|
||||
}
|
||||
this.assertNotArchived();
|
||||
}
|
||||
|
||||
/** Can open tickets and comment: members and guests (not viewers). */
|
||||
assertCanReport(userId: string): void {
|
||||
const role = this.roleOf(userId);
|
||||
if (!role) {
|
||||
throw new ForbiddenError(`You are not a member of project ${this.key}`);
|
||||
}
|
||||
if (role === ProjectRole.VIEWER) {
|
||||
throw new ForbiddenError(`Viewers cannot modify project ${this.key}`);
|
||||
}
|
||||
this.assertNotArchived();
|
||||
}
|
||||
|
||||
/** A guest of a private project: they only see the tickets they take part in. */
|
||||
seesOnlyOwnTickets(userId: string): boolean {
|
||||
return !this.isPublic && this.roleOf(userId) === ProjectRole.GUEST;
|
||||
}
|
||||
|
||||
/** Can change members, releases, settings and rules (owners and admins). */
|
||||
assertCanManage(userId: string): void {
|
||||
this.assertManages(userId);
|
||||
|
||||
Reference in New Issue
Block a user