Spaces:
Runtime error
Runtime error
| import { Controller, Get, Post, Put, Delete, Param, Body, HttpCode, HttpStatus } from '@nestjs/common'; | |
| import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger'; | |
| import { GroupService } from './group.service'; | |
| import { | |
| CreateGroupDto, | |
| ParticipantsDto, | |
| GroupSubjectDto, | |
| GroupDescriptionDto, | |
| JoinGroupDto, | |
| GroupSettingsDto, | |
| } from './dto/group.dto'; | |
| import { RequireRole } from '../auth/decorators/auth.decorators'; | |
| import { ApiKeyRole } from '../auth/entities/api-key.entity'; | |
| // NOTE: the session→groups LIST lives on the SessionController at GET /sessions/:id/groups (it | |
| // registered first and owns the canonical narrow projection). A bare @Get() here would collide on | |
| // the same path pattern (/sessions/{x}/groups) and be shadowed, so this controller owns only the | |
| // group sub-resource routes (:groupId/...) under the same mount. | |
| ('groups') | |
| ('sessions/:sessionId/groups') | |
| export class GroupController { | |
| constructor(private readonly groupService: GroupService) {} | |
| (':groupId') | |
| ({ summary: 'Get detailed group info' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID (e.g., 120363xxx@g.us)' }) | |
| ({ status: 200, description: 'Group details with participants' }) | |
| ({ status: 404, description: 'Group not found' }) | |
| async findOne(('sessionId') sessionId: string, ('groupId') groupId: string) { | |
| return this.groupService.getGroupInfo(sessionId, groupId); | |
| } | |
| ('join') | |
| (ApiKeyRole.OPERATOR) | |
| (HttpStatus.OK) | |
| ({ summary: 'Join a group via invite code' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ type: JoinGroupDto }) | |
| ({ status: 200, description: 'Joined the group' }) | |
| ({ status: 400, description: 'Invalid or expired invite code, or session is not started' }) | |
| async join(('sessionId') sessionId: string, () dto: JoinGroupDto) { | |
| const groupId = await this.groupService.joinGroupViaInviteCode(sessionId, dto.inviteCode); | |
| return { success: true, groupId }; | |
| } | |
| (':groupId/settings') | |
| ({ summary: 'Get group settings (announce / locked / ephemeral timer)' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ status: 200, description: 'Group settings' }) | |
| ({ status: 404, description: 'Group not found' }) | |
| async getSettings(('sessionId') sessionId: string, ('groupId') groupId: string) { | |
| return this.groupService.getGroupSettings(sessionId, groupId); | |
| } | |
| (':groupId/settings') | |
| (ApiKeyRole.OPERATOR) | |
| ({ summary: 'Update group settings (announce / locked / ephemeral timer)' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ type: GroupSettingsDto }) | |
| ({ status: 200, description: 'Group settings updated' }) | |
| ({ status: 400, description: 'No setting provided, or a value is not a boolean' }) | |
| ({ status: 403, description: 'The engine refused the change (the account is not a group admin)' }) | |
| ({ status: 404, description: 'Group not found' }) | |
| ({ status: 501, description: 'The active engine does not support a requested setting' }) | |
| async updateSettings( | |
| ('sessionId') sessionId: string, | |
| ('groupId') groupId: string, | |
| () dto: GroupSettingsDto, | |
| ) { | |
| await this.groupService.updateGroupSettings(sessionId, groupId, dto); | |
| return { success: true, message: 'Group settings updated' }; | |
| } | |
| () | |
| (ApiKeyRole.OPERATOR) | |
| ({ summary: 'Create a new group' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ type: CreateGroupDto }) | |
| ({ status: 201, description: 'Group created' }) | |
| async create(('sessionId') sessionId: string, () dto: CreateGroupDto) { | |
| return this.groupService.createGroup(sessionId, dto.name, dto.participants); | |
| } | |
| (':groupId/participants') | |
| (ApiKeyRole.OPERATOR) | |
| ({ summary: 'Add participants to a group' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ type: ParticipantsDto }) | |
| ({ status: 200, description: 'Participants added' }) | |
| (HttpStatus.OK) | |
| async addParticipants( | |
| ('sessionId') sessionId: string, | |
| ('groupId') groupId: string, | |
| () dto: ParticipantsDto, | |
| ) { | |
| await this.groupService.addParticipants(sessionId, groupId, dto.participants); | |
| return { success: true, message: 'Participants added' }; | |
| } | |
| (':groupId/participants') | |
| (ApiKeyRole.OPERATOR) | |
| ({ summary: 'Remove participants from a group' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ type: ParticipantsDto }) | |
| ({ status: 200, description: 'Participants removed' }) | |
| async removeParticipants( | |
| ('sessionId') sessionId: string, | |
| ('groupId') groupId: string, | |
| () dto: ParticipantsDto, | |
| ) { | |
| await this.groupService.removeParticipants(sessionId, groupId, dto.participants); | |
| return { success: true, message: 'Participants removed' }; | |
| } | |
| (':groupId/participants/promote') | |
| (ApiKeyRole.OPERATOR) | |
| ({ summary: 'Promote participants to admin' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ type: ParticipantsDto }) | |
| ({ status: 200, description: 'Participants promoted' }) | |
| (HttpStatus.OK) | |
| async promoteParticipants( | |
| ('sessionId') sessionId: string, | |
| ('groupId') groupId: string, | |
| () dto: ParticipantsDto, | |
| ) { | |
| await this.groupService.promoteParticipants(sessionId, groupId, dto.participants); | |
| return { success: true, message: 'Participants promoted to admin' }; | |
| } | |
| (':groupId/participants/demote') | |
| (ApiKeyRole.OPERATOR) | |
| ({ summary: 'Demote participants from admin' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ type: ParticipantsDto }) | |
| ({ status: 200, description: 'Participants demoted' }) | |
| (HttpStatus.OK) | |
| async demoteParticipants( | |
| ('sessionId') sessionId: string, | |
| ('groupId') groupId: string, | |
| () dto: ParticipantsDto, | |
| ) { | |
| await this.groupService.demoteParticipants(sessionId, groupId, dto.participants); | |
| return { success: true, message: 'Participants demoted from admin' }; | |
| } | |
| (':groupId/subject') | |
| (ApiKeyRole.OPERATOR) | |
| ({ summary: 'Change group name/subject' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ type: GroupSubjectDto }) | |
| ({ status: 200, description: 'Subject updated' }) | |
| async setSubject( | |
| ('sessionId') sessionId: string, | |
| ('groupId') groupId: string, | |
| () dto: GroupSubjectDto, | |
| ) { | |
| await this.groupService.setGroupSubject(sessionId, groupId, dto.subject); | |
| return { success: true, message: 'Group subject updated' }; | |
| } | |
| (':groupId/description') | |
| (ApiKeyRole.OPERATOR) | |
| ({ summary: 'Change group description' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ type: GroupDescriptionDto }) | |
| ({ status: 200, description: 'Description updated' }) | |
| async setDescription( | |
| ('sessionId') sessionId: string, | |
| ('groupId') groupId: string, | |
| () dto: GroupDescriptionDto, | |
| ) { | |
| await this.groupService.setGroupDescription(sessionId, groupId, dto.description); | |
| return { success: true, message: 'Group description updated' }; | |
| } | |
| (':groupId/leave') | |
| (ApiKeyRole.OPERATOR) | |
| ({ summary: 'Leave a group' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ status: 200, description: 'Left the group' }) | |
| (HttpStatus.OK) | |
| async leave(('sessionId') sessionId: string, ('groupId') groupId: string) { | |
| await this.groupService.leaveGroup(sessionId, groupId); | |
| return { success: true, message: 'Left the group' }; | |
| } | |
| // ========== Gap Quick Wins: Invite Link ========== | |
| (':groupId/invite-code') | |
| ({ summary: 'Get group invite code/link' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ status: 200, description: 'Group invite code' }) | |
| async getInviteCode(('sessionId') sessionId: string, ('groupId') groupId: string) { | |
| const inviteCode = await this.groupService.getGroupInviteCode(sessionId, groupId); | |
| return { | |
| inviteCode, | |
| inviteLink: `https://chat.whatsapp.com/${inviteCode}`, | |
| }; | |
| } | |
| (':groupId/invite-code/revoke') | |
| (ApiKeyRole.OPERATOR) | |
| (HttpStatus.OK) | |
| ({ summary: 'Revoke group invite code and generate new one' }) | |
| ({ name: 'sessionId', description: 'Session ID' }) | |
| ({ name: 'groupId', description: 'Group ID' }) | |
| ({ status: 200, description: 'New invite code generated' }) | |
| async revokeInviteCode(('sessionId') sessionId: string, ('groupId') groupId: string) { | |
| const newCode = await this.groupService.revokeGroupInviteCode(sessionId, groupId); | |
| return { | |
| inviteCode: newCode, | |
| inviteLink: `https://chat.whatsapp.com/${newCode}`, | |
| message: 'Invite code revoked and new one generated', | |
| }; | |
| } | |
| } | |