Work on delete chat

This commit is contained in:
2025-08-01 20:59:59 +03:30
parent c6616863a1
commit 3cdbb7e24b
5 changed files with 242 additions and 12 deletions
@@ -1237,6 +1237,7 @@ public class ActionHandler {
return true; return true;
} }
private JSONObject getGroupPermissions(UUID groupId) { private JSONObject getGroupPermissions(UUID groupId) {
JSONObject req = new JSONObject(); JSONObject req = new JSONObject();
req.put("action", "get_group_permissions"); req.put("action", "get_group_permissions");
@@ -2013,7 +2014,7 @@ public class ActionHandler {
private void deleteChat(UUID targetId, boolean both) { private void deleteChat(UUID targetId, boolean both) {
JSONObject req = new JSONObject(); JSONObject req = new JSONObject();
req.put("action", "delete_private_chat"); req.put("action", "delete_private_chat");
req.put("target_id", targetId.toString()); req.put("chat_id", targetId.toString());
req.put("both", both); req.put("both", both);
send(req); send(req);
@@ -65,6 +65,54 @@ public class MessageDatabase {
} }
} }
public static void markGloballyDeleted(UUID chatId) {
String sql = "UPDATE messages SET deleted_globally = true WHERE receiver_id = ? AND receiver_type = 'private'";
try (Connection conn = ConnectionDb.connect(); PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, chatId);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void logDeletedMessagesFor(UUID chatId, UUID userId) {
List<Message> messages = MessageDatabase.privateChatHistory(chatId);
for (Message message : messages) {
if (!isMessageDeleted(message.getMessage_id(), userId)) {
String sql = """
INSERT INTO deleted_messages (message_id, user_id)
VALUES (?, ?)
ON CONFLICT (message_id, user_id) DO NOTHING
""";
try (Connection conn = ConnectionDb.connect();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, message.getMessage_id());
ps.setObject(2, userId);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public static boolean isMessageDeleted(UUID messageId, UUID userId) {
String sql = "SELECT 1 FROM deleted_messages WHERE message_id = ? AND user_id = ?";
try (Connection conn = ConnectionDb.connect();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, messageId);
ps.setObject(2, userId);
ResultSet rs = ps.executeQuery();
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
public void markMessageAsRead(UUID messageId, UUID userId) { public void markMessageAsRead(UUID messageId, UUID userId) {
String sql = "INSERT INTO message_receipts (message_id, user_id) VALUES (?, ?) ON CONFLICT DO NOTHING"; String sql = "INSERT INTO message_receipts (message_id, user_id) VALUES (?, ?) ON CONFLICT DO NOTHING";
try (Connection conn = ConnectionDb.connect(); try (Connection conn = ConnectionDb.connect();
@@ -2,10 +2,7 @@ package org.to.telegramfinalproject.Database;
import org.to.telegramfinalproject.Models.PrivateChat; import org.to.telegramfinalproject.Models.PrivateChat;
import java.sql.Connection; import java.sql.*;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -133,4 +130,129 @@ public class PrivateChatDatabase {
return null; return null;
} }
private static PrivateChat extractPrivateChat(ResultSet rs) throws SQLException {
UUID chatId = UUID.fromString(rs.getString("chat_id"));
UUID user1 = rs.getObject("user1_id", UUID.class);
UUID user2 = rs.getObject("user2_id", UUID.class);
boolean user1Deleted = rs.getBoolean("user1_deleted");
boolean user2Deleted = rs.getBoolean("user2_deleted");
LocalDateTime createdAt = rs.getTimestamp("created_at").toLocalDateTime();
return new PrivateChat(chatId, user1, user2, user1Deleted, user2Deleted, createdAt);
}
public static void markChatDeleted(UUID userId, UUID chatId) {
String sql = """
UPDATE private_chat
SET user1_deleted = CASE WHEN user1_id = ? THEN true ELSE user1_deleted END,
user2_deleted = CASE WHEN user2_id = ? THEN true ELSE user2_deleted END
WHERE chat_id = ?
""";
try (Connection conn = ConnectionDb.connect();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setObject(1, userId);
stmt.setObject(2, userId);
stmt.setObject(3, chatId);
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void unmarkChatDeleted(UUID userId, UUID chatId) {
String sql = """
UPDATE private_chat
SET user1_deleted = CASE WHEN user1_id = ? THEN false ELSE user1_deleted END,
user2_deleted = CASE WHEN user2_id = ? THEN false ELSE user2_deleted END
WHERE chat_id = ?
""";
try (Connection conn = ConnectionDb.connect();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setObject(1, userId);
stmt.setObject(2, userId);
stmt.setObject(3, chatId);
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void markUser1Deleted(UUID chatId) {
updateBoolField(chatId, "user1_deleted", true);
}
public static void markUser2Deleted(UUID chatId) {
updateBoolField(chatId, "user2_deleted", true);
}
public static void markBothDeleted(UUID chatId) {
String sql = "UPDATE private_chat SET user1_deleted = true, user2_deleted = true WHERE chat_id = ?";
try (Connection conn = ConnectionDb.connect(); PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, chatId);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
private static void updateBoolField(UUID chatId, String field, boolean value) {
String sql = "UPDATE private_chat SET " + field + " = ? WHERE chat_id = ?";
try (Connection conn = ConnectionDb.connect(); PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setBoolean(1, value);
ps.setObject(2, chatId);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static PrivateChat findById(UUID chatId) {
String sql = "SELECT * FROM private_chat WHERE chat_id = ?";
try (Connection conn = ConnectionDb.connect(); PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, chatId);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
UUID user1_id = (UUID) rs.getObject("user1_id");
UUID user2_id = (UUID) rs.getObject("user2_id");
boolean user1_deleted = rs.getBoolean("user1_deleted");
boolean user2_deleted = rs.getBoolean("user2_deleted");
LocalDateTime created_at = rs.getTimestamp("created_at").toLocalDateTime();
return new PrivateChat(chatId, user1_id, user2_id, user1_deleted, user2_deleted, created_at);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void clearDeletedFlag(UUID senderId, UUID receiverId) {
String sql = """
UPDATE private_chat
SET user1_deleted = CASE WHEN user1_id = ? THEN false ELSE user1_deleted END,
user2_deleted = CASE WHEN user2_id = ? THEN false ELSE user2_deleted END
WHERE (user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)
""";
try (Connection conn = ConnectionDb.connect(); PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, senderId);
ps.setObject(2, senderId);
ps.setObject(3, senderId);
ps.setObject(4, receiverId);
ps.setObject(5, receiverId);
ps.setObject(6, senderId);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
} }
@@ -5,6 +5,8 @@ import java.util.UUID;
public class PrivateChat { public class PrivateChat {
private final UUID chat_id; private final UUID chat_id;
private boolean user1_deleted;
private boolean user2_deleted;
private UUID user1_id; private UUID user1_id;
private UUID user2_id; private UUID user2_id;
private LocalDateTime created_at; private LocalDateTime created_at;
@@ -16,6 +18,16 @@ public class PrivateChat {
this.created_at =created_at; this.created_at =created_at;
} }
public PrivateChat(UUID chatId, UUID user1, UUID user2, boolean user1Deleted, boolean user2Deleted, LocalDateTime createdAt) {
this.chat_id = chatId;
this.user1_id = user1;
this.user2_id = user2;
this.user1_deleted = user1Deleted;
this.user2_deleted = user2Deleted;
this.created_at = createdAt;
}
public void setUser1_id(UUID user1_id){this.user1_id =user1_id;} public void setUser1_id(UUID user1_id){this.user1_id =user1_id;}
public void setUser2_id(UUID user2_id){this.user2_id =user2_id;} public void setUser2_id(UUID user2_id){this.user2_id =user2_id;}
public void setCreated_at(LocalDateTime created_at){this.created_at = created_at;} public void setCreated_at(LocalDateTime created_at){this.created_at = created_at;}
@@ -1432,26 +1432,33 @@ public class ClientHandler implements Runnable {
case "delete_private_chat" : { case "delete_private_chat": {
if (currentUser == null) { if (currentUser == null) {
response = new ResponseModel("error", "Unauthorized. Please login first."); response = new ResponseModel("error", "Unauthorized. Please login first.");
break; break;
} }
UUID targetId = UUID.fromString(requestJson.getString("target_id"));
// دریافت شناسه چت و نوع حذف (یک‌طرفه یا دوطرفه)
UUID targetId = UUID.fromString(requestJson.getString("chat_id"));
boolean both = requestJson.getBoolean("both"); boolean both = requestJson.getBoolean("both");
//RealTime // Real-Time Event Dispatch (اطلاع‌رسانی ریل تایم)
if (both) { if (both) {
// حذف دوطرفه
RealTimeEventDispatcher.notifyChatDeleted("private", targetId, List.of(currentUser.getInternal_uuid())); RealTimeEventDispatcher.notifyChatDeleted("private", targetId, List.of(currentUser.getInternal_uuid()));
RealTimeEventDispatcher.notifyChatDeleted("private", currentUser.getInternal_uuid(), List.of(targetId)); RealTimeEventDispatcher.notifyChatDeleted("private", currentUser.getInternal_uuid(), List.of(targetId));
} else { } else {
// حذف یک‌طرفه
RealTimeEventDispatcher.notifyChatDeleted("private", targetId, List.of(currentUser.getInternal_uuid())); RealTimeEventDispatcher.notifyChatDeleted("private", targetId, List.of(currentUser.getInternal_uuid()));
} }
response = PrivateChatService.deletePrivateChat(currentUser.getInternal_uuid(), targetId, both);
// فراخوانی متد حذف چت
response = handleDeleteChat(requestJson);
break; break;
} }
case "get_group_permissions": { case "get_group_permissions": {
if (currentUser == null) { if (currentUser == null) {
response = new ResponseModel("error", "Unauthorized. Please login first."); response = new ResponseModel("error", "Unauthorized. Please login first.");
@@ -2025,8 +2032,6 @@ public class ClientHandler implements Runnable {
default: default:
response = new ResponseModel("error", "Unknown action: " + action); response = new ResponseModel("error", "Unknown action: " + action);
} }
@@ -2085,6 +2090,7 @@ public class ClientHandler implements Runnable {
private ResponseModel handleSendMessage(JSONObject json) { private ResponseModel handleSendMessage(JSONObject json) {
try { try {
if (currentUser == null) if (currentUser == null)
return new ResponseModel("error", "Unauthorized. Please login first."); return new ResponseModel("error", "Unauthorized. Please login first.");
@@ -2093,9 +2099,13 @@ public class ClientHandler implements Runnable {
UUID senderId = currentUser.getInternal_uuid(); UUID senderId = currentUser.getInternal_uuid();
String receiverType = json.getString("receiver_type"); String receiverType = json.getString("receiver_type");
UUID receiverId; UUID receiverId;
receiverId = UUID.fromString(json.getString("receiver_id")); receiverId = UUID.fromString(json.getString("receiver_id"));
if(Objects.equals(receiverType, "private")){
PrivateChatDatabase.clearDeletedFlag(senderId, receiverId);
}
String content = json.optString("content", ""); String content = json.optString("content", "");
String messageType = json.optString("message_type", "TEXT"); String messageType = json.optString("message_type", "TEXT");
@@ -2165,5 +2175,42 @@ public class ClientHandler implements Runnable {
} }
private ResponseModel handleDeleteChat(JSONObject json) {
try {
if (currentUser == null)
return new ResponseModel("error", "Unauthorized");
UUID chatId = UUID.fromString(json.getString("chat_id"));
boolean bothSides = json.optBoolean("both_sides", false);
PrivateChat chat = PrivateChatDatabase.findById(chatId);
if (chat == null) return new ResponseModel("error", "Chat not found.");
UUID self = currentUser.getInternal_uuid();
UUID other = chat.getUser1_id().equals(self) ? chat.getUser2_id() : chat.getUser1_id();
if (bothSides) {
PrivateChatDatabase.markBothDeleted(chatId);
MessageDatabase.markGloballyDeleted(chatId);
MessageDatabase.logDeletedMessagesFor(chatId, self);
MessageDatabase.logDeletedMessagesFor(chatId, other);
return new ResponseModel("success", "Chat deleted for both sides.");
} else {
if (chat.getUser1_id().equals(self))
PrivateChatDatabase.markUser1Deleted(chatId);
else
PrivateChatDatabase.markUser2Deleted(chatId);
MessageDatabase.logDeletedMessagesFor(chatId, self);
return new ResponseModel("success", "Chat deleted (one-sided).");
}
} catch (Exception e) {
e.printStackTrace();
return new ResponseModel("error", "Exception while deleting chat.");
}
}
} }