feat(threads): governed group settings — rename, list members, remove participant
- MessageService.renameThread / removeParticipant / listParticipants, each fail-closed via OPA (kernel stays generic — no dm/group branching) - dev OPA: iios.thread.update + iios.thread.participant.remove rules (group requires ADMIN; ungoverned threads unchanged) - REST: PATCH /v1/threads/:id, GET + DELETE /v1/threads/:id/participants - tests: admin renames/removes, member is denied, member list carries roles (message.spec + dev-opa.port.spec) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,10 +3,12 @@ import {
|
||||
BadRequestException,
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Headers,
|
||||
HttpCode,
|
||||
Param,
|
||||
Patch,
|
||||
Post,
|
||||
Query,
|
||||
UseGuards,
|
||||
@@ -56,6 +58,27 @@ export class ThreadsController {
|
||||
return this.messages.addParticipant(id, this.principal(auth), body.userId, body.role);
|
||||
}
|
||||
|
||||
/** Members of a thread with their role — drives the group settings member list. */
|
||||
@Get(':id/participants')
|
||||
async listParticipants(@Param('id') id: string, @Headers('authorization') auth?: string) {
|
||||
return this.messages.listParticipants(id, this.principal(auth));
|
||||
}
|
||||
|
||||
/** Governed removal: remove a user from a thread — policy enforces group-admin. */
|
||||
@Delete(':id/participants/:userId')
|
||||
@HttpCode(200)
|
||||
async removeParticipant(@Param('id') id: string, @Param('userId') userId: string, @Headers('authorization') auth?: string) {
|
||||
return this.messages.removeParticipant(id, this.principal(auth), userId);
|
||||
}
|
||||
|
||||
/** Governed rename (group settings): change a thread subject — policy enforces group-admin. */
|
||||
@Patch(':id')
|
||||
@HttpCode(200)
|
||||
async updateThread(@Param('id') id: string, @Body() body: { subject?: string }, @Headers('authorization') auth?: string) {
|
||||
if (body?.subject == null) throw new BadRequestException('subject is required');
|
||||
return this.messages.renameThread(id, this.principal(auth), body.subject);
|
||||
}
|
||||
|
||||
@Get(':id/messages')
|
||||
async listMessages(@Param('id') id: string) {
|
||||
return this.threads.getMessages(id);
|
||||
|
||||
Reference in New Issue
Block a user