From d3f449b8d24c9387fbc16d48de4eb85b38ad07a9 Mon Sep 17 00:00:00 2001 From: Partow Roshani Date: Tue, 1 Jul 2025 15:31:12 +0330 Subject: [PATCH] add member and remove member in a group --- .../Client/ActionHandler.java | 168 ++++++++++++++++-- .../Database/ChannelDatabase.java | 16 ++ .../Server/ClientHandler.java | 54 +++++- 3 files changed, 221 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java b/src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java index ade0bfb..ba18656 100644 --- a/src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java +++ b/src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java @@ -10,6 +10,8 @@ import java.io.PrintWriter; import java.time.LocalDateTime; import java.util.*; +import static org.to.telegramfinalproject.Database.ChannelDatabase.addSubscriberToChannel; + public class ActionHandler { private final PrintWriter out; private final BufferedReader in; @@ -88,6 +90,67 @@ public class ActionHandler { } + + public void searchEligibleUsers(String entityType, UUID entityId) { + System.out.print("Enter keyword to search: "); + String keyword = scanner.nextLine().trim(); + + if (Session.currentUser == null || !Session.currentUser.has("user_id")) { + System.out.println("You must be logged in to search."); + return; + } + + JSONObject req = new JSONObject(); + req.put("action", "searchEligibleUsers"); + req.put("keyword", keyword); + req.put("user_id", Session.currentUser.getString("user_id")); + req.put("entity_id", entityId.toString()); + req.put("entity_type", entityType); // group یا channel + + JSONObject res = sendWithResponse(req); + + if (res == null || !res.getString("status").equals("success")) { + System.out.println("❌ " + (res != null ? res.getString("message") : "No response received.")); + return; + } + + JSONArray results = res.getJSONObject("data").getJSONArray("results"); + if (results.isEmpty()) { + System.out.println("⚠️ No eligible users found."); + return; + } + + System.out.println("\nEligible Users:"); + for (int i = 0; i < results.length(); i++) { + JSONObject user = results.getJSONObject(i); + System.out.println((i + 1) + ". " + user.getString("name") + " (ID: " + user.getString("id") + ")"); + } + + System.out.print("Select a user to add (or 0 to cancel): "); + int choice; + try { + choice = Integer.parseInt(scanner.nextLine()) - 1; + } catch (Exception e) { + System.out.println("❌ Invalid input."); + return; + } + + if (choice < 0 || choice >= results.length()) { + System.out.println("Cancelled."); + return; + } + + JSONObject selected = results.getJSONObject(choice); + UUID targetUUID = UUID.fromString(selected.getString("uuid")); + + if (entityType.equals("group")) { + addMemberToGroup(entityId, targetUUID); + } else if (entityType.equals("channel")) { + addSubscriberToChannel(entityId, targetUUID); + } + } + + private void addContact(UUID contactId) { JSONObject req = new JSONObject(); req.put("action", "add_contact"); @@ -554,6 +617,8 @@ public class ActionHandler { openChat(selected); } + + private void openChat(ChatEntry chat) { JSONObject req = new JSONObject(); req.put("action", "get_messages"); @@ -615,7 +680,7 @@ public class ActionHandler { JSONObject res = sendWithResponse(req); if (res == null || !res.getString("status").equals("success")) { - return new JSONObject(); // پیش‌فرض خالی یعنی هیچ پرمیشنی + return new JSONObject(); } return res.getJSONObject("data"); } @@ -643,10 +708,13 @@ public class ActionHandler { if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) { System.out.println("6. Remove Admin"); } - if (isOwner) { - System.out.println("7. Delete Group"); + if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) { + System.out.println("7. Remove member"); } - System.out.println("8. Leave Group"); + if (isOwner) { + System.out.println("8. Delete Group"); + } + System.out.println("9. Leave Group"); System.out.println("0. Back to Chat List"); String input = scanner.nextLine(); @@ -654,7 +722,8 @@ public class ActionHandler { case "1" -> sendMessageTo(chat.getId(), "group"); case "2" -> viewGroupMembers(chat.getId()); case "3" -> { - if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) addMemberToGroup(chat.getId()); + if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) + searchEligibleUsers("group", chat.getId()); else System.out.println("❌ You don't have permission."); } case "4" -> { @@ -669,12 +738,15 @@ public class ActionHandler { if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) removeAdminFromGroup(chat.getId()); else System.out.println("❌ You don't have permission."); } - case "7" -> { + case "7" ->{ + if(isOwner || (isAdmin && perms.optBoolean("can_remove_members",false))) removeMemberFromGroup(chat.getId()); + } + case "8" -> { if (isOwner) deleteGroup(chat.getId()); else System.out.println("❌ You don't have permission."); return false; } - case "8" -> { + case "9" -> { leaveChat(chat.getId(), "group"); return false; } @@ -739,6 +811,65 @@ public class ActionHandler { + private void removeMemberFromGroup(UUID groupId) { + JSONObject req = new JSONObject(); + req.put("action", "view_group_members"); + req.put("group_id", groupId.toString()); + + JSONObject res = sendWithResponse(req); + if (res == null || !res.getString("status").equals("success")) { + System.out.println("❌ Failed to fetch members."); + return; + } + + JSONArray members = res.getJSONObject("data").getJSONArray("members"); + List eligible = new ArrayList<>(); + + System.out.println("\n--- Members List ---"); + for (int i = 0; i < members.length(); i++) { + JSONObject m = members.getJSONObject(i); + String role = m.getString("role"); + String profileName = m.getString("profile_name"); + String userId = m.getString("user_id"); + + // فقط اونر غیرقابل حذف + if (role.equals("owner")) continue; + + eligible.add(m); + System.out.println((eligible.size()) + ". " + profileName + " (" + userId + ") [" + role + "]"); + } + + if (eligible.isEmpty()) { + System.out.println("⚠️ No removable members."); + return; + } + + System.out.print("Select a member to remove: "); + int choice; + try { + choice = Integer.parseInt(scanner.nextLine()) - 1; + } catch (Exception e) { + System.out.println("❌ Invalid input."); + return; + } + + if (choice < 0 || choice >= eligible.size()) { + System.out.println("❌ Invalid selection."); + return; + } + + JSONObject selected = eligible.get(choice); + String targetInternalUUID = selected.getString("internal_uuid"); + + JSONObject removeReq = new JSONObject(); + removeReq.put("action", "remove_member_from_group"); + removeReq.put("group_id", groupId.toString()); + removeReq.put("user_id", targetInternalUUID); + + JSONObject removeRes = sendWithResponse(removeReq); + if (removeRes != null) + System.out.println(removeRes.getString("message")); + } @@ -948,20 +1079,31 @@ public class ActionHandler { } } - private void addMemberToGroup(UUID groupId) { - System.out.print("Enter user_id to add: "); - String userId = scanner.nextLine().trim(); - + private void addMemberToGroup(UUID groupId, UUID userId) { JSONObject req = new JSONObject(); req.put("action", "add_member_to_group"); req.put("group_id", groupId.toString()); - req.put("user_id", userId); + req.put("user_id", userId.toString()); JSONObject res = sendWithResponse(req); - if (res != null) + if (res != null) { System.out.println(res.getString("message")); + } } + private void addSubscriberToChannel(UUID channelId, UUID userId) { + JSONObject req = new JSONObject(); + req.put("action", "add_subscriber_to_channel"); + req.put("channel_id", channelId.toString()); + req.put("user_id", userId.toString()); + + JSONObject res = sendWithResponse(req); + if (res != null) { + System.out.println(res.getString("message")); + } + } + + private void editGroupInfo(UUID groupId) { System.out.print("Enter new group name: "); String newName = scanner.nextLine().trim(); diff --git a/src/main/java/org/to/telegramfinalproject/Database/ChannelDatabase.java b/src/main/java/org/to/telegramfinalproject/Database/ChannelDatabase.java index 01ac6b4..f293efa 100644 --- a/src/main/java/org/to/telegramfinalproject/Database/ChannelDatabase.java +++ b/src/main/java/org/to/telegramfinalproject/Database/ChannelDatabase.java @@ -419,5 +419,21 @@ public class ChannelDatabase { } + public static boolean isUserInChannel(UUID userId, UUID channelId) { + try (Connection conn = ConnectionDb.connect(); + PreparedStatement stmt = conn.prepareStatement( + "SELECT 1 FROM channel_subscribers WHERE channel_id = ? AND user_id = ?")) { + stmt.setObject(1, channelId); + stmt.setObject(2, userId); + + ResultSet rs = stmt.executeQuery(); + return rs.next(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + } diff --git a/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java b/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java index 6bee449..7eb2de9 100644 --- a/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java +++ b/src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java @@ -193,6 +193,41 @@ public class ClientHandler implements Runnable { break; } + + + case "searchEligibleUsers": { + String keyword = requestJson.optString("keyword"); + UUID entityId = UUID.fromString(requestJson.getString("entity_id")); + String entityType = requestJson.getString("entity_type"); // group یا channel + + String user_Id = requestJson.getString("user_id"); + User currentUser = new userDatabase().findByUserId(user_Id); + + List results = new ArrayList<>(); + for (User u : new userDatabase().searchUsers(keyword, currentUser.getInternal_uuid())) { + + boolean isMember = switch (entityType) { + case "group" -> GroupDatabase.isUserInGroup(u.getInternal_uuid(), entityId); + case "channel" -> ChannelDatabase.isUserInChannel(u.getInternal_uuid(), entityId); + default -> true; + }; + + if (isMember || u.getInternal_uuid().equals(currentUser.getInternal_uuid())) continue; + + JSONObject obj = new JSONObject(); + obj.put("id", u.getUser_id()); + obj.put("uuid", u.getInternal_uuid().toString()); + obj.put("name", u.getProfile_name()); + results.add(obj); + } + + + JSONObject data = new JSONObject(); + data.put("results", new JSONArray(results)); + response = new ResponseModel("success", "Eligible users found", data); + break; + } + case "search": { String keyword = requestJson.optString("keyword"); List results = new ArrayList<>(); @@ -479,6 +514,9 @@ public class ClientHandler implements Runnable { response = new ResponseModel("success", "Chat list updated.", data); break; } + + + case "create_group": { try { String groupId = requestJson.getString("group_id"); @@ -644,11 +682,14 @@ public class ClientHandler implements Runnable { } + + + case "remove_admin_from_group": { UUID groupId = UUID.fromString(requestJson.getString("group_id")); String targetUserIdStr = requestJson.getString("user_id"); - // تبدیل user_id نمایشی به internal_uuid واقعی + User targetUser = new userDatabase().findByUserId(targetUserIdStr); if (targetUser == null) { response = new ResponseModel("error", "User not found."); @@ -713,8 +754,13 @@ public class ClientHandler implements Runnable { } String targetRole = GroupDatabase.getGroupRole(groupId, targetUserId); - if (targetRole.equals("owner") || targetRole.equals("admin")) { - response = new ResponseModel("error", "You cannot remove admins or owner this way."); + if (targetRole == null) { + response = new ResponseModel("error", "User is not a member of the group."); + break; + } + + if (targetRole.equals("owner")) { + response = new ResponseModel("error", "You cannot remove the owner."); break; } @@ -726,6 +772,7 @@ public class ClientHandler implements Runnable { } + case "view_group_admins": { UUID groupId = UUID.fromString(requestJson.getString("group_id")); @@ -752,7 +799,6 @@ public class ClientHandler implements Runnable { switch (receiverType) { case "private" -> { - // تبدیل user_id به internal_uuid User otherUser = new userDatabase().findByInternalUUID(UUID.fromString(receiverId)); if (otherUser == null) { response = new ResponseModel("error", "User not found.");