Files
GPI/src/server/controllers/messageController.ts
2026-03-17 07:34:09 -03:00

198 lines
7.4 KiB
TypeScript

import { Request, Response } from 'express';
import { query } from '../config/database.js';
// Send a message
export const sendMessage = async (req: Request, res: Response) => {
try {
const { toUserId, message } = req.body;
const fromUserId = req.appUser?.externalId;
const organizationId = req.headers['x-organization-id'] as string;
if (!organizationId) {
return res.status(400).json({ error: 'Organização não selecionada.' });
}
if (!fromUserId) {
return res.status(401).json({ error: 'Usuário não autenticado.' });
}
if (!toUserId || !message) {
return res.status(400).json({ error: 'Destinatário e mensagem são obrigatórios.' });
}
// Check if there's already a pending (unread) message from this user to that user
const existingRes = await query(
'SELECT * FROM gpi.messages WHERE organization_id = $1 AND from_user_id = $2 AND to_user_id = $3 AND is_read = false',
[organizationId, fromUserId, toUserId]
);
if (existingRes.rows.length > 0) {
const updatedRes = await query(
'UPDATE gpi.messages SET message = $1, updated_at = NOW() WHERE id = $2 RETURNING *',
[message, existingRes.rows[0].id]
);
return res.json(updatedRes.rows[0]);
}
const insertRes = await query(
`INSERT INTO gpi.messages (organization_id, from_user_id, to_user_id, message)
VALUES ($1, $2, $3, $4) RETURNING *`,
[organizationId, fromUserId, toUserId, message]
);
res.status(201).json(insertRes.rows[0]);
} catch (error) {
console.error('Error sending message:', error);
res.status(500).json({ error: 'Erro ao enviar mensagem.' });
}
};
// Get unread messages for current user
export const getUnreadMessages = async (req: Request, res: Response) => {
try {
const toUserId = req.appUser?.externalId;
const organizationId = req.headers['x-organization-id'] as string;
if (!organizationId || !toUserId) {
return res.status(400).json({ error: 'Contexto incompleto.' });
}
const sql = `
SELECT m.*, u.name as "fromUserName", u.email as "fromUserEmail"
FROM gpi.messages m
LEFT JOIN gpi.users u ON m.from_user_id = u.clerk_id OR m.from_user_id = u.logto_id
WHERE m.organization_id = $1 AND m.to_user_id = $2 AND m.is_read = false AND m.is_archived = false AND m.is_deleted_by_recipient = false
ORDER BY m.created_at DESC
`;
const result = await query(sql, [organizationId, toUserId]);
const messages = result.rows.map(m => ({
...m,
fromUser: { name: m.fromUserName, email: m.fromUserEmail }
}));
res.json(messages);
} catch (error) {
console.error('Error getting unread messages:', error);
res.status(500).json({ error: 'Erro ao buscar mensagens.' });
}
};
// Mark message as read
export const markMessageAsRead = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const userId = req.appUser?.externalId;
const organizationId = req.headers['x-organization-id'] as string;
const result = await query(
'UPDATE gpi.messages SET is_read = true, read_at = NOW() WHERE id = $1 AND organization_id = $2 AND to_user_id = $3 RETURNING *',
[id, organizationId, userId]
);
if (result.rows.length === 0) {
return res.status(404).json({ error: 'Mensagem não encontrada.' });
}
res.json(result.rows[0]);
} catch (error) {
console.error('Error marking message as read:', error);
res.status(500).json({ error: 'Erro ao marcar mensagem como lida.' });
}
};
// Get my pending (unread) sent messages
export const getMyPendingMessages = async (req: Request, res: Response) => {
try {
const fromUserId = req.appUser?.externalId;
const organizationId = req.headers['x-organization-id'] as string;
if (!organizationId || !fromUserId) {
return res.status(400).json({ error: 'Contexto incompleto.' });
}
const sql = `
SELECT m.*, u.name as "toUserName", u.email as "toUserEmail"
FROM gpi.messages m
LEFT JOIN gpi.users u ON m.to_user_id = u.clerk_id OR m.to_user_id = u.logto_id
WHERE m.organization_id = $1 AND m.from_user_id = $2 AND m.is_read = false
ORDER BY m.created_at DESC
`;
const result = await query(sql, [organizationId, fromUserId]);
const messages = result.rows.map(m => ({
...m,
toUser: { name: m.toUserName, email: m.toUserEmail }
}));
res.json(messages);
} catch (error) {
console.error('Error getting pending messages:', error);
res.status(500).json({ error: 'Erro ao buscar mensagens pendentes.' });
}
};
// Delete a message (only if unread and sender is the current user)
export const deleteMessage = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const userId = req.appUser?.externalId;
const organizationId = req.headers['x-organization-id'] as string;
const result = await query(
'DELETE FROM gpi.messages WHERE id = $1 AND from_user_id = $2 AND organization_id = $3 AND is_read = false',
[id, userId, organizationId]
);
if (result.rowCount === 0) {
return res.status(404).json({ error: 'Mensagem não encontrada ou já lida.' });
}
res.json({ message: 'Mensagem deletada com sucesso.' });
} catch (error) {
console.error('Error deleting message:', error);
res.status(500).json({ error: 'Erro ao deletar mensagem.' });
}
};
// Recipient archives a message
export const archiveMessage = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const userId = req.appUser?.externalId;
const organizationId = req.headers['x-organization-id'] as string;
const result = await query(
'UPDATE gpi.messages SET is_archived = true, is_read = true WHERE id = $1 AND to_user_id = $2 AND organization_id = $3 RETURNING *',
[id, userId, organizationId]
);
if (result.rows.length === 0) return res.status(404).json({ error: 'Mensagem não encontrada.' });
res.json(result.rows[0]);
} catch (error) {
console.error('Error archiving message:', error);
res.status(500).json({ error: 'Erro ao arquivar mensagem.' });
}
};
export const recipientDeleteMessage = async (req: Request, res: Response) => {
try {
const { id } = req.params;
const userId = req.appUser?.externalId;
const organizationId = req.headers['x-organization-id'] as string;
const result = await query(
'UPDATE gpi.messages SET is_deleted_by_recipient = true WHERE id = $1 AND to_user_id = $2 AND organization_id = $3 RETURNING *',
[id, userId, organizationId]
);
if (result.rows.length === 0) return res.status(404).json({ error: 'Mensagem não encontrada.' });
res.json({ message: 'Mensagem excluída com sucesso.' });
} catch (error) {
console.error('Error deleting message:', error);
res.status(500).json({ error: 'Erro ao excluir mensagem.' });
}
};