Spaces:
Sleeping
Sleeping
| import { | |
| Controller, | |
| Get, | |
| Post, | |
| Patch, | |
| Delete, | |
| Body, | |
| Param, | |
| Query, | |
| Req, | |
| UseGuards, | |
| ParseIntPipe, | |
| HttpCode, | |
| HttpStatus, | |
| } from '@nestjs/common'; | |
| import { | |
| ApiTags, | |
| ApiOperation, | |
| ApiParam, | |
| ApiBody, | |
| ApiResponse, | |
| ApiBearerAuth, | |
| } from '@nestjs/swagger'; | |
| import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard'; | |
| import { RolesGuard } from '../../auth/guards/roles.guard'; | |
| import { MessagingService } from '../services/messaging.service'; | |
| import { | |
| StartConversationDto, | |
| SendMessageDto, | |
| MessageQueryDto, | |
| SearchMessagesDto, | |
| EditMessageDto, | |
| SearchUsersDto, | |
| } from '../dto'; | |
| ('💬 Messaging') | |
| ('JWT-auth') | |
| ('api/messages') | |
| (JwtAuthGuard, RolesGuard) | |
| export class MessagingController { | |
| constructor(private readonly messagingService: MessagingService) {} | |
| ('users/search') | |
| ({ | |
| summary: 'Search users', | |
| description: 'Search for users by name or email. Available to all authenticated users. Useful for starting new conversations.', | |
| }) | |
| ({ status: 200, description: 'Matching users' }) | |
| async searchUsers(() dto: SearchUsersDto) { | |
| return this.messagingService.searchUsers(dto.query, dto.limit); | |
| } | |
| ('conversations') | |
| ({ | |
| summary: 'List conversations', | |
| description: 'List all conversations for the current user. Returns last message, unread count, and participants for each conversation.', | |
| }) | |
| ({ status: 200, description: 'Conversations retrieved' }) | |
| async listConversations(() req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.messagingService.listConversations(userId); | |
| } | |
| ('conversations') | |
| (HttpStatus.CREATED) | |
| ({ | |
| summary: 'Start new conversation', | |
| description: 'Start a new direct or group conversation. For direct messages, if a conversation already exists with the same user, the message is sent there instead.', | |
| }) | |
| ({ type: StartConversationDto }) | |
| ({ status: 201, description: 'Conversation created or message sent to existing' }) | |
| async startConversation(() dto: StartConversationDto, () req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.messagingService.startConversation(userId, dto); | |
| } | |
| ('conversations/:id') | |
| ({ | |
| summary: 'Get conversation messages', | |
| description: 'Get paginated messages in a conversation. Messages deleted for the current user are excluded. Deleted-for-everyone messages show "This message was deleted".', | |
| }) | |
| ({ name: 'id', description: 'Conversation (root message) ID', example: 1 }) | |
| ({ status: 200, description: 'Messages retrieved' }) | |
| async getConversationMessages( | |
| ('id', ParseIntPipe) id: number, | |
| () query: MessageQueryDto, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.messagingService.getConversationMessages(id, userId, query); | |
| } | |
| ('conversations/:id') | |
| (HttpStatus.CREATED) | |
| ({ | |
| summary: 'Send message in conversation', | |
| description: 'Send a message in an existing conversation. Supports text and optional file attachment. Message is delivered in real-time via WebSocket to all participants.', | |
| }) | |
| ({ name: 'id', description: 'Conversation ID', example: 1 }) | |
| ({ type: SendMessageDto }) | |
| ({ status: 201, description: 'Message sent' }) | |
| async sendMessage( | |
| ('id', ParseIntPipe) id: number, | |
| () dto: SendMessageDto, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.messagingService.sendMessage(id, userId, dto); | |
| } | |
| (':id') | |
| ({ | |
| summary: 'Edit message', | |
| description: 'Edit the text of a message. Only the original sender can edit. Updates the editedAt timestamp.', | |
| }) | |
| ({ name: 'id', description: 'Message ID', example: 1 }) | |
| ({ type: EditMessageDto }) | |
| ({ status: 200, description: 'Message edited' }) | |
| ({ status: 403, description: 'Only the sender can edit' }) | |
| async editMessage( | |
| ('id', ParseIntPipe) id: number, | |
| () dto: EditMessageDto, | |
| () req: any, | |
| ) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.messagingService.editMessage(id, userId, dto.text); | |
| } | |
| (':id/read') | |
| ({ | |
| summary: 'Mark message as read', | |
| description: 'Mark a single message as read. Updates the read receipt timestamp.', | |
| }) | |
| ({ name: 'id', description: 'Message ID', example: 1 }) | |
| ({ status: 200, description: 'Message marked as read' }) | |
| async markAsRead(('id', ParseIntPipe) id: number, () req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.messagingService.markAsRead(id, userId); | |
| } | |
| (':id') | |
| ({ | |
| summary: 'Delete message for me', | |
| description: 'Soft-delete a message for the current user only. Other participants can still see it.', | |
| }) | |
| ({ name: 'id', description: 'Message ID', example: 1 }) | |
| ({ status: 200, description: 'Message deleted for you' }) | |
| async deleteForMe(('id', ParseIntPipe) id: number, () req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.messagingService.deleteForMe(id, userId); | |
| } | |
| (':id/everyone') | |
| ({ | |
| summary: 'Delete message for everyone', | |
| description: 'Delete a message for all participants (WhatsApp-style). Only the original sender can do this. Shows "This message was deleted" for all.', | |
| }) | |
| ({ name: 'id', description: 'Message ID', example: 1 }) | |
| ({ status: 200, description: 'Message deleted for everyone' }) | |
| ({ status: 403, description: 'Only the sender can delete for everyone' }) | |
| async deleteForEveryone(('id', ParseIntPipe) id: number, () req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.messagingService.deleteForEveryone(id, userId); | |
| } | |
| ('unread-count') | |
| ({ | |
| summary: 'Get unread message count', | |
| description: 'Get total count of unread messages across all conversations.', | |
| }) | |
| ({ status: 200, description: 'Unread count', schema: { example: { count: 5 } } }) | |
| async getUnreadCount(() req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.messagingService.getUnreadCount(userId); | |
| } | |
| ('search') | |
| ({ | |
| summary: 'Search messages', | |
| description: 'Search through all messages the user has access to. Returns matching messages with conversation context.', | |
| }) | |
| ({ status: 200, description: 'Search results' }) | |
| async searchMessages(() dto: SearchMessagesDto, () req: any) { | |
| const userId = req.user.userId || req.user.id; | |
| return this.messagingService.searchMessages(userId, dto); | |
| } | |
| ('online-users') | |
| ({ | |
| summary: 'Get online users', | |
| description: 'Get list of currently online user IDs (connected via WebSocket).', | |
| }) | |
| ({ status: 200, description: 'Online user IDs', schema: { example: { onlineUserIds: [57, 58] } } }) | |
| async getOnlineUsers() { | |
| return { onlineUserIds: this.messagingService.getOnlineUserIds() }; | |
| } | |
| } | |