fix search in messages

This commit is contained in:
2025-08-05 13:59:01 +03:30
parent 4647dafa1d
commit f49dfacc33
4 changed files with 310 additions and 164 deletions
@@ -607,12 +607,24 @@ public class ActionHandler {
String type = item.getString("type");
if (type.equals("message")) {
System.out.println((i + 1) + ". [message] \"" + item.getString("content") + "\""
+ " (from: " + item.optString("sender", "N/A") + ", at: " + item.getString("time") + ")");
String senderName = item.optString("sender_name", item.optString("sender", "Unknown"));
String time = item.optString("time", "Unknown time");
String content = item.optString("content", "[No content]");
String context = "";
if (item.has("group_name")) {
context = " in group: " + item.getString("group_name");
} else if (item.has("channel_name")) {
context = " in channel: " + item.getString("channel_name");
}
System.out.println((i + 1) + ". [message] \"" + content + "\""
+ " (from: " + senderName + context + ", at: " + time + ")");
} else {
System.out.println((i + 1) + ". [" + type + "] "
+ item.getString("name") + " (ID: " + item.getString("id") + ")");
}
}
System.out.print("Select a result number to interact (or 0 to exit): ");
@@ -714,6 +726,22 @@ public class ActionHandler {
case "message" -> {
String receiverId = selected.getString("receiver_id");
String receiverType = selected.getString("receiver_type");
String senderName = selected.optString("sender_name", "Unknown");
String content = selected.optString("content", "[No content]");
String time = selected.optString("time", "Unknown time");
String context = "";
if (receiverType.equals("group")) {
context = "in group: " + selected.optString("group_name", "Unknown group");
} else if (receiverType.equals("channel")) {
context = "in channel: " + selected.optString("channel_name", "Unknown channel");
}
System.out.println("📩 Message preview:");
System.out.println("From: " + senderName);
if (!context.isEmpty()) System.out.println(context);
System.out.println("Time: " + time);
System.out.println("Content: \"" + content + "\"");
System.out.println("🔍 Looking for chat with displayId='" + receiverId + "' type='" + receiverType + "'");
@@ -725,6 +753,7 @@ public class ActionHandler {
openChat(chat);
}
default -> System.out.println("No interaction available for type: " + type);
}
}
@@ -6,6 +6,7 @@ import org.to.telegramfinalproject.Models.Message;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -128,14 +129,17 @@ public class MessageDatabase {
public static List<Message> getUnreadMessages(UUID userId) {
List<Message> messages = new ArrayList<>();
String sql = """
SELECT m.* FROM messages m
SELECT m.*
FROM messages m
LEFT JOIN message_receipts r ON m.message_id = r.message_id AND r.user_id = ?
LEFT JOIN deleted_messages d ON m.message_id = d.message_id AND d.user_id = ?
WHERE r.user_id IS NULL
AND d.message_id IS NULL
AND m.is_deleted_globally = FALSE
AND (
(m.receiver_type = 'private' AND m.receiver_id = ?)
OR
@@ -147,19 +151,21 @@ public class MessageDatabase {
SELECT 1 FROM channel_subscribers cs WHERE cs.channel_id = m.receiver_id AND cs.user_id = ?
))
)
ORDER BY m.send_at DESC
""";
try (Connection conn = ConnectionDb.connect();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setObject(1, userId);
stmt.setObject(2, userId);
stmt.setObject(3, userId);
stmt.setObject(4, userId);
stmt.setObject(1, userId); // for message_receipts
stmt.setObject(2, userId); // for deleted_messages
stmt.setObject(3, userId); // for private messages
stmt.setObject(4, userId); // for group members
stmt.setObject(5, userId); // for channel subscribers
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
messages.add(new Message(
Message message = new Message(
UUID.fromString(rs.getString("message_id")),
rs.getObject("sender_id") != null ? UUID.fromString(rs.getString("sender_id")) : null,
rs.getString("receiver_type"),
@@ -170,10 +176,13 @@ public class MessageDatabase {
rs.getString("status"),
rs.getObject("reply_to_id") != null ? UUID.fromString(rs.getString("reply_to_id")) : null,
rs.getBoolean("is_edited"),
rs.getBoolean("is_deleted_globally"),
rs.getObject("original_message_id") != null ? UUID.fromString(rs.getString("original_message_id")) : null,
rs.getObject("forwarded_by") != null ? UUID.fromString(rs.getString("forwarded_by")) : null,
rs.getObject("forwarded_from") != null ? UUID.fromString(rs.getString("forwarded_from")) : null
));
);
messages.add(message);
}
} catch (SQLException e) {
@@ -183,6 +192,8 @@ public class MessageDatabase {
return messages;
}
public static List<FileAttachment> getAttachments(UUID messageId) {
List<FileAttachment> attachments = new ArrayList<>();
String sql = "SELECT file_url, file_type FROM message_attachments WHERE message_id = ?";
@@ -271,6 +282,7 @@ public class MessageDatabase {
rs.getString("status"),
(UUID) rs.getObject("reply_to_id"),
rs.getBoolean("is_edited"),
rs.getBoolean("is_deleted_globally"),
(UUID) rs.getObject("original_message_id"),
(UUID) rs.getObject("forwarded_by"),
(UUID) rs.getObject("forwarded_from")
@@ -279,33 +291,90 @@ public class MessageDatabase {
// public static List<Message> searchMessagesForUser(UUID userId, String keyword) {
// List<Message> result = new ArrayList<>();
// String sql = """
// SELECT * FROM messages
// WHERE receiver_type = 'private'
// AND (sender_id = ? OR receiver_id = ?)
// AND content ILIKE ?
// ORDER BY send_at DESC
// """;
//
// try (Connection conn = ConnectionDb.connect();
// PreparedStatement stmt = conn.prepareStatement(sql)) {
// stmt.setObject(1, userId);
// stmt.setObject(2, userId);
// stmt.setString(3, "%" + keyword + "%");
//
// ResultSet rs = stmt.executeQuery();
// while (rs.next()) {
// result.add(extractMessage(rs));
// }
// } catch (SQLException e) {
// e.printStackTrace();
// }
//
// return result;
// }
public static List<Message> searchMessagesForUser(UUID userId, String keyword) {
List<Message> result = new ArrayList<>();
String sql = """
SELECT * FROM messages
WHERE receiver_type = 'private'
AND (sender_id = ? OR receiver_id = ?)
AND content ILIKE ?
ORDER BY send_at DESC
SELECT * FROM messages m
WHERE m.receiver_type = 'private'
AND m.content ILIKE ?
AND m.is_deleted_globally = FALSE
AND (m.sender_id = ? OR m.receiver_id = ?)
AND NOT EXISTS (
SELECT 1 FROM deleted_messages d
WHERE d.message_id = m.message_id AND d.user_id = ?
)
ORDER BY m.send_at DESC
""";
try (Connection conn = ConnectionDb.connect();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setObject(1, userId);
stmt.setObject(2, userId);
stmt.setString(3, "%" + keyword + "%");
PreparedStatement ps = conn.prepareStatement(sql)) {
ResultSet rs = stmt.executeQuery();
ps.setString(1, "%" + keyword + "%");
ps.setObject(2, userId); // m.sender_id
ps.setObject(3, userId); // m.receiver_id
ps.setObject(4, userId); // deleted_messages
ResultSet rs = ps.executeQuery();
List<Message> messages = new ArrayList<>();
while (rs.next()) {
result.add(extractMessage(rs));
messages.add(mapResultSetToMessage(rs));
}
return messages;
} catch (SQLException e) {
e.printStackTrace();
return Collections.emptyList();
}
}
return result;
private static Message mapResultSetToMessage(ResultSet rs) throws SQLException {
return new Message(
UUID.fromString(rs.getString("message_id")),
rs.getObject("sender_id") != null ? UUID.fromString(rs.getString("sender_id")) : null,
rs.getString("receiver_type"),
UUID.fromString(rs.getString("receiver_id")),
rs.getString("content"),
rs.getString("message_type"),
rs.getTimestamp("send_at").toLocalDateTime(),
rs.getString("status"),
rs.getObject("reply_to_id") != null ? UUID.fromString(rs.getString("reply_to_id")) : null,
rs.getBoolean("is_edited"),
rs.getBoolean("is_deleted_globally"),
rs.getObject("original_message_id") != null ? UUID.fromString(rs.getString("original_message_id")) : null,
rs.getObject("forwarded_by") != null ? UUID.fromString(rs.getString("forwarded_by")) : null,
rs.getObject("forwarded_from") != null ? UUID.fromString(rs.getString("forwarded_from")) : null
);
}
// public static List<Message> privateChatHistory(UUID chatId) {
// List<Message> result = new ArrayList<>();
// String sql = """
@@ -464,32 +533,74 @@ public class MessageDatabase {
public static List<Message> searchMessagesInGroups(List<UUID> groupIds, String keyword) {
// public static List<Message> searchMessagesInGroups(List<UUID> groupIds, String keyword) {
// List<Message> result = new ArrayList<>();
// if (groupIds.isEmpty()) return result;
//
// String placeholders = groupIds.stream().map(id -> "?").collect(Collectors.joining(", "));
// String sql = """
// SELECT * FROM messages
// WHERE receiver_type = 'group'
// AND receiver_id IN (%s)
// AND content ILIKE ?
// ORDER BY send_at DESC
// """.formatted(placeholders);
//
// try (Connection conn = ConnectionDb.connect();
// PreparedStatement stmt = conn.prepareStatement(sql)) {
//
// int i = 1;
// for (UUID id : groupIds) {
// stmt.setObject(i++, id);
// }
// stmt.setString(i, "%" + keyword + "%");
//
// ResultSet rs = stmt.executeQuery();
// while (rs.next()) {
// result.add(extractMessage(rs));
// }
// } catch (SQLException e) {
// e.printStackTrace();
// }
//
// return result;
// }
public static List<Message> searchMessagesInGroups(List<UUID> groupIds, String keyword, UUID userId) {
List<Message> result = new ArrayList<>();
if (groupIds.isEmpty()) return result;
String placeholders = groupIds.stream().map(id -> "?").collect(Collectors.joining(", "));
String sql = """
SELECT * FROM messages
WHERE receiver_type = 'group'
AND receiver_id IN (%s)
AND content ILIKE ?
ORDER BY send_at DESC
SELECT m.*
FROM messages m
LEFT JOIN deleted_messages d ON m.message_id = d.message_id AND d.user_id = ?
WHERE m.receiver_type = 'group'
AND m.receiver_id IN (%s)
AND d.message_id IS NULL
AND m.is_deleted_globally = FALSE
AND m.content ILIKE ?
ORDER BY m.send_at DESC
""".formatted(placeholders);
try (Connection conn = ConnectionDb.connect();
PreparedStatement stmt = conn.prepareStatement(sql)) {
int i = 1;
for (UUID id : groupIds) {
stmt.setObject(i++, id);
stmt.setObject(i++, userId);
for (UUID groupId : groupIds) {
stmt.setObject(i++, groupId);
}
stmt.setString(i, "%" + keyword + "%");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
result.add(extractMessage(rs));
result.add(mapResultSetToMessage(rs));
}
} catch (SQLException e) {
e.printStackTrace();
}
@@ -498,32 +609,71 @@ public class MessageDatabase {
}
// public static List<Message> searchMessagesInChannels(List<UUID> channelIds, String keyword) {
// List<Message> result = new ArrayList<>();
// if (channelIds.isEmpty()) return result;
//
// String placeholders = channelIds.stream().map(id -> "?").collect(Collectors.joining(", "));
// String sql = """
// SELECT * FROM messages
// WHERE receiver_type = 'channel'
// AND receiver_id IN (%s)
// AND content ILIKE ?
// ORDER BY send_at DESC
// """.formatted(placeholders);
//
// try (Connection conn = ConnectionDb.connect();
// PreparedStatement stmt = conn.prepareStatement(sql)) {
//
// int i = 1;
// for (UUID id : channelIds) {
// stmt.setObject(i++, id);
// }
// stmt.setString(i, "%" + keyword + "%");
//
// ResultSet rs = stmt.executeQuery();
// while (rs.next()) {
// result.add(extractMessage(rs));
// }
// } catch (SQLException e) {
// e.printStackTrace();
// }
//
// return result;
// }
public static List<Message> searchMessagesInChannels(List<UUID> channelIds, String keyword) {
List<Message> result = new ArrayList<>();
if (channelIds.isEmpty()) return result;
String placeholders = channelIds.stream().map(id -> "?").collect(Collectors.joining(", "));
String sql = """
SELECT * FROM messages
WHERE receiver_type = 'channel'
AND receiver_id IN (%s)
AND content ILIKE ?
ORDER BY send_at DESC
SELECT m.*
FROM messages m
WHERE m.receiver_type = 'channel'
AND m.receiver_id IN (%s)
AND m.is_deleted_globally = FALSE
AND m.content ILIKE ?
ORDER BY m.send_at DESC
""".formatted(placeholders);
try (Connection conn = ConnectionDb.connect();
PreparedStatement stmt = conn.prepareStatement(sql)) {
int i = 1;
for (UUID id : channelIds) {
stmt.setObject(i++, id);
for (UUID channelId : channelIds) {
stmt.setObject(i++, channelId);
}
stmt.setString(i, "%" + keyword + "%");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
result.add(extractMessage(rs));
result.add(mapResultSetToMessage(rs));
}
} catch (SQLException e) {
e.printStackTrace();
}
@@ -7,23 +7,25 @@ import java.util.UUID;
public class Message {
private UUID message_id;
private UUID sender_id;
private String receiver_type; // private, group, channel
private String receiver_type;
private UUID receiver_id;
private String content;
private String message_type; // TEXT, IMAGE, FILE, ...
private String message_type;
private LocalDateTime send_at;
private String status; // SENT, DELIVERED, READ
private String status;
private UUID reply_to_id;
private boolean is_edited;
private boolean is_deleted_globally;
private UUID original_message_id;
private UUID forwarded_by;
private UUID forwarded_from;
private List<FileAttachment> attachments;
// ✅ Full Constructor
public Message(UUID message_id, UUID sender_id, String receiver_type, UUID receiver_id, String content,
String message_type, LocalDateTime send_at, String status,
UUID reply_to_id, boolean is_edited, UUID original_message_id,
UUID forwarded_by, UUID forwarded_from) {
UUID reply_to_id, boolean is_edited, boolean is_deleted_globally,
UUID original_message_id, UUID forwarded_by, UUID forwarded_from) {
this.message_id = message_id;
this.sender_id = sender_id;
this.receiver_type = receiver_type;
@@ -34,127 +36,69 @@ public class Message {
this.status = status;
this.reply_to_id = reply_to_id;
this.is_edited = is_edited;
this.is_deleted_globally = is_deleted_globally;
this.original_message_id = original_message_id;
this.forwarded_by = forwarded_by;
this.forwarded_from = forwarded_from;
}
public Message(UUID messageId, UUID senderId, UUID receiverId, String receiverType, String content, String messageType, LocalDateTime now) {
// ✅ Short Constructor
public Message(UUID messageId, UUID senderId, UUID receiverId, String receiverType,
String content, String messageType, LocalDateTime sendAt) {
this.message_id = messageId;
this.sender_id = senderId;
this.receiver_id = receiverId;
this.receiver_type = receiverType;
this.content = content;
this.message_type = messageType;
this.send_at = now;
this.send_at = sendAt;
}
// ✅ Getters & Setters
public UUID getMessage_id() { return message_id; }
public void setMessage_id(UUID messageId) { this.message_id = messageId; }
public UUID getMessage_id() {
return message_id;
public UUID getSender_id() { return sender_id; }
public void setSender_id(UUID sender_id) { this.sender_id = sender_id; }
public String getReceiver_type() { return receiver_type; }
public void setReceiver_type(String receiver_type) { this.receiver_type = receiver_type; }
public UUID getReceiver_id() { return receiver_id; }
public void setReceiver_id(UUID receiver_id) { this.receiver_id = receiver_id; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public String getMessage_type() { return message_type; }
public void setMessage_type(String message_type) { this.message_type = message_type; }
public LocalDateTime getSend_at() { return send_at; }
public void setSend_at(LocalDateTime send_at) { this.send_at = send_at; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public UUID getReply_to_id() { return reply_to_id; }
public void setReply_to_id(UUID reply_to_id) { this.reply_to_id = reply_to_id; }
public boolean isIs_edited() { return is_edited; }
public void setIs_edited(boolean is_edited) { this.is_edited = is_edited; }
public boolean isIs_deleted_globally() { return is_deleted_globally; }
public void setIs_deleted_globally(boolean is_deleted_globally) {
this.is_deleted_globally = is_deleted_globally;
}
public UUID getOriginal_message_id() { return original_message_id; }
public void setOriginal_message_id(UUID original_message_id) { this.original_message_id = original_message_id; }
public UUID getSender_id() {
return sender_id;
}
public UUID getForwarded_by() { return forwarded_by; }
public void setForwarded_by(UUID forwarded_by) { this.forwarded_by = forwarded_by; }
public void setSender_id(UUID sender_id) {
this.sender_id = sender_id;
}
public UUID getForwarded_from() { return forwarded_from; }
public void setForwarded_from(UUID forwarded_from) { this.forwarded_from = forwarded_from; }
public String getReceiver_type() {
return receiver_type;
}
public void setReceiver_type(String receiver_type) {
this.receiver_type = receiver_type;
}
public UUID getReceiver_id() {
return receiver_id;
}
public void setReceiver_id(UUID receiver_id) {
this.receiver_id = receiver_id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getMessage_type() {
return message_type;
}
public void setMessage_type(String message_type) {
this.message_type = message_type;
}
public LocalDateTime getSend_at() {
return send_at;
}
public void setSend_at(LocalDateTime send_at) {
this.send_at = send_at;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public UUID getReply_to_id() {
return reply_to_id;
}
public void setReply_to_id(UUID reply_to_id) {
this.reply_to_id = reply_to_id;
}
public boolean isIs_edited() {
return is_edited;
}
public void setIs_edited(boolean is_edited) {
this.is_edited = is_edited;
}
public UUID getOriginal_message_id() {
return original_message_id;
}
public void setOriginal_message_id(UUID original_message_id) {
this.original_message_id = original_message_id;
}
public UUID getForwarded_by() {
return forwarded_by;
}
public void setForwarded_by(UUID forwarded_by) {
this.forwarded_by = forwarded_by;
}
public UUID getForwarded_from() {
return forwarded_from;
}
public void setForwarded_from(UUID forwarded_from) {
this.forwarded_from = forwarded_from;
}
public void setAttachments(List<FileAttachment> attachments) {
this.attachments = attachments;
}
public List<FileAttachment> getAttachments() {
return attachments;
}
public List<FileAttachment> getAttachments() { return attachments; }
public void setAttachments(List<FileAttachment> attachments) { this.attachments = attachments; }
}
@@ -419,10 +419,14 @@ public class ClientHandler implements Runnable {
JSONObject obj = new JSONObject();
obj.put("type", "message");
obj.put("content", m.getContent());
obj.put("sender", m.getSender_id().toString());
obj.put("time", m.getSend_at().toString());
obj.put("sender", m.getSender_id() != null ? m.getSender_id().toString() : "N/A");
obj.put("receiver_id", m.getReceiver_id().toString());
obj.put("receiver_type", m.getReceiver_type());
User senderUser = userDatabase.findByInternalUUID(m.getSender_id());
String senderName = senderUser != null ? senderUser.getProfile_name() : "Unknown";
obj.put("sender_name", senderName);
results.add(obj);
}
@@ -439,13 +443,23 @@ public class ClientHandler implements Runnable {
}
List<Message> groupMessages = MessageDatabase.searchMessagesInGroups(groupIds, keyword);
List<Message> groupMessages = MessageDatabase.searchMessagesInGroups(groupIds, keyword, currentUser.getInternal_uuid());
for (Message m : groupMessages) {
JSONObject obj = new JSONObject();
obj.put("type", "message");
obj.put("from", "group");
obj.put("content", m.getContent());
obj.put("time", m.getSend_at().toString());
obj.put("sender", m.getSender_id() != null ? m.getSender_id().toString() : "N/A");
obj.put("receiver_id", m.getReceiver_id().toString());
obj.put("receiver_type", "group");
Group senderGroup = GroupDatabase.findByInternalUUID(m.getReceiver_id());
String groupName = senderGroup != null ? senderGroup.getGroup_name() : "Unknown";
obj.put("group_name", groupName);
User senderUser = userDatabase.findByInternalUUID(m.getSender_id());
String senderName = senderUser != null ? senderUser.getProfile_name() : "Unknown";
obj.put("sender_name", senderName);
results.add(obj);
}
@@ -456,6 +470,15 @@ public class ClientHandler implements Runnable {
obj.put("from", "channel");
obj.put("content", m.getContent());
obj.put("time", m.getSend_at().toString());
obj.put("sender", m.getSender_id() != null ? m.getSender_id().toString() : "N/A");
obj.put("receiver_id", m.getReceiver_id().toString());
obj.put("receiver_type", "channel");
Channel SenderChannel = ChannelDatabase.findByInternalUUID(m.getReceiver_id());
String channelName = SenderChannel != null ? SenderChannel.getChannel_name() : "Unknown";
obj.put("channel_name", channelName);
User senderUser = userDatabase.findByInternalUUID(m.getSender_id());
String senderName = senderUser != null ? senderUser.getProfile_name() : "Unknown";
obj.put("sender_name", senderName);
results.add(obj);
}