2026-04-05 22:22:00 +00:00

259 lines
12 KiB
Java

package com.rjlresaka.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import com.rjlresaka.model.Message;
import com.rjlresaka.model.ReactionStat;
import com.rjlresaka.util.DatabaseConnection;
public class MessageDAO {
private final ConversationDAO conversationDAO = new ConversationDAO();
public List<Message> findMessagesBetweenUsers(int currentUserId, int otherUserId, ServletContext context)
throws SQLException, ClassNotFoundException {
Integer conversationId = conversationDAO.findConversationIdBetweenUsers(currentUserId, otherUserId, context);
if (conversationId == null) {
return new ArrayList<Message>();
}
return findMessagesByConversation(conversationId.intValue(), currentUserId, context);
}
public List<Message> findMessagesByConversation(int conversationId, int currentUserId, ServletContext context)
throws SQLException, ClassNotFoundException {
String sql = "SELECT m.*, u.full_name, u.avatar_color "
+ "FROM messages m "
+ "INNER JOIN users u ON u.id = m.sender_id "
+ "INNER JOIN conversation_participants cp ON cp.conversation_id = m.conversation_id AND cp.user_id = ? "
+ "WHERE m.conversation_id = ? "
+ "ORDER BY m.created_at ASC, m.id ASC";
List<Message> messages = new ArrayList<Message>();
try (Connection connection = DatabaseConnection.getConnection(context);
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setInt(1, currentUserId);
statement.setInt(2, conversationId);
try (ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
Message message = mapMessage(rs, currentUserId);
message.getReactions().addAll(findReactions(message.getId(), currentUserId, context));
messages.add(message);
}
}
}
return messages;
}
public int createMessage(int senderId, int receiverId, Message draft, ServletContext context)
throws SQLException, ClassNotFoundException {
int conversationId = conversationDAO.findOrCreateConversationId(senderId, receiverId, context);
createMessageInConversation(senderId, conversationId, draft, context);
return conversationId;
}
public void createMessageInConversation(int senderId, int conversationId, Message draft, ServletContext context)
throws SQLException, ClassNotFoundException {
String sql = "INSERT INTO messages (conversation_id, sender_id, body, attachment_name, attachment_path, attachment_type, attachment_size) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?)";
String updateConversation = "UPDATE conversations SET updated_at = NOW() WHERE id = ?";
try (Connection connection = DatabaseConnection.getConnection(context)) {
connection.setAutoCommit(false);
try {
if (!hasAccess(connection, conversationId, senderId)) {
throw new SQLException("Accès refusé à cette conversation.");
}
try (PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setInt(1, conversationId);
statement.setInt(2, senderId);
statement.setString(3, cleanText(draft.getBody()));
statement.setString(4, emptyToNull(draft.getAttachmentName()));
statement.setString(5, emptyToNull(draft.getAttachmentPath()));
statement.setString(6, emptyToNull(draft.getAttachmentType()));
if (draft.getAttachmentSize() > 0) {
statement.setLong(7, draft.getAttachmentSize());
} else {
statement.setNull(7, java.sql.Types.BIGINT);
}
statement.executeUpdate();
}
try (PreparedStatement statement = connection.prepareStatement(updateConversation)) {
statement.setInt(1, conversationId);
statement.executeUpdate();
}
connection.commit();
} catch (SQLException exception) {
connection.rollback();
throw exception;
} finally {
connection.setAutoCommit(true);
}
}
}
public boolean updateMessage(int messageId, int senderId, String body, ServletContext context)
throws SQLException, ClassNotFoundException {
String sql = "UPDATE messages SET body = ?, is_edited = 1, updated_at = NOW() "
+ "WHERE id = ? AND sender_id = ? AND is_deleted = 0";
try (Connection connection = DatabaseConnection.getConnection(context);
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, cleanText(body));
statement.setInt(2, messageId);
statement.setInt(3, senderId);
return statement.executeUpdate() > 0;
}
}
public boolean deleteMessage(int messageId, int senderId, ServletContext context)
throws SQLException, ClassNotFoundException {
String sql = "UPDATE messages SET body = NULL, attachment_name = NULL, attachment_path = NULL, attachment_type = NULL, "
+ "attachment_size = NULL, is_deleted = 1, updated_at = NOW() WHERE id = ? AND sender_id = ?";
try (Connection connection = DatabaseConnection.getConnection(context);
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setInt(1, messageId);
statement.setInt(2, senderId);
return statement.executeUpdate() > 0;
}
}
public void toggleReaction(int messageId, int userId, String emoji, ServletContext context)
throws SQLException, ClassNotFoundException {
if (emoji == null || emoji.trim().isEmpty()) {
return;
}
String select = "SELECT id FROM message_reactions WHERE message_id = ? AND user_id = ? AND emoji = ? LIMIT 1";
String insert = "INSERT INTO message_reactions (message_id, user_id, emoji) VALUES (?, ?, ?)";
String delete = "DELETE FROM message_reactions WHERE id = ?";
try (Connection connection = DatabaseConnection.getConnection(context);
PreparedStatement selectStatement = connection.prepareStatement(select)) {
selectStatement.setInt(1, messageId);
selectStatement.setInt(2, userId);
selectStatement.setString(3, emoji);
try (ResultSet rs = selectStatement.executeQuery()) {
if (rs.next()) {
try (PreparedStatement deleteStatement = connection.prepareStatement(delete)) {
deleteStatement.setInt(1, rs.getInt("id"));
deleteStatement.executeUpdate();
}
} else {
try (PreparedStatement insertStatement = connection.prepareStatement(insert)) {
insertStatement.setInt(1, messageId);
insertStatement.setInt(2, userId);
insertStatement.setString(3, emoji);
insertStatement.executeUpdate();
}
}
}
}
}
public Message findAttachmentForDownload(int messageId, int currentUserId, ServletContext context)
throws SQLException, ClassNotFoundException {
String sql = "SELECT m.*, u.full_name, u.avatar_color "
+ "FROM messages m "
+ "INNER JOIN users u ON u.id = m.sender_id "
+ "INNER JOIN conversation_participants cp ON cp.conversation_id = m.conversation_id AND cp.user_id = ? "
+ "WHERE m.id = ? LIMIT 1";
try (Connection connection = DatabaseConnection.getConnection(context);
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setInt(1, currentUserId);
statement.setInt(2, messageId);
try (ResultSet rs = statement.executeQuery()) {
return rs.next() ? mapMessage(rs, currentUserId) : null;
}
}
}
private boolean hasAccess(Connection connection, int conversationId, int userId) throws SQLException {
String sql = "SELECT 1 FROM conversation_participants WHERE conversation_id = ? AND user_id = ? LIMIT 1";
try (PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setInt(1, conversationId);
statement.setInt(2, userId);
try (ResultSet rs = statement.executeQuery()) {
return rs.next();
}
}
}
private List<ReactionStat> findReactions(int messageId, int currentUserId, ServletContext context)
throws SQLException, ClassNotFoundException {
String sql = "SELECT emoji, COUNT(*) AS total, MAX(CASE WHEN user_id = ? THEN 1 ELSE 0 END) AS mine "
+ "FROM message_reactions WHERE message_id = ? GROUP BY emoji ORDER BY total DESC, emoji ASC";
List<ReactionStat> reactions = new ArrayList<ReactionStat>();
try (Connection connection = DatabaseConnection.getConnection(context);
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setInt(1, currentUserId);
statement.setInt(2, messageId);
try (ResultSet rs = statement.executeQuery()) {
while (rs.next()) {
ReactionStat stat = new ReactionStat();
stat.setEmoji(rs.getString("emoji"));
stat.setCount(rs.getInt("total"));
stat.setReactedByCurrentUser(rs.getInt("mine") == 1);
reactions.add(stat);
}
}
}
return reactions;
}
private Message mapMessage(ResultSet rs, int currentUserId) throws SQLException {
Message message = new Message();
message.setId(rs.getInt("id"));
message.setConversationId(rs.getInt("conversation_id"));
message.setSenderId(rs.getInt("sender_id"));
message.setSenderName(rs.getString("full_name"));
message.setSenderAvatarColor(rs.getString("avatar_color"));
message.setSenderInitials(initials(rs.getString("full_name")));
message.setBody(rs.getString("body"));
message.setAttachmentName(rs.getString("attachment_name"));
message.setAttachmentPath(rs.getString("attachment_path"));
message.setAttachmentType(rs.getString("attachment_type"));
message.setAttachmentSize(rs.getLong("attachment_size"));
message.setEdited(rs.getBoolean("is_edited"));
message.setDeleted(rs.getBoolean("is_deleted"));
message.setMine(rs.getInt("sender_id") == currentUserId);
message.setCreatedAt(rs.getTimestamp("created_at"));
message.setUpdatedAt(rs.getTimestamp("updated_at"));
return message;
}
private String initials(String fullName) {
if (fullName == null || fullName.trim().isEmpty()) {
return "RR";
}
String[] parts = fullName.trim().split("\\s+");
StringBuilder builder = new StringBuilder();
for (String part : parts) {
if (!part.isEmpty()) {
builder.append(Character.toUpperCase(part.charAt(0)));
}
if (builder.length() == 2) {
break;
}
}
return builder.length() == 0 ? "RR" : builder.toString();
}
private String cleanText(String body) {
if (body == null) {
return null;
}
String cleaned = body.trim();
return cleaned.isEmpty() ? null : cleaned;
}
private String emptyToNull(String value) {
if (value == null || value.trim().isEmpty()) {
return null;
}
return value;
}
}