259 lines
12 KiB
Java
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;
|
|
}
|
|
}
|