Delete group by owner, transfer ownership, leave group
This commit is contained in:
@@ -713,8 +713,11 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
if (isOwner) {
|
if (isOwner) {
|
||||||
System.out.println("8. Delete Group");
|
System.out.println("8. Delete Group");
|
||||||
}
|
System.out.println("9. Leave Group (Transfer ownership required)");
|
||||||
|
} else {
|
||||||
System.out.println("9. Leave Group");
|
System.out.println("9. Leave Group");
|
||||||
|
}
|
||||||
|
|
||||||
System.out.println("0. Back to Chat List");
|
System.out.println("0. Back to Chat List");
|
||||||
|
|
||||||
String input = scanner.nextLine();
|
String input = scanner.nextLine();
|
||||||
@@ -747,9 +750,16 @@ public class ActionHandler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case "9" -> {
|
case "9" -> {
|
||||||
|
if (isOwner) {
|
||||||
|
transferOwnershipAndLeave(chat.getId());
|
||||||
|
refreshChatList();
|
||||||
|
} else {
|
||||||
leaveChat(chat.getId(), "group");
|
leaveChat(chat.getId(), "group");
|
||||||
|
refreshChatList();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "0" -> {
|
case "0" -> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -811,6 +821,57 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void transferOwnershipAndLeave(UUID groupId) {
|
||||||
|
JSONObject req = new JSONObject();
|
||||||
|
req.put("action", "view_group_admins");
|
||||||
|
req.put("group_id", groupId.toString());
|
||||||
|
|
||||||
|
JSONObject res = sendWithResponse(req);
|
||||||
|
if (res == null || !res.getString("status").equals("success")) {
|
||||||
|
System.out.println("❌ Failed to fetch admins.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArray admins = res.getJSONObject("data").getJSONArray("admins");
|
||||||
|
|
||||||
|
if (admins.length() == 0) {
|
||||||
|
System.out.println("⚠️ No other admins available. You cannot leave without promoting someone to owner.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("--- Admins List ---");
|
||||||
|
for (int i = 0; i < admins.length(); i++) {
|
||||||
|
JSONObject admin = admins.getJSONObject(i);
|
||||||
|
System.out.printf("%d. %s (%s)\n", i + 1, admin.getString("profile_name"), admin.getString("user_id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.print("Select a new owner by number: ");
|
||||||
|
int choice = Integer.parseInt(scanner.nextLine()) - 1;
|
||||||
|
|
||||||
|
if (choice < 0 || choice >= admins.length()) {
|
||||||
|
System.out.println("Invalid selection.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject selected = admins.getJSONObject(choice);
|
||||||
|
String newOwnerId = selected.getString("user_id");
|
||||||
|
|
||||||
|
JSONObject promoteReq = new JSONObject();
|
||||||
|
promoteReq.put("action", "transfer_group_ownership");
|
||||||
|
promoteReq.put("group_id", groupId.toString());
|
||||||
|
promoteReq.put("new_owner_user_id", newOwnerId);
|
||||||
|
|
||||||
|
JSONObject promoteRes = sendWithResponse(promoteReq);
|
||||||
|
if (promoteRes == null || !promoteRes.getString("status").equals("success")) {
|
||||||
|
System.out.println("❌ Failed to transfer ownership.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("✅ Ownership transferred successfully.");
|
||||||
|
leaveChat(groupId, "group");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void removeMemberFromGroup(UUID groupId) {
|
private void removeMemberFromGroup(UUID groupId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_group_members");
|
req.put("action", "view_group_members");
|
||||||
@@ -1046,13 +1107,17 @@ public class ActionHandler {
|
|||||||
JSONObject res = sendWithResponse(req);
|
JSONObject res = sendWithResponse(req);
|
||||||
if (res == null) return;
|
if (res == null) return;
|
||||||
|
|
||||||
if (res.getBoolean("success")) {
|
String status = res.getString("status");
|
||||||
|
String message = res.getString("message");
|
||||||
|
|
||||||
|
if (status.equals("success")) {
|
||||||
System.out.println("✅ You left the chat.");
|
System.out.println("✅ You left the chat.");
|
||||||
} else {
|
} else {
|
||||||
System.out.println("❌ " + res.getString("message"));
|
System.out.println("❌ " + message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void sendMessageTo(UUID id, String type) {
|
private void sendMessageTo(UUID id, String type) {
|
||||||
System.out.print("Enter message: ");
|
System.out.print("Enter message: ");
|
||||||
String text = scanner.nextLine().trim();
|
String text = scanner.nextLine().trim();
|
||||||
@@ -1120,8 +1185,8 @@ public class ActionHandler {
|
|||||||
|
|
||||||
String currentId = data.getString("id");
|
String currentId = data.getString("id");
|
||||||
String currentName = data.getString("name");
|
String currentName = data.getString("name");
|
||||||
String currentDesc = data.optString("description", "None");
|
String currentDesc = data.optString("description", null);
|
||||||
String currentImage = data.optString("image_url", "None");
|
String currentImage = data.optString("image_url", null);
|
||||||
|
|
||||||
System.out.println("\n--- Current Group Info ---");
|
System.out.println("\n--- Current Group Info ---");
|
||||||
System.out.println("1. Group ID: " + currentId);
|
System.out.println("1. Group ID: " + currentId);
|
||||||
|
|||||||
@@ -435,5 +435,22 @@ public class ChannelDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean removeSubscriberFromChannel(UUID channelId, UUID userId) {
|
||||||
|
String sql = "DELETE FROM channel_subscribers WHERE channel_id = ? AND user_id = ?";
|
||||||
|
|
||||||
|
try (Connection conn =ConnectionDb.connect();
|
||||||
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
stmt.setObject(1, channelId);
|
||||||
|
stmt.setObject(2, userId);
|
||||||
|
|
||||||
|
int affectedRows = stmt.executeUpdate();
|
||||||
|
return affectedRows > 0;
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
System.err.println("Error removing subscriber from channel: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,22 +404,32 @@ public class GroupDatabase {
|
|||||||
|
|
||||||
|
|
||||||
public static List<JSONObject> getGroupAdminsAndOwner(UUID groupId) {
|
public static List<JSONObject> getGroupAdminsAndOwner(UUID groupId) {
|
||||||
String sql = "SELECT user_id, role, permissions FROM group_members WHERE group_id = ? AND role IN ('owner', 'admin')";
|
|
||||||
List<JSONObject> admins = new ArrayList<>();
|
List<JSONObject> admins = new ArrayList<>();
|
||||||
|
|
||||||
|
String sql = "SELECT gm.user_id, gm.role, gm.permissions, u.profile_name " +
|
||||||
|
"FROM group_members gm " +
|
||||||
|
"JOIN users u ON gm.user_id = u.internal_uuid " +
|
||||||
|
"WHERE gm.group_id = ? AND gm.role IN ('owner', 'admin')";
|
||||||
|
|
||||||
try (Connection conn = ConnectionDb.connect();
|
try (Connection conn = ConnectionDb.connect();
|
||||||
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
|
|
||||||
stmt.setObject(1, groupId);
|
stmt.setObject(1, groupId);
|
||||||
ResultSet rs = stmt.executeQuery();
|
ResultSet rs = stmt.executeQuery();
|
||||||
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
JSONObject obj = new JSONObject();
|
JSONObject obj = new JSONObject();
|
||||||
obj.put("user_id", rs.getObject("user_id").toString());
|
obj.put("user_id", rs.getObject("user_id").toString());
|
||||||
obj.put("role", rs.getString("role"));
|
obj.put("role", rs.getString("role"));
|
||||||
obj.put("permissions", new JSONObject(rs.getString("permissions")));
|
obj.put("permissions", new JSONObject(rs.getString("permissions")));
|
||||||
|
obj.put("profile_name", rs.getString("profile_name"));
|
||||||
admins.add(obj);
|
admins.add(obj);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return admins;
|
return admins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,4 +554,50 @@ public class GroupDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean transferOwnership(UUID groupId, UUID newOwnerId) {
|
||||||
|
String demoteOldOwner = "UPDATE group_members SET role = 'admin' WHERE group_id = ? AND role = 'owner'";
|
||||||
|
String promoteNewOwner = "UPDATE group_members SET role = 'owner' WHERE group_id = ? AND user_id = ?";
|
||||||
|
|
||||||
|
try (Connection conn = ConnectionDb.connect()) {
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
|
||||||
|
try (PreparedStatement demoteStmt = conn.prepareStatement(demoteOldOwner);
|
||||||
|
PreparedStatement promoteStmt = conn.prepareStatement(promoteNewOwner)) {
|
||||||
|
|
||||||
|
demoteStmt.setObject(1, groupId);
|
||||||
|
demoteStmt.executeUpdate();
|
||||||
|
|
||||||
|
promoteStmt.setObject(1, groupId);
|
||||||
|
promoteStmt.setObject(2, newOwnerId);
|
||||||
|
promoteStmt.executeUpdate();
|
||||||
|
|
||||||
|
conn.commit();
|
||||||
|
return true;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
conn.rollback();
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean deleteGroup(UUID groupId) {
|
||||||
|
try (Connection conn = ConnectionDb.connect();
|
||||||
|
PreparedStatement stmt = conn.prepareStatement("DELETE FROM groups WHERE internal_uuid = ?")) {
|
||||||
|
|
||||||
|
stmt.setObject(1, groupId);
|
||||||
|
int affectedRows = stmt.executeUpdate();
|
||||||
|
|
||||||
|
return affectedRows > 0;
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -912,6 +912,36 @@ public class ClientHandler implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case "transfer_group_ownership": {
|
||||||
|
UUID groupId = UUID.fromString(requestJson.getString("group_id"));
|
||||||
|
UUID newOwnerUserId = UUID.fromString(requestJson.getString("new_owner_user_id"));
|
||||||
|
|
||||||
|
User newOwner = userDatabase.findByInternalUUID(newOwnerUserId);
|
||||||
|
if (newOwner == null) {
|
||||||
|
response = new ResponseModel("error", "New owner not found.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GroupDatabase.isOwner(groupId, currentUser.getInternal_uuid())) {
|
||||||
|
response = new ResponseModel("error", "Only current owner can transfer ownership.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GroupDatabase.isAdmin(groupId, newOwner.getInternal_uuid())) {
|
||||||
|
response = new ResponseModel("error", "Selected user is not an admin.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = GroupDatabase.transferOwnership(groupId, newOwner.getInternal_uuid());
|
||||||
|
|
||||||
|
response = success
|
||||||
|
? new ResponseModel("success", "Ownership transferred.")
|
||||||
|
: new ResponseModel("error", "Failed to transfer ownership.");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
case "view_group_members" : {
|
case "view_group_members" : {
|
||||||
UUID groupId = UUID.fromString(requestJson.getString("group_id"));
|
UUID groupId = UUID.fromString(requestJson.getString("group_id"));
|
||||||
|
|
||||||
@@ -948,7 +978,47 @@ public class ClientHandler implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case "leave_chat": {
|
||||||
|
String chatType = requestJson.getString("chat_type");
|
||||||
|
UUID chatId = UUID.fromString(requestJson.getString("chat_id"));
|
||||||
|
userId = UUID.fromString(requestJson.getString("user_id"));
|
||||||
|
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
switch (chatType) {
|
||||||
|
case "group" -> success = GroupDatabase.removeMemberFromGroup(chatId, userId);
|
||||||
|
case "channel" -> success = ChannelDatabase.removeSubscriberFromChannel(chatId, userId);
|
||||||
|
default -> {
|
||||||
|
response = new ResponseModel("error", "Unsupported chat type.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response == null) {
|
||||||
|
response = success
|
||||||
|
? new ResponseModel("success", "Left the " + chatType + " successfully.")
|
||||||
|
: new ResponseModel("error", "Failed to leave the " + chatType + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case "delete_group": {
|
||||||
|
UUID groupId = UUID.fromString(requestJson.getString("group_id"));
|
||||||
|
|
||||||
|
if (!GroupDatabase.isOwner(groupId, currentUser.getInternal_uuid())) {
|
||||||
|
response = new ResponseModel("error", "Only the group owner can delete the group.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = GroupDatabase.deleteGroup(groupId);
|
||||||
|
|
||||||
|
response = success
|
||||||
|
? new ResponseModel("success", "Group deleted successfully.")
|
||||||
|
: new ResponseModel("error", "Failed to delete group.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user