2026-03-30 18:05:54 +09:00
|
|
|
import { Request, Response } from 'express';
|
|
|
|
|
import { messengerService } from '../services/messengerService';
|
|
|
|
|
import { AuthenticatedRequest } from '../types/auth';
|
2026-03-30 18:41:13 +09:00
|
|
|
import { getIo } from '../socket/socketManager';
|
2026-03-30 18:05:54 +09:00
|
|
|
import path from 'path';
|
|
|
|
|
|
|
|
|
|
class MessengerController {
|
|
|
|
|
async getRooms(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const user = (req as AuthenticatedRequest).user!;
|
|
|
|
|
const rooms = await messengerService.getRooms(user.userId, user.companyCode!);
|
|
|
|
|
res.json({ success: true, data: rooms });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('getRooms error:', err.message);
|
|
|
|
|
res.status(500).json({ success: false, message: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async createRoom(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const user = (req as AuthenticatedRequest).user!;
|
|
|
|
|
const room_type = req.body.room_type ?? req.body.type;
|
|
|
|
|
const room_name = req.body.room_name ?? req.body.name;
|
|
|
|
|
const participant_ids = req.body.participant_ids ?? req.body.participantIds;
|
|
|
|
|
|
|
|
|
|
if (!room_type || !participant_ids || !Array.isArray(participant_ids)) {
|
|
|
|
|
return res.status(400).json({ success: false, message: 'room_type and participant_ids are required.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const room = await messengerService.createRoom(user.userId, user.companyCode!, {
|
|
|
|
|
room_type,
|
|
|
|
|
room_name,
|
|
|
|
|
participant_ids,
|
|
|
|
|
});
|
|
|
|
|
res.json({ success: true, data: room });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('createRoom error:', err.message);
|
|
|
|
|
res.status(500).json({ success: false, message: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getMessages(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const user = (req as AuthenticatedRequest).user!;
|
|
|
|
|
const roomId = parseInt(req.params.roomId, 10);
|
|
|
|
|
const limit = parseInt(req.query.limit as string, 10) || 50;
|
|
|
|
|
const before = req.query.before ? parseInt(req.query.before as string, 10) : undefined;
|
|
|
|
|
|
|
|
|
|
const messages = await messengerService.getMessages(roomId, user.userId, user.companyCode!, limit, before);
|
|
|
|
|
res.json({ success: true, data: messages });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('getMessages error:', err.message);
|
|
|
|
|
res.status(500).json({ success: false, message: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async sendMessage(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const user = (req as AuthenticatedRequest).user!;
|
|
|
|
|
const roomId = parseInt(req.params.roomId, 10);
|
|
|
|
|
const content = req.body.content;
|
|
|
|
|
const messageType = req.body.type ?? req.body.message_type ?? 'text';
|
|
|
|
|
const parentId = req.body.parentId ?? req.body.parent_message_id ?? null;
|
|
|
|
|
|
|
|
|
|
if (!content) {
|
|
|
|
|
return res.status(400).json({ success: false, message: 'content is required.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const message = await messengerService.sendMessage(roomId, user.userId, user.companyCode!, content, messageType, parentId);
|
2026-03-30 18:41:13 +09:00
|
|
|
|
|
|
|
|
// Broadcast to all room participants via Socket.IO
|
|
|
|
|
const io = getIo();
|
|
|
|
|
if (io) {
|
|
|
|
|
io.to(`${user.companyCode}:${roomId}`).emit('new_message', message);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 18:05:54 +09:00
|
|
|
res.json({ success: true, data: message });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('sendMessage error:', err.message);
|
|
|
|
|
res.status(500).json({ success: false, message: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async markAsRead(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const user = (req as AuthenticatedRequest).user!;
|
|
|
|
|
const roomId = parseInt(req.params.roomId, 10);
|
|
|
|
|
await messengerService.markAsRead(roomId, user.userId);
|
|
|
|
|
res.json({ success: true });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('markAsRead error:', err.message);
|
|
|
|
|
res.status(500).json({ success: false, message: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async uploadFile(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const user = (req as AuthenticatedRequest).user!;
|
|
|
|
|
const files = req.files as Express.Multer.File[];
|
|
|
|
|
|
|
|
|
|
if (!files || files.length === 0) {
|
|
|
|
|
return res.status(400).json({ success: false, message: 'No files uploaded.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const roomId = parseInt(req.body.room_id, 10);
|
|
|
|
|
if (!roomId) {
|
|
|
|
|
return res.status(400).json({ success: false, message: 'room_id is required.' });
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 12:13:00 +09:00
|
|
|
const io = getIo();
|
2026-03-30 18:05:54 +09:00
|
|
|
const savedFiles = [];
|
|
|
|
|
for (const file of files) {
|
2026-04-01 12:13:00 +09:00
|
|
|
// Use a readable placeholder as content to avoid filename encoding issues
|
|
|
|
|
const isImage = file.mimetype.startsWith('image/');
|
|
|
|
|
const content = isImage ? '[이미지]' : '[파일]';
|
|
|
|
|
|
2026-03-30 18:05:54 +09:00
|
|
|
// Create a file message
|
|
|
|
|
const message = await messengerService.sendMessage(
|
|
|
|
|
roomId,
|
|
|
|
|
user.userId,
|
|
|
|
|
user.companyCode!,
|
2026-04-01 12:13:00 +09:00
|
|
|
content,
|
2026-03-30 18:05:54 +09:00
|
|
|
'file'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const savedFile = await messengerService.saveFile(message.id, {
|
|
|
|
|
originalName: file.originalname,
|
|
|
|
|
storedName: file.filename,
|
|
|
|
|
filePath: file.path,
|
|
|
|
|
fileSize: file.size,
|
|
|
|
|
mimeType: file.mimetype,
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-01 12:13:00 +09:00
|
|
|
message.files = [savedFile];
|
|
|
|
|
|
|
|
|
|
// Broadcast to room so recipients receive it in real-time
|
|
|
|
|
io.to(`${user.companyCode}:${roomId}`).emit('new_message', message);
|
|
|
|
|
|
2026-03-30 18:05:54 +09:00
|
|
|
savedFiles.push({ message, file: savedFile });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.json({ success: true, data: savedFiles });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('uploadFile error:', err.message);
|
|
|
|
|
res.status(500).json({ success: false, message: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async downloadFile(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const fileId = parseInt(req.params.fileId, 10);
|
|
|
|
|
const file = await messengerService.getFileById(fileId);
|
|
|
|
|
|
|
|
|
|
if (!file) {
|
|
|
|
|
return res.status(404).json({ success: false, message: 'File not found.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.download(file.file_path, file.original_name);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('downloadFile error:', err.message);
|
|
|
|
|
res.status(500).json({ success: false, message: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getCompanyUsers(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const user = (req as AuthenticatedRequest).user!;
|
|
|
|
|
const users = await messengerService.getCompanyUsers(user.companyCode!, user.userId);
|
|
|
|
|
res.json({ success: true, data: users });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('getCompanyUsers error:', err.message);
|
|
|
|
|
res.status(500).json({ success: false, message: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async updateRoom(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const user = (req as AuthenticatedRequest).user!;
|
|
|
|
|
const roomId = parseInt(req.params.roomId, 10);
|
|
|
|
|
const { room_name } = req.body;
|
|
|
|
|
|
|
|
|
|
if (!room_name) {
|
|
|
|
|
return res.status(400).json({ success: false, message: 'room_name is required.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const room = await messengerService.updateRoom(roomId, user.companyCode!, room_name);
|
|
|
|
|
if (!room) {
|
|
|
|
|
return res.status(404).json({ success: false, message: 'Room not found.' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.json({ success: true, data: room });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('updateRoom error:', err.message);
|
|
|
|
|
res.status(500).json({ success: false, message: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getUnreadCount(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const user = (req as AuthenticatedRequest).user!;
|
|
|
|
|
const count = await messengerService.getUnreadCount(user.userId, user.companyCode!);
|
|
|
|
|
res.json({ success: true, data: { unread_count: count } });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error as Error;
|
|
|
|
|
console.error('getUnreadCount error:', err.message);
|
|
|
|
|
res.status(500).json({ success: false, message: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const messengerController = new MessengerController();
|