Files
Telegram-Final-Project/src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java
T
2025-07-22 18:08:18 +03:30

2444 lines
91 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package org.to.telegramfinalproject.Client;
import org.json.JSONArray;
import org.json.JSONObject;
import org.to.telegramfinalproject.Models.ChatEntry;
import org.to.telegramfinalproject.Models.SearchRequestModel;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class ActionHandler {
private final PrintWriter out;
private final BufferedReader in;
private final Scanner scanner;
public static volatile boolean forceExitChat = false;
public static ActionHandler instance;
private void handleRealTime(JSONObject json) throws IOException {
IncomingMessageListener listener = new IncomingMessageListener(this.in);
listener.handleRealTimeEvent (json);
}
public ActionHandler(PrintWriter out, BufferedReader in, Scanner scanner) {
this.out = out;
this.in = in;
this.scanner = scanner;
ActionHandler.instance = this;
}
public void loginHandler() {
System.out.println("Login form: \n");
System.out.print("Username: ");
String username = this.scanner.nextLine();
System.out.print("Password: ");
String password = this.scanner.nextLine();
JSONObject request = new JSONObject();
request.put("action", "login");
request.put("user_id", JSONObject.NULL);
request.put("username", username);
request.put("password", password);
request.put("profile_name", JSONObject.NULL);
this.send(request);
}
public void register() {
System.out.println("Register form: \n");
System.out.print("Username: ");
String username = this.scanner.nextLine();
System.out.print("User id: ");
String user_id = this.scanner.nextLine();
System.out.print("Password: ");
String password = this.scanner.nextLine();
System.out.print("Profile name: ");
String profile_name = this.scanner.nextLine();
JSONObject request = new JSONObject();
request.put("action", "register");
request.put("user_id", user_id);
request.put("username", username);
request.put("password", password);
request.put("profile_name", profile_name);
this.send(request);
}
public void search() {
System.out.print("Enter keyword to search: ");
String keyword = scanner.nextLine();
if (Session.currentUser == null || !Session.currentUser.has("user_id")) {
System.out.println("You must be logged in to search.");
return;
}
String userId = Session.currentUser.getString("user_id");
SearchRequestModel model = new SearchRequestModel("search", keyword, userId);
send(model.toJson());
}
public void searchInUsers(){
System.out.println("Enter keyword to search: ");
String keyword = scanner.nextLine();
if (Session.currentUser == null || !Session.currentUser.has("user_id")) {
System.out.println("You must be logged in to search.");
return;
}
String userId = Session.currentUser.getString("user_id");
SearchRequestModel model = new SearchRequestModel("searchInUsers", keyword, userId);
send(model.toJson());
}
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");
req.put("user_id", Session.currentUser.getString("user_id"));
req.put("contact_id", contactId.toString());
send(req);
}
private void joinGroupOrChannel(String type, String uuid) {
JSONObject req = new JSONObject();
req.put("action", "join_" + type);
req.put("user_id", Session.getUserUUID());
req.put("id", uuid);
send(req);
}
private ChatEntry fetchChatInfo(String receiverId, String receiverType) {
JSONObject req = new JSONObject();
req.put("action", "get_chat_info");
req.put("receiver_id", receiverId);
req.put("receiver_type", receiverType);
out.println(req.toString());
try {
JSONObject response = TelegramClient.responseQueue.take();
if (response != null && response.getString("status").equals("success")) {
JSONObject data = response.getJSONObject("data");
return new ChatEntry(
UUID.fromString(data.getString("internal_id")),
receiverId,
data.getString("name"),
data.optString("image_url", ""),
receiverType,
null,
data.optBoolean("is_owner", false),
data.optBoolean("is_admin", false)
);
}
} catch (Exception e) {
System.err.println("Error fetching chat info: " + e.getMessage());
}
// اگر شکست خورد، internalId نامعتبر می‌سازیم (برای جلوگیری از null)
return new ChatEntry(
UUID.randomUUID(), // ساخت یک UUID موقت (ولی اشتباه)
receiverId,
"[Unknown " + receiverType + "]",
"",
receiverType,
null
);
}
private void refreshChatList() {
JSONObject req = new JSONObject();
req.put("action", "get_chat_list");
req.put("user_id", Session.currentUser.getString("user_id"));
out.println(req.toString());
try {
JSONObject response = TelegramClient.responseQueue.take();
if (response != null && response.getString("status").equals("success")) {
if (response.has("data") && !response.isNull("data")) {
JSONObject data = response.getJSONObject("data");
// ❗ چک کن که chat_list وجود داره
if (!data.has("chat_list") || data.isNull("chat_list")) {
System.out.println("❌ chat_list not found in response data.");
return;
}
JSONArray chatListJson = data.getJSONArray("chat_list");
List<ChatEntry> chatList = new ArrayList<>();
for (Object obj : chatListJson) {
JSONObject chat = (JSONObject) obj;
ChatEntry entry = new ChatEntry(
UUID.fromString(chat.getString("internal_id")),
chat.getString("id"),
chat.getString("name"),
chat.optString("image_url", ""),
chat.getString("type"),
chat.isNull("last_message_time") ? null : LocalDateTime.parse(chat.getString("last_message_time")),
chat.optBoolean("is_owner", false),
chat.optBoolean("is_admin", false)
);
chatList.add(entry);
}
Session.chatList = chatList;
System.out.println("✅ Chat list updated. Total: " + chatList.size());
} else {
System.out.println("⚠️ Response has no data object.");
}
} else {
if (response.has("message") && !response.isNull("message")) {
System.out.println("❌ Failed to refresh chat list: " + response.getString("message"));
} else {
System.out.println("❌ Failed to refresh chat list.");
}
}
} catch (Exception e) {
System.err.println("❌ Error during refreshChatList: " + e.getMessage());
e.printStackTrace();
}
}
public void createGroup() {
System.out.print("Enter group ID: ");
String groupId = scanner.nextLine();
String groupName = null;
while (groupName == null) {
System.out.print("Enter group name: ");
String input = scanner.nextLine();
if (!input.trim().isEmpty()) {
groupName = input;
} else {
System.out.println("Group name can't be empty.");
}
}
System.out.print("Enter image URL (optional): ");
String imageUrl = scanner.nextLine();
JSONObject req = new JSONObject();
req.put("action", "create_group");
req.put("user_id", Session.getUserUUID());
req.put("group_id", groupId);
req.put("group_name", groupName);
req.put("image_url", imageUrl.isBlank() ? JSONObject.NULL : imageUrl);
send(req);
}
public void createChannel() {
System.out.print("Enter channel ID: ");
String channelId = scanner.nextLine();
String channelName = null;
while (channelName == null) {
System.out.print("Enter channel name: ");
String input = scanner.nextLine();
if (!input.trim().isEmpty()) {
channelName = input;
} else {
System.out.println("Channel name can't be empty.");
}
}
System.out.print("Enter image URL (optional): ");
String imageUrl = scanner.nextLine();
JSONObject req = new JSONObject();
req.put("action", "create_channel");
req.put("user_id", Session.getUserUUID());
req.put("channel_id", channelId);
req.put("channel_name", channelName);
req.put("image_url", imageUrl.isBlank() ? JSONObject.NULL : imageUrl);
send(req);
}
public void addMember(UUID memberId){
JSONObject req = new JSONObject();
req.put("action", "add_member");
req.put("user_id", Session.currentUser.getString("user_id"));
//req.put("group/channel",)
req.put("member_id", memberId.toString());
send(req);
}
private void send(JSONObject request) {
try {
if (!request.has("action") || request.isNull("action")) {
System.err.println("❌ Invalid request: missing action.");
return;
}
String action = request.getString("action");
this.out.println(request.toString());
JSONObject response = null;
// منتظر بمون تا پاسخ واقعی (یعنی status داشته باشه) بیاد
while (true) {
JSONObject incoming = TelegramClient.responseQueue.take();
if (incoming.has("status")) {
response = incoming;
break;
} else {
// این یک پیام Real-Time است
handleRealTime(incoming); // ✅
}
}
if (response == null) {
System.out.println("⚠️ No usable response received.");
return;
}
if (response.has("message") && !response.isNull("message")) {
System.out.println("✅ Server Response: " + response.getString("message"));
}
String status = response.optString("status", "error");
if (!"success".equals(status) || !response.has("data") || response.isNull("data"))
return;
switch (action) {
case "login":
case "register":
Session.currentUser = response.getJSONObject("data");
JSONArray chatListJson = Session.currentUser.getJSONArray("chat_list");
List<ChatEntry> chatList = new ArrayList<>();
for (Object obj : chatListJson) {
JSONObject chat = (JSONObject) obj;
ChatEntry entry = new ChatEntry(
UUID.fromString(chat.getString("internal_id")),
chat.getString("id"),
chat.getString("name"),
chat.optString("image_url", ""),
chat.getString("type"),
chat.isNull("last_message_time") ? null : LocalDateTime.parse(chat.getString("last_message_time")),
chat.optBoolean("is_owner", false),
chat.optBoolean("is_admin", false)
);
chatList.add(entry);
}
Session.chatList = chatList;
break;
case "searchInUsers":
JSONArray result = response.getJSONObject("data").getJSONArray("results");
if (result.isEmpty()){
System.out.println("No results found.");
}
else{
System.out.println("Search Results:");
for (int i = 0 ; i < result.length(); i++){
JSONObject item = result.getJSONObject(i);
String type = item.getString("type");
if(type.equals("user")){
System.out.println((i + 1) + ". [" + type + "] "
+ item.getString("name") + " (ID: " + item.getString("id") + ")");
}
}
System.out.print("Select a result number to interact(0 for return): ");
int index = Integer.parseInt(scanner.nextLine()) - 1;
if (index < 0 || index >= result.length()) return;
JSONObject selected = result.getJSONObject(index);
String userId = selected.getString("id");
String uuid = selected.getString("uuid");
UUID memberId = UUID.fromString(uuid);
addMember(memberId);
}
break;
case "search" :
JSONArray results = response.getJSONObject("data").getJSONArray("results");
if (results.isEmpty()) {
System.out.println("No results found.");
} else {
System.out.println("\nSearch Results:");
for (int i = 0; i < results.length(); i++) {
JSONObject item = results.getJSONObject(i);
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") + ")");
} 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): ");
int index = Integer.parseInt(scanner.nextLine()) - 1;
if (index == -1) {
System.out.println("Exit...");
return;
}
if (index < -1 || index >= results.length()) return;
JSONObject selected = results.getJSONObject(index);
String type = selected.getString("type");
switch (type) {
case "user" -> {
String uuidStr = selected.getString("uuid");
UUID uuid = UUID.fromString(uuidStr);
System.out.println("🔍 Looking for chat with internal_id='" + uuid + "' type='private'");
ChatEntry existing = Session.chatList.stream()
.filter(c -> c.getId().equals(uuid) && c.getType().equals("private"))
.findFirst()
.orElse(null);
if (existing != null) {
openChat(existing);
} else {
System.out.println(" Trying to add contact...");
addContact(uuid);
refreshChatList();
System.out.println("🔄 Rechecking chat list...");
existing = Session.chatList.stream()
.filter(c -> c.getId().equals(uuid) && c.getType().equals("private"))
.findFirst()
.orElse(null);
if (existing != null) {
openChat(existing);
} else {
System.out.println("❌ Failed to open chat. Try again later.");
}
}
}
case "group", "channel" -> {
String uuidStr = selected.getString("uuid");
UUID uuid = UUID.fromString(uuidStr);
System.out.println("🔍 Looking for chat with internal_id='" + uuid + "' type='" + type + "'");
ChatEntry existing = Session.chatList.stream()
.filter(c -> c.getId().equals(uuid) && c.getType().equals(type))
.findFirst()
.orElse(null);
if (existing != null) {
openChat(existing);
} else {
System.out.println(" Trying to join " + type + "...");
joinGroupOrChannel(type, uuidStr);
refreshChatList();
System.out.println("🔄 Rechecking chat list...");
existing = Session.chatList.stream()
.filter(c -> c.getId().equals(uuid) && c.getType().equals(type))
.findFirst()
.orElse(null);
if (existing != null) {
openChat(existing);
} else {
System.out.println("❌ Failed to open " + type + ". Try again later.");
}
}
}
case "message" -> {
String receiverId = selected.getString("receiver_id");
String receiverType = selected.getString("receiver_type");
System.out.println("🔍 Looking for chat with displayId='" + receiverId + "' type='" + receiverType + "'");
ChatEntry chat = Session.chatList.stream()
.filter(c -> c.getDisplayId().equals(receiverId) && c.getType().equals(receiverType))
.findFirst()
.orElseGet(() -> fetchChatInfo(receiverId, receiverType));
openChat(chat);
}
default -> System.out.println("No interaction available for type: " + type);
}
}
break;
case "create_group":
case "create_channel":
if (response.has("data")) {
JSONObject chatJson = response.getJSONObject("data");
ChatEntry chat = new ChatEntry(
UUID.fromString(chatJson.getString("internal_id")),
chatJson.getString("id"),
chatJson.getString("name"),
chatJson.optString("image_url", ""),
chatJson.getString("type"),
null,
chatJson.optBoolean("is_owner", false),
chatJson.optBoolean("is_admin", false)
);
refreshChatList();
System.out.println("✅ Created and opening chat...");
refreshChatList();
openChat(chat);
}
break;
case "get_messages":
JSONArray messages = response.getJSONObject("data").getJSONArray("messages");
System.out.println("\n🔓 Messages fetched:");
System.out.println("─────────────────────────────────────────────");
for (int i = 0; i < messages.length(); i++) {
JSONObject m = messages.getJSONObject(i);
String senderId = m.getString("sender_id");
String content = m.getString("content");
String time = m.getString("send_at");
String label = senderId.equals(Session.currentUser.getString("internal_uuid")) ? "You" : "Other";
System.out.println("[" + time + "] " + label + ": " + content);
}
System.out.println("─────────────────────────────────────────────");
break;
case "logout":
Session.currentUser = null;
Session.chatList = null;
break;
}
} catch (Exception e) {
System.err.println("❌ Error during send(): " + e.getMessage());
e.printStackTrace();
}
}
public void userMenu(UUID internal_uuid) throws IOException {
while (true) {
if (Session.backToChatList) {
Session.backToChatList = false;
return;
}
System.out.println("\nUser Menu:");
System.out.println("1. Show chat list");
System.out.println("2. Search");
System.out.println("3. Create Channel");
System.out.println("4. Create group");
System.out.println("5. Logout");
System.out.print("Choose an option: ");
String choice = scanner.nextLine();
switch (choice) {
case "1" -> {
Session.inChatListMenu = true;
showChatListAndSelect();
Session.inChatListMenu = false;
}
case "2" -> search();
case "3" -> createChannel();
case "4" -> createGroup();
case "5" -> {
logout();
return;
}
default -> System.out.println("Invalid choice.");
}
}
}
public void showChatListAndSelect() {
List<ChatEntry> chatList = Session.getChatList();
if (chatList.isEmpty()) {
System.out.println("📭 You have no chats.");
return;
}
System.out.println("\nYour Chats:");
for (int i = 0; i < chatList.size(); i++) {
ChatEntry entry = chatList.get(i);
String last = entry.getLastMessageTime() == null ? "No messages yet" : entry.getLastMessageTime().toString();
System.out.printf("%d. [%s] %s - Last: %s\n", i + 1, entry.getType(), entry.getName(), last);
}
System.out.print("Select a chat by number: ");
int choice = Integer.parseInt(scanner.nextLine());
if (choice < 1 || choice > chatList.size()) {
System.out.println("❌ Invalid choice.");
return;
}
openChat(chatList.get(choice - 1));
}
private void openChat(ChatEntry chat) {
JSONObject req = new JSONObject();
req.put("action", "get_messages");
req.put("receiver_id", chat.getId());
req.put("receiver_type", chat.getType());
JSONObject res = sendWithResponse(req);
if (res == null || !res.getString("status").equals("success")) {
System.out.println("❌ Failed to fetch messages.");
return;
}
JSONArray messages = res.getJSONObject("data").getJSONArray("messages");
System.out.println("\n🔓 Messages fetched:");
System.out.println("─────────────────────────────────────────────");
for (int i = 0; i < messages.length(); i++) {
JSONObject m = messages.getJSONObject(i);
String senderId = m.getString("sender_id");
String content = m.getString("content");
String time = m.getString("send_at");
String label = senderId.equals(Session.currentUser.getString("internal_uuid")) ? "You" : "Other";
System.out.println("[" + time + "] " + label + ": " + content);
}
System.out.println("─────────────────────────────────────────────");
boolean stayInChat = true;
Session.currentChatId = chat.getId().toString();
Session.currentChatEntry = chat;
Session.currentChatType = chat.getType().toLowerCase();
Session.inChatMenu = true;
startMenuRefresherThread();
while (stayInChat) {
if (forceExitChat) {
System.out.println("⚠️ You have been removed from this chat or chat was deleted. Returning to chat list...");
forceExitChat = false;
break;
}
System.out.println("\n📍 Entered Chat:");
System.out.println("🔷 Name: " + chat.getName());
System.out.println("────────────────────────────────────────────");
switch (chat.getType().trim().toLowerCase()) {
case "private" -> stayInChat = showPrivateChatMenu(chat);
case "group" -> stayInChat = showGroupChatMenu(chat);
case "channel" -> stayInChat = showChannelChatMenu(chat);
default -> {
System.out.println("❗ Unknown chat type: " + chat.getType());
stayInChat = false;
}
}
}
Session.inChatMenu = false;
Session.currentChatId = null;
Session.currentChatEntry = null;
Session.currentChatType = null;
}
private boolean showPrivateChatMenu(ChatEntry chat) {
if (forceExitChat) {
forceExitChat = false;
System.out.println("🚪 Exiting chat due to real-time update.");
return false;
}
JSONObject req = new JSONObject();
req.put("action", "view_profile");
req.put("target_id", chat.getId()); // internal UUID
JSONObject res = sendWithResponse(req);
if (res.getString("status").equals("success")) {
JSONObject data = res.getJSONObject("data");
System.out.println("\n💬 Private Chat with: " + data.getString("profile_name"));
if (data.getBoolean("is_online")) {
System.out.println("✅ Status: Online");
} else {
System.out.println("📅 Last seen: " + data.getString("last_seen"));
}
System.out.println("────────────────────────────────────────────");
}
System.out.println("1. Send message");
System.out.println("2. Block/Unblock");
System.out.println("3. Delete chat (one-sided)");
System.out.println("4. Delete chat (both sides)");
System.out.println("5. View profile");
System.out.println("6. Back");
String input = scanner.nextLine();
switch (input) {
case "1" -> sendMessageTo(chat.getId(), "private");
case "2" -> toggleBlock(chat.getId());
case "3" -> {
deleteChat(chat.getId(), false);
return false;
}
case "4" -> {
deleteChat(chat.getId(), true);
return false;
}
case "5" -> {
JSONObject reqProfile = new JSONObject();
reqProfile.put("action", "view_profile");
reqProfile.put("target_id", chat.getId());
JSONObject resProfile = sendWithResponse(reqProfile);
if (resProfile.getString("status").equals("success")) {
JSONObject profile = resProfile.getJSONObject("data");
System.out.println("\n👤 Profile Info:");
System.out.println("🔷 Name: " + profile.optString("profile_name", "Unknown"));
System.out.println("📄 Bio: " + profile.optString("bio", "No bio set"));
System.out.println("🖼️ Image URL: " + profile.optString("image_url", "N/A"));
if (profile.getBoolean("is_online")) {
System.out.println("✅ Status: Online");
} else {
System.out.println("📅 Last seen: " + profile.optString("last_seen", "Unknown"));
}
System.out.println("────────────────────────────────────────────");
} else {
System.out.println("❌ Could not load profile.");
}
return true;
}
case "6" -> {
return false;
}
default -> System.out.println("Invalid choice.");
}
return true;
}
private JSONObject getGroupPermissions(UUID groupId) {
JSONObject req = new JSONObject();
req.put("action", "get_group_permissions");
req.put("group_id", groupId.toString());
JSONObject res = sendWithResponse(req);
if (res == null || !res.getString("status").equals("success")) {
return new JSONObject();
}
return res.getJSONObject("data");
}
private boolean showGroupChatMenu(ChatEntry chat) {
if (forceExitChat) {
forceExitChat = false;
System.out.println("🚪 Exiting chat due to real-time update.");
return false;
}
boolean isAdmin = chat.isAdmin();
boolean isOwner = chat.isOwner();
JSONObject perms = getGroupPermissions(chat.getId());
System.out.println("\n--- Group Chat Menu ---");
System.out.println("1. Send Message");
System.out.println("2. View Members");
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) {
System.out.println("3. Add Member");
}
if (isOwner || (isAdmin && perms.optBoolean("can_edit_group", false))) {
System.out.println("4. Edit Group Info");
}
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) {
System.out.println("5. Add Admin");
}
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) {
System.out.println("6. Remove Admin");
}
if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) {
System.out.println("7. Remove member");
}
if (isOwner) {
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("10. View Profile");
System.out.println("0. Back to Chat List");
String input = scanner.nextLine();
switch (input) {
case "1" -> sendMessageTo(chat.getId(), "group");
case "2" -> viewGroupMembers(chat.getId());
case "3" -> {
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false)))
searchEligibleUsers("group", chat.getId());
else System.out.println("❌ You don't have permission.");
}
case "4" -> {
if (isOwner || (isAdmin && perms.optBoolean("can_edit_group", false))) editGroupInfo(chat.getId());
else System.out.println("❌ You don't have permission.");
}
case "5" -> {
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) addAdminToGroup(chat.getId());
else System.out.println("❌ You don't have permission.");
}
case "6" -> {
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) removeAdminFromGroup(chat.getId());
else System.out.println("❌ You don't have permission.");
}
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 "9" -> {
if (isOwner) {
transferOwnershipAndLeave(chat.getId());
} else {
leaveChat(chat.getId(), "group");
// refreshChatList();
}
return false;
}
case "10" ->{
GroupInfo(chat.getId());
}
case "0" -> {
return false;
}
default -> System.out.println("Invalid choice.");
}
return true;
}
private boolean showChannelChatMenu(ChatEntry chat) {
if (forceExitChat) {
forceExitChat = false;
System.out.println("🚪 Exiting chat due to real-time update.");
return false;
}
chat = fetchChatInfo(chat.getId().toString(), chat.getType());
boolean isAdmin = chat.isAdmin();
boolean isOwner = chat.isOwner();
JSONObject perms = getChannelPermissions(chat.getId());
System.out.println("\n--- Channel Menu ---");
if (isOwner || (isAdmin && perms.optBoolean("can_post", false))) {
System.out.println("1. Send Post");
}
if (isOwner || isAdmin) {
System.out.println("2. View Subscribers");
}
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) {
System.out.println("3. Add Subscriber");
}
if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) {
System.out.println("4. Remove Subscriber");
}
if (isOwner || (isAdmin && perms.optBoolean("can_edit_channel", false))) {
System.out.println("5. Edit Channel Info");
}
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) {
System.out.println("6. Add Admin");
}
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) {
System.out.println("7. Remove Admin");
}
if (isOwner) {
System.out.println("8. Delete Channel");
System.out.println("9. Leave Channel (Transfer ownership required)");
} else {
System.out.println("8. Leave Channel");
}
System.out.println("10. View Profile");
System.out.println("0. Back to Chat List");
String input = scanner.nextLine();
switch (input) {
case "1" -> {
if (isOwner || (isAdmin && perms.optBoolean("can_post", false))) {
sendMessageTo(chat.getId(), "channel");
} else {
System.out.println("❌ You don't have permission to post.");
}
}
case "2" -> {
if (isOwner || isAdmin) {
viewChannelSubscribers(chat.getId());
} else {
System.out.println("❌ You don't have permission to view subscribers.");
}
}
case "3" -> {
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) {
searchEligibleUsers("channel", chat.getId());
} else {
System.out.println("❌ You don't have permission to add subscribers.");
}
}
case "4" -> {
if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) {
removeSubscriberFromChannel(chat.getId());
} else {
System.out.println("❌ You don't have permission to remove subscribers.");
}
}
case "5" -> {
if (isOwner || (isAdmin && perms.optBoolean("can_edit_channel", false))) {
editChannelInfo(chat.getId());
} else {
System.out.println("❌ You don't have permission to edit channel info.");
}
}
case "6" -> {
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) {
addAdminToChannel(chat.getId());
} else {
System.out.println("❌ You don't have permission to add admins.");
}
}
case "7" -> {
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) {
removeAdminFromChannel(chat.getId());
} else {
System.out.println("❌ You don't have permission to remove admins.");
}
}
case "8" -> {
if (isOwner) {
deleteChannel(chat.getId());
return false;
} else {
leaveChat(chat.getId(), "channel");
return false;
}
}
case "9" -> {
if (isOwner) {
transferChannelOwnershipAndLeave(chat.getId());
return false;
} else {
System.out.println("❌ You don't have permission.");
}
}
case "10"->{
ChannelInfo(chat.getId());
}
case "0" -> {
return false;
}
default -> System.out.println("Invalid choice.");
}
return true;
}
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) {
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<JSONObject> 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"));
}
private void addAdminToChannel(UUID channelId) {
JSONObject req = new JSONObject();
req.put("action", "view_channel_subscribers");
req.put("channel_id", channelId.toString());
JSONObject res = sendWithResponse(req);
if (res == null || !res.getString("status").equals("success")) {
System.out.println("❌ Failed to fetch subscribers.");
return;
}
JSONArray subscribers = res.getJSONObject("data").getJSONArray("subscribers");
List<JSONObject> eligible = new ArrayList<>();
System.out.println("\n--- Subscribers List ---");
for (int i = 0; i < subscribers.length(); i++) {
JSONObject s = subscribers.getJSONObject(i);
String role = s.getString("role");
String profileName = s.getString("profile_name");
String userId = s.getString("user_id");
if (role.equals("subscriber")) {
eligible.add(s);
System.out.printf("%d. %s (%s)\n", eligible.size(), profileName, userId);
}
}
if (eligible.isEmpty()) {
System.out.println("⚠️ No eligible subscribers to promote.");
return;
}
System.out.print("Select a subscriber to promote to admin: ");
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 permissions = new JSONObject();
System.out.print("Can post? (true/false): ");
permissions.put("can_post", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can edit channel info? (true/false): ");
permissions.put("can_edit_channel", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can add members? (true/false): ");
permissions.put("can_add_members", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can remove members? (true/false): ");
permissions.put("can_remove_members", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can add admins? (true/false): ");
permissions.put("can_add_admins", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can remove admins? (true/false): ");
permissions.put("can_remove_admins", Boolean.parseBoolean(scanner.nextLine()));
JSONObject promoteReq = new JSONObject();
promoteReq.put("action", "add_admin_to_channel");
promoteReq.put("channel_id", channelId.toString());
promoteReq.put("target_user_id", targetInternalUUID);
promoteReq.put("permissions", permissions);
JSONObject promoteRes = sendWithResponse(promoteReq);
if (promoteRes != null)
System.out.println(promoteRes.getString("message"));
}
private void addAdminToGroup(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<JSONObject> eligible = new ArrayList<>();
System.out.println("\n--- Members List ---");
for (int i = 0; i < members.length(); i++) {
JSONObject m = members.getJSONObject(i);
if (m.getString("role").equals("member")) {
eligible.add(m);
System.out.println((eligible.size()) + ". " + m.getString("profile_name") + " (" + m.getString("user_id") + ")");
}
}
if (eligible.isEmpty()) {
System.out.println("⚠️ No eligible members.");
return;
}
System.out.print("Select a member to promote: ");
int choice = Integer.parseInt(scanner.nextLine()) - 1;
if (choice < 0 || choice >= eligible.size()) {
System.out.println("❌ Invalid selection.");
return;
}
JSONObject selected = eligible.get(choice);
String targetInternalUUID = selected.getString("internal_uuid"); // دقت کن internal_uuid
JSONObject permissions = new JSONObject();
System.out.print("Can add members? (true/false): ");
permissions.put("can_add_members", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can remove members? (true/false): ");
permissions.put("can_remove_members", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can add admins? (true/false): ");
permissions.put("can_add_admins", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can remove admins? (true/false): ");
permissions.put("can_remove_admins", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can edit group info? (true/false): ");
permissions.put("can_edit_group", Boolean.parseBoolean(scanner.nextLine()));
JSONObject promoteReq = new JSONObject();
promoteReq.put("action", "add_admin_to_group");
promoteReq.put("group_id", groupId.toString());
promoteReq.put("user_id", targetInternalUUID); // ارسال internal_uuid واقعی
promoteReq.put("permissions", permissions);
JSONObject promoteRes = sendWithResponse(promoteReq);
if (promoteRes != null)
System.out.println(promoteRes.getString("message"));
}
private void viewGroupMembers(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) return;
if (res.getString("status").equals("success")) {
JSONArray members = res.getJSONObject("data").getJSONArray("members");
System.out.println("\n--- Group Members ---");
for (int i = 0; i < members.length(); i++) {
JSONObject m = members.getJSONObject(i);
String name = m.getString("profile_name");
String userId = m.getString("user_id");
String role = m.getString("role");
System.out.printf("- %s (ID: %s) [%s]\n", name, userId, role);
}
} else {
System.out.println("❌ Failed to fetch members.");
}
}
private void removeSubscriberFromChannel(UUID channelId) {
JSONObject req = new JSONObject();
req.put("action", "view_channel_subscribers");
req.put("channel_id", channelId.toString());
JSONObject res = sendWithResponse(req);
if (res == null || !res.getString("status").equals("success")) {
System.out.println("❌ Failed to fetch subscribers.");
return;
}
JSONArray subscribers = res.getJSONObject("data").getJSONArray("subscribers");
List<JSONObject> eligible = new ArrayList<>();
System.out.println("\n--- Subscribers List ---");
for (int i = 0; i < subscribers.length(); i++) {
JSONObject s = subscribers.getJSONObject(i);
String role = s.getString("role");
String profileName = s.getString("profile_name");
String userId = s.getString("user_id");
if (role.equals("owner")) continue;
eligible.add(s);
System.out.println((eligible.size()) + ". " + profileName + " (" + userId + ") [" + role + "]");
}
if (eligible.isEmpty()) {
System.out.println("⚠️ No removable subscribers.");
return;
}
System.out.print("Select a subscriber 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_subscriber_from_channel");
removeReq.put("channel_id", channelId.toString());
removeReq.put("user_id", targetInternalUUID);
JSONObject removeRes = sendWithResponse(removeReq);
if (removeRes != null)
System.out.println(removeRes.getString("message"));
}
private void transferChannelOwnershipAndLeave(UUID channelId) {
JSONObject req = new JSONObject();
req.put("action", "view_channel_admins");
req.put("channel_id", channelId.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("\n--- 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("internal_id");
JSONObject promoteReq = new JSONObject();
promoteReq.put("action", "transfer_channel_ownership");
promoteReq.put("channel_id", channelId.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(channelId, "channel");
}
private void deleteChannel(UUID channelId) {
System.out.print("Are you sure you want to delete the channel? (yes/no): ");
String confirm = scanner.nextLine().trim().toLowerCase();
if (!confirm.equals("yes")) {
System.out.println("❌ Delete cancelled.");
return;
}
JSONObject req = new JSONObject();
req.put("action", "delete_channel");
req.put("channel_id", channelId.toString());
JSONObject res = sendWithResponse(req);
if (res != null && res.getString("status").equals("success")) {
System.out.println("✅ Channel deleted successfully.");
refreshChatList();
} else {
System.out.println("❌ Failed to delete channel.");
}
}
private void deleteGroup(UUID groupId) {
System.out.print("Are you sure you want to delete the group? (yes/no): ");
String confirm = scanner.nextLine().trim().toLowerCase();
if (!confirm.equals("yes")) {
System.out.println("❌ Delete cancelled.");
return;
}
JSONObject req = new JSONObject();
req.put("action", "delete_group");
req.put("group_id", groupId.toString());
JSONObject res = sendWithResponse(req);
if (res != null && res.getString("status").equals("success")) {
System.out.println("✅ Group deleted successfully.");
refreshChatList();
} else {
System.out.println("❌ Failed to delete group.");
}
}
private void deleteChat(UUID targetId, boolean both) {
JSONObject req = new JSONObject();
req.put("action", "delete_private_chat");
req.put("target_id", targetId.toString());
req.put("both", both);
send(req);
JSONObject resp = sendWithResponse(req);
if (resp.getString("status").equals("success")) {
System.out.println("✅ Chat deleted successfully.");
} else {
System.out.println("⚠️ Failed to delete chat.");
}
}
private void toggleBlock(UUID userId) {
JSONObject req = new JSONObject();
req.put("action", "toggle_block");
req.put("user_id", Session.getUserUUID());
req.put("target_id", userId.toString());
JSONObject res = sendWithResponse(req);
if (res == null) return;
String status = res.getString("status");
String message = res.getString("message");
if (status.equals("success")) {
System.out.println("🔒 " + message);
} else {
System.out.println("❌ " + message);
}
}
private void leaveChat(UUID id, String type) {
JSONObject req = new JSONObject();
req.put("action", "leave_chat");
req.put("user_id", Session.getUserUUID());
req.put("chat_id", id.toString());
req.put("chat_type", type);
JSONObject res = sendWithResponse(req);
if (res == null) return;
String status = res.getString("status");
String message = res.getString("message");
if (status.equals("success")) {
System.out.println("✅ You left the chat.");
} else {
System.out.println("❌ " + message);
}
}
private void removeAdminFromGroup(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");
List<JSONObject> eligible = new ArrayList<>();
System.out.println("\n--- Admins List ---");
for (int i = 0; i < admins.length(); i++) {
JSONObject admin = admins.getJSONObject(i);
String role = admin.getString("role");
String profileName = admin.getString("profile_name");
String userId = admin.getString("user_id");
if (!role.equals("owner")) {
eligible.add(admin);
System.out.printf("%d. %s (%s)\n", eligible.size(), profileName, userId);
}
}
if (eligible.isEmpty()) {
System.out.println("⚠️ No removable admins.");
return;
}
System.out.print("Select an admin 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("user_id");
JSONObject removeReq = new JSONObject();
removeReq.put("action", "remove_admin_from_group");
removeReq.put("group_id", groupId.toString());
removeReq.put("target_user_id", targetInternalUUID);
JSONObject removeRes = sendWithResponse(removeReq);
if (removeRes != null)
System.out.println(removeRes.getString("message"));
}
private void removeAdminFromChannel(UUID channelId) {
JSONObject req = new JSONObject();
req.put("action", "view_channel_admins");
req.put("channel_id", channelId.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");
List<JSONObject> eligible = new ArrayList<>();
System.out.println("\n--- Admins List ---");
for (int i = 0; i < admins.length(); i++) {
JSONObject admin = admins.getJSONObject(i);
String role = admin.getString("role");
String profileName = admin.getString("profile_name");
String userId = admin.getString("user_id");
if (!role.equals("owner")) {
eligible.add(admin);
System.out.printf("%d. %s (%s)\n", eligible.size(), profileName, userId);
}
}
if (eligible.isEmpty()) {
System.out.println("⚠️ No removable admins.");
return;
}
System.out.print("Select an admin 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_admin_from_channel");
removeReq.put("channel_id", channelId.toString());
removeReq.put("target_user_id", targetInternalUUID);
JSONObject removeRes = sendWithResponse(removeReq);
if (removeRes != null)
System.out.println(removeRes.getString("message"));
}
private void sendMessageTo(UUID id, String type) {
System.out.print("Enter message: ");
String text = scanner.nextLine().trim();
if (text.isEmpty()) {
System.out.println("Message cannot be empty.");
return;
}
JSONObject req = new JSONObject();
req.put("action", "send_message");
req.put("sender_id", Session.getUserUUID());
req.put("receiver_id", id.toString());
req.put("receiver_type", type);
req.put("text", text);
JSONObject res = sendWithResponse(req);
if (res == null) return;
if (res.getBoolean("success")) {
System.out.println("✅ Message sent.");
} else {
System.out.println("❌ Failed to send message.");
}
}
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.toString());
JSONObject res = sendWithResponse(req);
if (res != null) {
System.out.println(res.getString("message"));
}
}
private void addSubscriberToChannel(UUID channelId, UUID targetUserId) {
JSONObject req = new JSONObject();
req.put("action", "add_subscriber_to_channel");
req.put("channel_id", channelId.toString());
req.put("user_id", targetUserId.toString());
JSONObject res = sendWithResponse(req);
if (res == null) return;
if (res.getString("status").equals("success")) {
System.out.println("✅ Subscriber added successfully.");
} else {
System.out.println("❌ " + res.getString("message"));
}
}
private void GroupInfo(UUID groupId){
JSONObject req = new JSONObject();
req.put("action", "get_chat_info");
req.put("receiver_id", groupId.toString());
req.put("receiver_type", "group");
JSONObject res = sendWithResponse(req);
if (res == null || !res.getString("status").equals("success")) {
System.out.println("❌ Failed to fetch group info.");
return;
}
JSONObject data = res.getJSONObject("data");
String currentId = data.getString("id");
String currentName = data.getString("name");
String currentDesc = data.optString("description", null);
String currentImage = data.optString("image_url", null);
System.out.println("\n--- Group Info ---");
System.out.println("1. Group ID: " + currentId);
System.out.println("2. Name: " + currentName);
System.out.println("3. Description: " + currentDesc);
System.out.println("4. Image URL: " + currentImage);
System.out.println("────────────────────────────────────────────");
}
private void editGroupInfo(UUID groupId) {
JSONObject req = new JSONObject();
req.put("action", "get_chat_info");
req.put("receiver_id", groupId.toString());
req.put("receiver_type", "group");
JSONObject res = sendWithResponse(req);
if (res == null || !res.getString("status").equals("success")) {
System.out.println("❌ Failed to fetch group info.");
return;
}
JSONObject data = res.getJSONObject("data");
String currentId = data.getString("id");
String currentName = data.getString("name");
String currentDesc = data.optString("description", null);
String currentImage = data.optString("image_url", null);
System.out.println("\n--- Current Group Info ---");
System.out.println("1. Group ID: " + currentId);
System.out.println("2. Name: " + currentName);
System.out.println("3. Description: " + currentDesc);
System.out.println("4. Image URL: " + currentImage);
System.out.println("0. Cancel");
System.out.print("Select the field you want to edit (0-4): ");
String choice = scanner.nextLine().trim();
String newGroupId = currentId;
String newName = currentName;
String newDesc = currentDesc;
String newImage = currentImage;
switch (choice) {
case "1" -> {
System.out.print("Enter new Group ID: ");
newGroupId = scanner.nextLine().trim();
}
case "2" -> {
System.out.print("Enter new Group Name: ");
newName = scanner.nextLine().trim();
}
case "3" -> {
System.out.print("Enter new Description: ");
newDesc = scanner.nextLine().trim();
}
case "4" -> {
System.out.print("Enter new Image URL: ");
newImage = scanner.nextLine().trim();
}
case "0" -> {
System.out.println("Cancelled.");
return;
}
default -> {
System.out.println("Invalid choice.");
return;
}
}
JSONObject editReq = new JSONObject();
editReq.put("action", "edit_group_info");
editReq.put("group_id", groupId.toString()); // internal_uuid
editReq.put("new_group_id", newGroupId);
editReq.put("name", newName);
editReq.put("description", newDesc);
editReq.put("image_url", newImage);
JSONObject editRes = sendWithResponse(editReq);
if (editRes != null)
System.out.println(editRes.getString("message"));
}
private void viewChannelSubscribers(UUID channelId) {
JSONObject req = new JSONObject();
req.put("action", "view_channel_subscribers");
req.put("channel_id", channelId.toString());
JSONObject res = sendWithResponse(req);
if (res == null) return;
if (res.getString("status").equals("success")) {
JSONObject data = res.getJSONObject("data");
JSONArray subs = data.getJSONArray("subscribers");
System.out.println("--- Subscribers ---");
for (int i = 0; i < subs.length(); i++) {
JSONObject s = subs.getJSONObject(i);
System.out.println("- " + s.getString("profile_name"));
}
} else {
System.out.println("❌ Failed to load subscribers.");
}
}
private void ChannelInfo(UUID channelInternalId){
JSONObject req = new JSONObject();
req.put("action", "get_chat_info");
req.put("receiver_id", channelInternalId.toString());
req.put("receiver_type", "channel");
JSONObject res = sendWithResponse(req);
if (res == null || !res.getString("status").equals("success")) {
System.out.println("❌ Failed to fetch channel info.");
return;
}
JSONObject data = res.getJSONObject("data");
String currentId = data.getString("id");
String currentName = data.getString("name");
String currentDesc = data.optString("description", null);
String currentImage = data.optString("image_url", null);
System.out.println("\n--- Channel Info ---");
System.out.println("1. Channel ID: " + currentId);
System.out.println("2. Name: " + currentName);
System.out.println("3. Description: " + currentDesc);
System.out.println("4. Image URL: " + currentImage);
System.out.println("────────────────────────────────────────────");
}
private void editChannelInfo(UUID channelInternalId) {
JSONObject req = new JSONObject();
req.put("action", "get_chat_info");
req.put("receiver_id", channelInternalId.toString());
req.put("receiver_type", "channel");
JSONObject res = sendWithResponse(req);
if (res == null || !res.getString("status").equals("success")) {
System.out.println("❌ Failed to fetch channel info.");
return;
}
JSONObject data = res.getJSONObject("data");
String currentId = data.getString("id");
String currentName = data.getString("name");
String currentDesc = data.optString("description", null);
String currentImage = data.optString("image_url", null);
System.out.println("\n--- Current Channel Info ---");
System.out.println("1. Channel ID: " + currentId);
System.out.println("2. Name: " + currentName);
System.out.println("3. Description: " + currentDesc);
System.out.println("4. Image URL: " + currentImage);
System.out.println("0. Cancel");
System.out.print("Select the field you want to edit (0-4): ");
String choice = scanner.nextLine().trim();
String newChannelId = currentId;
String newName = currentName;
String newDesc = currentDesc;
String newImage = currentImage;
switch (choice) {
case "1" -> {
System.out.print("Enter new Channel ID: ");
newChannelId = scanner.nextLine().trim();
}
case "2" -> {
System.out.print("Enter new Channel Name: ");
newName = scanner.nextLine().trim();
}
case "3" -> {
System.out.print("Enter new Description: ");
newDesc = scanner.nextLine().trim();
}
case "4" -> {
System.out.print("Enter new Image URL: ");
newImage = scanner.nextLine().trim();
}
case "0" -> {
System.out.println("Cancelled.");
return;
}
default -> {
System.out.println("Invalid choice.");
return;
}
}
JSONObject editReq = new JSONObject();
editReq.put("action", "edit_channel_info");
editReq.put("channel_id", channelInternalId.toString()); // internal_uuid
editReq.put("new_channel_id", newChannelId);
editReq.put("name", newName);
editReq.put("description", newDesc);
editReq.put("image_url", newImage);
JSONObject editRes = sendWithResponse(editReq);
if (editRes != null)
System.out.println(editRes.getString("message"));
}
private JSONObject getResponse() {
try {
return TelegramClient.responseQueue.take();
} catch (InterruptedException e) {
throw new RuntimeException("Failed to get server response");
}
}
public void logout() {
if (Session.currentUser != null && Session.currentUser.has("user_id")) {
JSONObject request = new JSONObject();
request.put("action", "logout");
request.put("user_id", Session.currentUser.getString("internal_uuid"));
send(request);
Session.currentUser = null;
Session.chatList = null;
} else {
System.out.println("Not logged in.");
}
}
public void addAdminToEntity(String type, UUID entityId) {
System.out.print("Enter user ID to promote to admin: ");
String targetUserId = scanner.nextLine().trim();
JSONObject permissions = new JSONObject();
System.out.print("Can send messages? (true/false): ");
permissions.put("can_send", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can edit info? (true/false): ");
permissions.put("can_edit", Boolean.parseBoolean(scanner.nextLine()));
JSONObject req = new JSONObject();
req.put("action", type.equals("group") ? "add_admin_to_group" : "add_admin_to_channel");
req.put(type + "_id", entityId.toString());
req.put("target_user_id", targetUserId);
req.put("permissions", permissions);
send(req);
JSONObject res = getResponse();
System.out.println(res.getString("message"));
}
private void editChannelAdminPermissions(UUID channelId) {
System.out.print("Enter user_id of the admin to edit: ");
String userId = scanner.nextLine().trim();
JSONObject permissions = new JSONObject();
System.out.print("Can post? (true/false): ");
permissions.put("can_post", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can edit channel info? (true/false): ");
permissions.put("can_edit_channel", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can add members? (true/false): ");
permissions.put("can_add_members", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can remove members? (true/false): ");
permissions.put("can_remove_members", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can add admins? (true/false): ");
permissions.put("can_add_admins", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can remove admins? (true/false): ");
permissions.put("can_remove_admins", Boolean.parseBoolean(scanner.nextLine()));
JSONObject req = new JSONObject();
req.put("action", "edit_channel_admin_permissions");
req.put("channel_id", channelId.toString());
req.put("user_id", userId);
req.put("permissions", permissions);
JSONObject res = sendWithResponse(req);
if (res != null)
System.out.println(res.getString("message"));
}
private void viewChannelAdmins(UUID channelId) {
JSONObject req = new JSONObject();
req.put("action", "view_channel_admins");
req.put("channel_id", channelId.toString());
JSONObject res = sendWithResponse(req);
if (res == null) return;
if (res.getString("status").equals("success")) {
JSONArray admins = res.getJSONObject("data").getJSONArray("admins");
System.out.println("\n--- Channel Admins ---");
for (int i = 0; i < admins.length(); i++) {
JSONObject a = admins.getJSONObject(i);
System.out.printf("- %s (%s) [%s]\n",
a.getString("profile_name"),
a.getString("user_id"),
a.getString("role"));
}
} else {
System.out.println("❌ Failed to fetch admins.");
}
}
private JSONObject getChannelPermissions(UUID channelId) {
JSONObject req = new JSONObject();
req.put("action", "get_channel_permissions");
req.put("channel_id", channelId.toString());
JSONObject res = sendWithResponse(req);
if (res == null || !res.getString("status").equals("success")) {
return new JSONObject();
}
return res.getJSONObject("data");
}
public void editAdminPermissions(String type, UUID entityId) {
System.out.print("Enter user ID of the admin to edit: ");
String targetUserId = scanner.nextLine().trim();
JSONObject permissions = new JSONObject();
System.out.print("Can send messages? (true/false): ");
permissions.put("can_send", Boolean.parseBoolean(scanner.nextLine()));
System.out.print("Can edit info? (true/false): ");
permissions.put("can_edit", Boolean.parseBoolean(scanner.nextLine()));
JSONObject req = new JSONObject();
req.put("action", type.equals("group") ? "edit_group_admin_permissions" : "edit_channel_admin_permissions");
req.put(type + "_id", entityId.toString());
req.put("target_user_id", targetUserId);
req.put("permissions", permissions);
send(req);
JSONObject res = getResponse();
System.out.println(res.getString("message"));
}
public void viewAdmins(String type, UUID entityId) {
JSONObject req = new JSONObject();
req.put("action", type.equals("group") ? "view_group_admins" : "view_channel_admins");
req.put(type + "_id", entityId.toString());
send(req);
JSONObject res = getResponse();
if (res.getString("status").equals("success")) {
JSONArray admins = res.getJSONObject("data").getJSONArray("admins");
System.out.println("📋 Admins in this " + type + ":");
for (int i = 0; i < admins.length(); i++) {
JSONObject admin = admins.getJSONObject(i);
System.out.printf("- %s (%s)\n", admin.getString("name"), admin.getString("role"));
}
} else {
System.out.println("❌ " + res.getString("message"));
}
}
public static JSONObject sendWithResponse(JSONObject request) {
try {
if (!request.has("action") || request.isNull("action")) {
System.err.println("❌ Invalid request: missing action.");
return null;
}
String requestId = UUID.randomUUID().toString();
request.put("request_id", requestId);
BlockingQueue<JSONObject> queue = new LinkedBlockingQueue<>();
TelegramClient.pendingResponses.put(requestId, queue);
TelegramClient.getInstance().getOut().println(request.toString());
// Wait for response
JSONObject response = queue.take();
TelegramClient.pendingResponses.remove(requestId);
if (response == null) {
System.out.println("⚠️ No response received.");
return null;
}
System.out.println("✅ Server Response: " + response.getString("message"));
return response;
} catch (Exception e) {
System.err.println("❌ Error during sendWithResponse(): " + e.getMessage());
e.printStackTrace();
return null;
}
}
public static void requestChatList() {
JSONObject req = new JSONObject();
req.put("action", "get_chat_list");
req.put("user_id", Session.getUserUUID());
JSONObject res = sendWithResponse(req);
if (res.getString("status").equals("success")) {
JSONArray chats = res.getJSONObject("data").getJSONArray("chat_list");
Session.updateChatList(chats);
System.out.println("✅ Chat list updated.");
} else {
System.out.println("❌ Failed to update chat list.");
}
}
public static void requestChatInfo(String chatId, String chatType) throws IOException {
JSONObject req = new JSONObject();
req.put("action", "get_chat_info");
req.put("receiver_id", chatId);
req.put("receiver_type", chatType);
TelegramClient.send(req);
}
public static void displayChatList() {
if (Session.chatList == null || Session.chatList.isEmpty()) {
System.out.println("\n📭 No chats available.");
return;
}
System.out.println("\n💬 Your Chats:");
int index = 1;
for (ChatEntry chat : Session.chatList) {
System.out.printf("%d. [%s] %s (%s)\n", index++, chat.getType(), chat.getName(), chat.getDisplayId());
}
}
public static class ChatStateMonitor implements Runnable {
private final PrintWriter out;
public ChatStateMonitor(PrintWriter out) {
this.out = out;
}
@Override
public void run() {
while (true) {
try {
if (forceExitChat) {
System.out.println("🚪 You were removed from the chat. Returning to chat list...");
forceExitChat = false;
Session.backToChatList = true;
}
if (Session.forceRefreshChatList) {
Session.forceRefreshChatList = false;
System.out.println("🔁 Refresh triggered by real-time event.");
ActionHandler.requestChatList();
if (Session.inChatListMenu) {
System.out.println("\n📬 Updated Chat List:");
ActionHandler.displayChatList(); // این متدی باشه که چت‌ها رو نمایش بده
System.out.print("Select a chat by number: ");
}
}
Thread.sleep(300); // جلوگیری از مصرف بی‌مورد CPU
} catch (Exception e) {
System.out.println("❌ ChatStateMonitor crashed: " + e.getMessage());
}
}
}
}
public static class CurrentChatMenuRefresher implements Runnable {
private final ActionHandler handler;
public CurrentChatMenuRefresher(ActionHandler handler) {
this.handler = handler;
}
@Override
public void run() {
System.out.println("🔁 Menu refresher thread running...");
while (true) {
try {
if (Session.refreshCurrentChatMenu && Session.inChatMenu && Session.currentChatId != null) {
System.out.println("🔁 [Refresher] Refresh requested. Searching for chat...");
// جستجو در لیست چت‌ها با استفاده از currentChatId
ChatEntry chat = Session.chatList.stream()
.filter(e -> e.getId().toString().equals(Session.currentChatId))
.findFirst()
.orElse(null);
if (chat != null) {
Session.currentChatEntry = chat;
Session.refreshCurrentChatMenu = false;
String type = chat.getType().toLowerCase();
System.out.println("\n🔁 Your permissions have changed. Menu updated:");
if (type.equals("group")) {
handler.printGroupMenuOnly(chat);
} else if (type.equals("channel")) {
handler.printChannelMenuOnly(chat);
}
System.out.print("Select an option: ");
} else {
System.out.println("⚠️ No matching chat found for ID: " + Session.currentChatId);
}
}
Thread.sleep(200);
} catch (Exception e) {
System.out.println("❌ CurrentChatMenuRefresher crashed: " + e.getMessage());
e.printStackTrace();
}
}
}
}
public void printGroupMenuOnly(ChatEntry chat) {
boolean isAdmin = chat.isAdmin();
boolean isOwner = chat.isOwner();
JSONObject perms = getGroupPermissions(chat.getId());
System.out.println("\n--- Group Chat Menu (Auto-refreshed) ---");
System.out.println("1. Send Message");
System.out.println("2. View Members");
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) {
System.out.println("3. Add Member");
}
if (isOwner || (isAdmin && perms.optBoolean("can_edit_group", false))) {
System.out.println("4. Edit Group Info");
}
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) {
System.out.println("5. Add Admin");
}
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) {
System.out.println("6. Remove Admin");
}
if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) {
System.out.println("7. Remove member");
}
if (isOwner) {
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("0. Back to Chat List");
}
public void printChannelMenuOnly(ChatEntry chat) {
boolean isAdmin = chat.isAdmin();
boolean isOwner = chat.isOwner();
JSONObject perms = getChannelPermissions(chat.getId());
System.out.println("\n--- Channel Menu (Auto-refreshed) ---");
if (isOwner || (isAdmin && perms.optBoolean("can_post", false))) {
System.out.println("1. Send Post");
}
if (isOwner || isAdmin) {
System.out.println("2. View Subscribers");
}
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) {
System.out.println("3. Add Subscriber");
}
if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) {
System.out.println("4. Remove Subscriber");
}
if (isOwner || (isAdmin && perms.optBoolean("can_edit_channel", false))) {
System.out.println("5. Edit Channel Info");
}
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) {
System.out.println("6. Add Admin");
}
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) {
System.out.println("7. Remove Admin");
}
if (isOwner) {
System.out.println("8. Delete Channel");
System.out.println("9. Leave Channel (Transfer ownership required)");
} else {
System.out.println("8. Leave Channel");
}
System.out.println("0. Back to Chat List");
}
public static void requestPermissions(String chatId, String chatType) {
JSONObject permissionReq = new JSONObject();
permissionReq.put("action", "get_permissions");
permissionReq.put("receiver_id", chatId);
permissionReq.put("receiver_type", chatType);
TelegramClient.send(permissionReq);
}
public void refreshCurrentChat() {
switch (Session.currentChatType.toLowerCase()) {
case "group" -> showGroupChatMenu(Session.currentChatEntry);
case "channel" -> showChannelChatMenu(Session.currentChatEntry);
}
}
private void startMenuRefresherThread() {
Thread refresher = new Thread(() -> {
System.out.println("🟡 Refresher tick. refreshCurrentChatMenu = " + Session.refreshCurrentChatMenu);
while (true) {
try {
Thread.sleep(500);
if (Session.refreshCurrentChatMenu) {
Session.refreshCurrentChatMenu = false;
if (Session.currentChatEntry == null) {
System.out.println("⚠️ currentChatEntry is null. Skipping...");
continue; // ❗ اینجا بجای return باید continue باشه
}
switch (Session.currentChatEntry.getType()) {
case "group" -> showGroupChatMenu(Session.currentChatEntry);
case "channel" -> showChannelChatMenu(Session.currentChatEntry);
}
}
} catch (Exception ignored) {}
}
});
refresher.setDaemon(true);
refresher.start();
}
}