diff --git a/src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java b/src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java index 1d4643d..81ed81a 100644 --- a/src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java +++ b/src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java @@ -3377,6 +3377,14 @@ public class ActionHandler { boolean isEdited = msg.optBoolean("is_edited", false); String editedAt = msg.optString("edited_at", ""); String label = isEdited ? "šŸ–Šļø (edited at: " + editedAt + ")" : ""; + + //for reply + if (msg.has("reply_to_sender") && msg.has("reply_to_content")) { + String replySender = msg.optString("reply_to_sender", "Unknown"); + String replyContent = msg.optString("reply_to_content", "(no content)"); + System.out.printf(" ā†Ŗļø Replying to [%s]: %s\n", replySender, replyContent); + } + System.out.printf("[%d] [%s] %s: %s %s\n", i + 1, time, senderName, content, label); } System.out.println("─────────────────────────────────────────────"); @@ -3508,10 +3516,35 @@ public class ActionHandler { return "not ready"; } - private String replyToMessage(UUID messageId) { - return "not ready"; + private void replyToMessage(UUID messageId) { + System.out.print("šŸ’¬ Enter your reply: "); + String content = scanner.nextLine().trim(); + + if (content.isEmpty()) { + System.out.println("āš ļø Empty reply discarded."); + return; + } + + UUID chatId = UUID.fromString(Session.currentChatId); + String chatType = Session.currentChatType; + + JSONObject req = new JSONObject(); + req.put("action", "send_reply_message"); + req.put("receiver_type", chatType); + req.put("receiver_id", chatId.toString()); + req.put("content", content); + req.put("reply_to_id", messageId.toString()); + + JSONObject res = sendWithResponse(req); + + if (res != null && res.getString("status").equals("success")) { + System.out.println("āœ… Reply sent."); + } else { + System.out.println("āŒ Failed to send reply."); + } } + private void deleteMessage(UUID messageId) { System.out.println("\nšŸ—‘ļø Delete Message Options:"); System.out.println("1. Delete for yourself (one-sided)"); diff --git a/src/main/java/org/to/telegramfinalproject/Database/MessageDatabase.java b/src/main/java/org/to/telegramfinalproject/Database/MessageDatabase.java index 260a526..e3f4293 100644 --- a/src/main/java/org/to/telegramfinalproject/Database/MessageDatabase.java +++ b/src/main/java/org/to/telegramfinalproject/Database/MessageDatabase.java @@ -246,6 +246,42 @@ public class MessageDatabase { } } + public static boolean saveReplyMessage(Message message) { + String sql = """ + INSERT INTO messages ( + message_id, sender_id, receiver_type, receiver_id, content, message_type, + send_at, status, reply_to_id, is_edited, is_deleted_globally, + original_message_id, forwarded_by, forwarded_from, edited_at + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """; + + try (Connection conn = ConnectionDb.connect(); + PreparedStatement ps = conn.prepareStatement(sql)) { + + ps.setObject(1, message.getMessage_id()); + ps.setObject(2, message.getSender_id()); + ps.setString(3, message.getReceiver_type()); + ps.setObject(4, message.getReceiver_id()); + ps.setString(5, message.getContent()); + ps.setString(6, message.getMessage_type()); + ps.setTimestamp(7, Timestamp.valueOf(message.getSend_at())); + ps.setString(8, message.getStatus()); + ps.setObject(9, message.getReply_to_id()); //Important part because of reply message id + ps.setBoolean(10, message.isIs_edited()); + ps.setBoolean(11, message.isIs_deleted_globally()); + ps.setObject(12, message.getOriginal_message_id()); + ps.setObject(13, message.getForwarded_by()); + ps.setObject(14, message.getForwarded_from()); + ps.setTimestamp(15, message.getEdited_at() != null ? Timestamp.valueOf(message.getEdited_at()) : null); + + return ps.executeUpdate() > 0; + + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + public void markMessageAsRead(UUID messageId, UUID userId) { diff --git a/src/main/java/org/to/telegramfinalproject/Models/Message.java b/src/main/java/org/to/telegramfinalproject/Models/Message.java index 663537d..7f71b28 100644 --- a/src/main/java/org/to/telegramfinalproject/Models/Message.java +++ b/src/main/java/org/to/telegramfinalproject/Models/Message.java @@ -48,7 +48,9 @@ public class Message { this.forwarded_from = forwarded_from; } - // āœ… Short Constructor + + // āœ… Short Constructors + //for normal messages public Message(UUID messageId, UUID senderId, UUID receiverId, String receiverType, String content, String messageType, LocalDateTime sendAt) { this.message_id = messageId; @@ -60,6 +62,24 @@ public class Message { this.send_at = sendAt; } + //for reply messages + public Message(UUID messageId, UUID senderId, String receiverType, UUID receiverId, + String content, String messageType, LocalDateTime sendAt, String status, + UUID replyToId) { + this.message_id = messageId; + this.sender_id = senderId; + this.receiver_type = receiverType; + this.receiver_id = receiverId; + this.content = content; + this.message_type = messageType; + this.send_at = sendAt; + this.status = status; + this.reply_to_id = replyToId; + this.is_edited = false; + this.is_deleted_globally = false; + } + + public Message(UUID messageId, UUID senderId, String receiverType, UUID receiverId, diff --git a/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java b/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java index 461598d..e8b63da 100644 --- a/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java +++ b/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java @@ -2149,6 +2149,16 @@ public class ClientHandler implements Runnable { obj.put("is_deleted_globally", m.isIs_deleted_globally()); obj.put("edited_at", m.getEdited_at() != null ? m.getEdited_at().toString() : JSONObject.NULL); + //for reply + if (m.getReply_to_id() != null) { + Message replied = MessageDatabase.findById(m.getReply_to_id()); + if (replied != null) { + User repliedSender = userDatabase.findByInternalUUID(replied.getSender_id()); + obj.put("reply_to_id", replied.getMessage_id().toString()); + obj.put("reply_to_sender", repliedSender != null ? repliedSender.getProfile_name() : "Unknown"); + obj.put("reply_to_content", replied.getContent()); + } + } result.put(obj); } @@ -2237,6 +2247,33 @@ public class ClientHandler implements Runnable { break; } + case "send_reply_message" : { + UUID senderId = currentUser.getInternal_uuid(); + String content = requestJson.getString("content"); + String receiverType = requestJson.getString("receiver_type"); + UUID receiverId = UUID.fromString(requestJson.getString("receiver_id")); + UUID replyToId = UUID.fromString(requestJson.getString("reply_to_id")); + + Message message = new Message( + UUID.randomUUID(), + senderId, + receiverType, + receiverId, + content, + "TEXT", + LocalDateTime.now(), + "SEND", + replyToId + ); + + boolean saved = MessageDatabase.saveReplyMessage(message); + response = saved ? + new ResponseModel("success", "Reply sent") : + new ResponseModel("error", "Failed to send reply"); + break; + } + + default: