Reaction and forwarded

This commit is contained in:
2025-08-07 21:20:49 +03:30
parent 608aae4d4e
commit e2e4bab029
4 changed files with 243 additions and 12 deletions
@@ -3378,16 +3378,37 @@ public class ActionHandler {
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);
// ✅ Forwarded info
String forwardLabel = "";
if (msg.optBoolean("is_forwarded", false)) {
String forwardFrom = msg.optString("forwarded_from_name", "Unknown");
forwardLabel = "🔁 Forwarded from " + forwardFrom;
}
System.out.printf("[%d] [%s] %s: %s %s\n", i + 1, time, senderName, content, label);
//for reply
String replyLabel = "";
if (msg.has("reply_to_id")) {
String repliedSender = msg.optString("reply_to_sender", "Unknown");
String repliedContent = msg.optString("reply_to_content", "...");
replyLabel = "↪️ Reply to " + repliedSender + ": \"" + repliedContent + "\"";
}
JSONArray reactions = msg.optJSONArray("reactions");
if (reactions != null && !reactions.isEmpty()) {
System.out.print(" 💬 Reactions: ");
for (int j = 0; j < reactions.length(); j++) {
System.out.print(reactions.getString(j) + " ");
}
System.out.println();
}
System.out.printf("[%d] [%s] %s: \n", i + 1, time, senderName);
if (!forwardLabel.isEmpty()) System.out.println(forwardLabel);
if (!replyLabel.isEmpty()) System.out.println(replyLabel);
System.out.printf("%s %s\n", content, label);
System.out.println("─────────────────────────────────────────────");
}
System.out.print("""
💬 Options:
@@ -3507,14 +3528,72 @@ public class ActionHandler {
}
private String reactToMessage(UUID messageId) {
return "not ready";
private void reactToMessage(UUID messageId) {
System.out.print("😊 Enter your reaction (e.g., ❤️, 👍, 😂): ");
String reaction = scanner.nextLine().trim();
if (reaction.isEmpty()) {
System.out.println("⚠️ Empty reaction discarded.");
return;
}
private String forwardMessage(UUID messageId) {
return "not ready";
JSONObject req = new JSONObject();
req.put("action", "react_to_message");
req.put("message_id", messageId.toString());
req.put("reaction", reaction);
JSONObject res = sendWithResponse(req);
if (res != null && res.getString("status").equals("success")) {
System.out.println("✅ Reaction sent.");
} else {
System.out.println("❌ Failed to react to message.");
}
}
private void forwardMessage(UUID originalMessageId) {
System.out.println("\n📤 Select a chat to forward this message to:");
List<ChatEntry> chatList = Session.chatList;
for (int i = 0; i < chatList.size(); i++) {
ChatEntry c = chatList.get(i);
System.out.printf("%d. [%s] %s\n", i + 1, c.getType(), c.getName());
}
System.out.println("0. Cancel");
System.out.print("➤ Enter chat number: ");
String input = scanner.nextLine().trim();
if (input.equals("0")) return;
try {
int choice = Integer.parseInt(input);
if (choice < 1 || choice > chatList.size()) {
System.out.println("❌ Invalid choice.");
return;
}
ChatEntry target = chatList.get(choice - 1);
JSONObject req = new JSONObject();
req.put("action", "forward_message");
req.put("target_chat_id", target.getId());
req.put("target_chat_type", target.getType());
req.put("original_message_id", originalMessageId.toString());
req.put("forwarded_by", Session.currentUser.getString("internal_uuid"));
JSONObject res = sendWithResponse(req);
if (res != null && res.getString("status").equals("success")) {
System.out.println("✅ Message forwarded successfully.");
} else {
System.out.println("❌ Failed to forward the message.");
}
} catch (NumberFormatException e) {
System.out.println("❌ Invalid input.");
}
}
private void replyToMessage(UUID messageId) {
System.out.print("💬 Enter your reply: ");
@@ -282,6 +282,42 @@ public class MessageDatabase {
}
}
public static boolean saveForwardedMessage(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
) 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());
ps.setBoolean(10, message.isIs_edited());
ps.setBoolean(11, message.isIs_deleted_globally());
ps.setObject(12, message.getOriginal_message_id()); //original id
ps.setObject(13, message.getForwarded_by()); //forwarded by
ps.setObject(14, message.getForwarded_from()); //forwarded from
return ps.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
public void markMessageAsRead(UUID messageId, UUID userId) {
@@ -0,0 +1,47 @@
package org.to.telegramfinalproject.Database;
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 java.util.UUID;
public class MessageReactionDatabase {
public static boolean saveOrUpdateReaction(UUID messageId, UUID userId, String reaction) {
String sql = """
INSERT INTO message_reactions (message_id, user_id, emoji)
VALUES (?, ?, ?)
ON CONFLICT (message_id, user_id)
DO UPDATE SET emoji = EXCLUDED.emoji, reacted_at = CURRENT_TIMESTAMP
""";
try (Connection conn = ConnectionDb.connect();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, messageId);
ps.setObject(2, userId);
ps.setString(3, reaction);
return ps.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
public static List<String> getReactions(UUID messageId) {
String sql = "SELECT emoji FROM message_reactions WHERE message_id = ?";
List<String> reactions = new ArrayList<>();
try (Connection conn = ConnectionDb.connect();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setObject(1, messageId);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
reactions.add(rs.getString("emoji"));
}
} catch (SQLException e) {
e.printStackTrace();
}
return reactions;
}
}
@@ -2149,7 +2149,7 @@ 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
//For reply messages
if (m.getReply_to_id() != null) {
Message replied = MessageDatabase.findById(m.getReply_to_id());
if (replied != null) {
@@ -2160,9 +2160,26 @@ public class ClientHandler implements Runnable {
}
}
// For forwarded messages
if (m.getOriginal_message_id() != null && m.getForwarded_from() != null) {
User originalSender = userDatabase.findByInternalUUID(m.getForwarded_from());
obj.put("is_forwarded", true);
obj.put("forwarded_from_id", m.getForwarded_from().toString());
obj.put("forwarded_from_name", originalSender != null ? originalSender.getProfile_name() : "Unknown");
} else {
obj.put("is_forwarded", false);
}
//For reactions
List<String> reactions = MessageReactionDatabase.getReactions(m.getMessage_id());
obj.put("reactions", new JSONArray(reactions));
result.put(obj);
}
JSONObject data = new JSONObject();
data.put("get_chat_messages", result);
@@ -2273,6 +2290,58 @@ public class ClientHandler implements Runnable {
break;
}
case "forward_message" : {
UUID originalMessageId = UUID.fromString(requestJson.getString("original_message_id"));
UUID targetChatId = UUID.fromString(requestJson.getString("target_chat_id"));
String targetChatType = requestJson.getString("target_chat_type");
// original message
Message original = MessageDatabase.findById(originalMessageId);
if (original == null) {
response = new ResponseModel("error", "Original message not found.");
break;
}
//make forwarded message
Message forwarded = new Message(
UUID.randomUUID(),
currentUser.getInternal_uuid(),
targetChatType,
targetChatId,
original.getContent(),
original.getMessage_type(),
LocalDateTime.now(),
"SEND",
null, // reply_to_id
false, // is_edited
false, // is_deleted_globally
original.getMessage_id(), //original message id
currentUser.getInternal_uuid(), // forwarded_by
original.getSender_id(), // forwarded_from
null // edited_at
);
boolean success = MessageDatabase.saveForwardedMessage(forwarded);
if (success) {
response = new ResponseModel("success", "Message forwarded.");
// (اختیاری) ارسال ریل تایم به اعضای چت مقصد
} else {
response = new ResponseModel("error", "Failed to forward message.");
}
break;
}
case "react_to_message": {
UUID messageId = UUID.fromString(requestJson.getString("message_id"));
String reaction = requestJson.getString("reaction");
boolean success = MessageReactionDatabase.saveOrUpdateReaction(messageId, currentUser.getInternal_uuid(), reaction);
response = success
? new ResponseModel("success", "Reaction saved.")
: new ResponseModel("error", "Failed to save reaction.");
break;
}