Merge branch 'develop' into SendMessage
# Conflicts: # src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java # src/main/java/org/to/telegramfinalproject/Database/MessageDatabase.java # src/main/java/org/to/telegramfinalproject/Models/ContactEntry.java # src/main/java/org/to/telegramfinalproject/Models/Message.java
This commit is contained in:
@@ -20,7 +20,7 @@ public class AuthService {
|
||||
} else {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
password = PasswordHashing.hash(password);
|
||||
User user = new User(user_id, uuid, username, password, profile_name);
|
||||
User user = new User(user_id, uuid, username, password, profile_name, "", "");
|
||||
return this.userDb.save(user);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.to.telegramfinalproject.Server;
|
||||
|
||||
import javafx.geometry.Side;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.to.telegramfinalproject.Database.*;
|
||||
@@ -118,6 +119,7 @@ public class ClientHandler implements Runnable {
|
||||
|
||||
c.put("profile_name", target.getProfile_name());
|
||||
c.put("image_url", target.getImage_url());
|
||||
c.put("last_seen", Contact.getLast_seen());
|
||||
|
||||
contactList.put(c);
|
||||
}
|
||||
@@ -182,6 +184,10 @@ public class ClientHandler implements Runnable {
|
||||
);
|
||||
entry.setOtherUserId(otherId);
|
||||
|
||||
if (currentUser.getInternal_uuid() == otherId) {
|
||||
entry.setSavedMessages(true);
|
||||
}
|
||||
|
||||
if (archivedChatIds.contains(chat.getChat_id())) {
|
||||
archivedChatList.add(entry);
|
||||
chatList.add(entry);
|
||||
@@ -718,6 +724,8 @@ public class ClientHandler implements Runnable {
|
||||
|
||||
LocalDateTime lastMessageTime = MessageDatabase.getLastMessageTime(chat.getChat_id(), "private");
|
||||
|
||||
boolean isSavedMessages = chat.getUser1_id().equals(currentUser.getInternal_uuid())
|
||||
&& chat.getUser2_id().equals(currentUser.getInternal_uuid());
|
||||
|
||||
ChatEntry entry = new ChatEntry(
|
||||
chat.getChat_id(),
|
||||
@@ -731,6 +739,11 @@ public class ClientHandler implements Runnable {
|
||||
);
|
||||
entry.setOtherUserId(otherId);
|
||||
|
||||
// Mark it as saved messages if it's the special self-chat
|
||||
if (isSavedMessages) {
|
||||
entry.setSavedMessages(true);
|
||||
}
|
||||
|
||||
if (archivedChatIds.contains(chat.getChat_id())) {
|
||||
archivedChatList.add(entry);
|
||||
chatList.add(entry);
|
||||
@@ -2412,8 +2425,103 @@ public class ClientHandler implements Runnable {
|
||||
break;
|
||||
}
|
||||
|
||||
case "get_user_profile": {
|
||||
// Get the current user's UUID
|
||||
UUID user_UUID = this.currentUser.getInternal_uuid();
|
||||
|
||||
// Get the profile JSON from SidebarService
|
||||
JSONObject data = SidebarService.getUserProfile(user_UUID);
|
||||
|
||||
if (data == null) {
|
||||
response = new ResponseModel("error", "Failed to retrieve user profile.");
|
||||
} else {
|
||||
response = new ResponseModel("success", "User profile retrieved successfully.", data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "edit_profile_name": {
|
||||
// Validate input
|
||||
if (!requestJson.has("new_profile_name")) {
|
||||
response = new ResponseModel("error", "Missing new profile name.");
|
||||
break;
|
||||
}
|
||||
|
||||
UUID user_UUID = this.currentUser.getInternal_uuid();
|
||||
String newProfileName = requestJson.getString("new_profile_name");
|
||||
|
||||
response = SidebarService.updateProfileName(user_UUID, newProfileName);
|
||||
break;
|
||||
}
|
||||
|
||||
case "edit_user_id": {
|
||||
// Validate input
|
||||
if (!requestJson.has("new_user_id")) {
|
||||
response = new ResponseModel("error", "Missing new user ID.");
|
||||
break;
|
||||
}
|
||||
|
||||
UUID user_UUID = this.currentUser.getInternal_uuid();
|
||||
String newUserId = requestJson.getString("new_user_id");
|
||||
|
||||
response = SidebarService.updateUserId(user_UUID, newUserId);
|
||||
break;
|
||||
}
|
||||
|
||||
case "edit_bio": {
|
||||
// Validate input
|
||||
if (!requestJson.has("new_bio")) {
|
||||
response = new ResponseModel("error", "Missing new bio.");
|
||||
break;
|
||||
}
|
||||
|
||||
UUID user_UUID = this.currentUser.getInternal_uuid();
|
||||
String newBio = requestJson.getString("new_bio").trim();
|
||||
|
||||
response = SidebarService.updateBio(user_UUID, newBio);
|
||||
break;
|
||||
}
|
||||
|
||||
case "edit_profile_picture": {
|
||||
// Validate input
|
||||
if (!requestJson.has("new_image_url")) {
|
||||
response = new ResponseModel("error", "Missing new image url.");
|
||||
break;
|
||||
}
|
||||
|
||||
UUID user_UUID = this.currentUser.getInternal_uuid();
|
||||
String newImageUrl = requestJson.getString("new_image_url").trim();
|
||||
|
||||
response = SidebarService.updateProfilePicture(user_UUID, newImageUrl);
|
||||
break;
|
||||
}
|
||||
|
||||
case "get_saved_messages": {
|
||||
UUID user_Id = UUID.fromString(requestJson.getString("user_id"));
|
||||
// response = SidebarService.handleGetSavedMessages(user_Id);
|
||||
break;
|
||||
}
|
||||
|
||||
case "send_saved_messages": {
|
||||
response = SidebarService.handleSendMessage(requestJson);
|
||||
break;
|
||||
}
|
||||
|
||||
case "search_contacts": {
|
||||
String user_id = requestJson.getString("user_id");
|
||||
String search_term = requestJson.getString("search_term");
|
||||
|
||||
response = SidebarService.handleSearchContacts(user_id, search_term);
|
||||
break;
|
||||
}
|
||||
|
||||
case "remove_contact": {
|
||||
UUID user_id = UUID.fromString(requestJson.getString("user_id"));
|
||||
UUID contactId = UUID.fromString(requestJson.getString("contact_id"));
|
||||
|
||||
response = SidebarService.handleRemoveContact(user_id, contactId);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
response = new ResponseModel("error", "Unknown action: " + action);
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
package org.to.telegramfinalproject.Server;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.to.telegramfinalproject.Database.ContactDatabase;
|
||||
import org.to.telegramfinalproject.Database.MessageDatabase;
|
||||
import org.to.telegramfinalproject.Database.PrivateChatDatabase;
|
||||
import org.to.telegramfinalproject.Database.userDatabase;
|
||||
import org.to.telegramfinalproject.Models.ContactEntry;
|
||||
import org.to.telegramfinalproject.Models.Message;
|
||||
import org.to.telegramfinalproject.Models.ResponseModel;
|
||||
import org.to.telegramfinalproject.Models.User;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SidebarService {
|
||||
private static userDatabase userDB = new userDatabase();
|
||||
|
||||
// Returns current user's profile data (name, bio, status, etc.)
|
||||
public static JSONObject getUserProfile(UUID userUUID) {
|
||||
User user = userDB.findByInternalUUID(userUUID);
|
||||
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject profile = new JSONObject();
|
||||
profile.put("user_id", user.getUser_id());
|
||||
profile.put("profile_name", user.getProfile_name());
|
||||
profile.put("bio", user.getBio() != null ? user.getBio() : "");
|
||||
profile.put("status", "ONLINE");
|
||||
profile.put("profile_picture_url", user.getImage_url());
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
// Changes the user's profile picture
|
||||
public static ResponseModel updateProfilePicture(UUID userUUID, String newImageUrl) {
|
||||
User user = userDB.findByInternalUUID(userUUID);
|
||||
if (user == null) {
|
||||
return new ResponseModel("error", "User not found.");
|
||||
}
|
||||
|
||||
String currentUrl = user.getImage_url();
|
||||
if (Objects.equals(currentUrl, newImageUrl)) {
|
||||
return new ResponseModel("error", "No changes made. Profile picture is the same.");
|
||||
}
|
||||
|
||||
user.setImage_url(newImageUrl); // Can be null
|
||||
boolean success = userDB.updateByUUID(userUUID, user);
|
||||
|
||||
if (success) {
|
||||
return new ResponseModel("success", "Profile picture updated successfully.");
|
||||
} else {
|
||||
user.setImage_url(currentUrl);
|
||||
return new ResponseModel("error", "Failed to update profile picture.");
|
||||
}
|
||||
}
|
||||
|
||||
// Changes user's bio
|
||||
public static ResponseModel updateBio(UUID userUUID, String newBio) {
|
||||
if (newBio.length() > 70) {
|
||||
return new ResponseModel("error", "Bio is too long.");
|
||||
}
|
||||
|
||||
User user = userDB.findByInternalUUID(userUUID);
|
||||
if (user == null) {
|
||||
return new ResponseModel("error", "User not found.");
|
||||
}
|
||||
|
||||
String currentBio = user.getBio();
|
||||
if (Objects.equals(currentBio, newBio)) {
|
||||
return new ResponseModel("error", "No changes made. Bio is the same.");
|
||||
}
|
||||
|
||||
user.setBio(newBio);
|
||||
boolean success = userDB.updateByUUID(userUUID, user);
|
||||
|
||||
if (success) {
|
||||
return new ResponseModel("success", "Bio updated successfully.");
|
||||
} else {
|
||||
user.setBio(currentBio);
|
||||
return new ResponseModel("error", "Failed to update bio.");
|
||||
}
|
||||
}
|
||||
|
||||
// Changes user-id
|
||||
public static ResponseModel updateUserId(UUID userUUID, String newUserId) {
|
||||
if (newUserId == null || newUserId.trim().isEmpty()) {
|
||||
return new ResponseModel("error", "User ID cannot be empty.");
|
||||
}
|
||||
|
||||
newUserId = newUserId.trim();
|
||||
|
||||
if (newUserId.contains(" ")) {
|
||||
return new ResponseModel("error", "User ID cannot contain spaces.");
|
||||
}
|
||||
|
||||
if (!newUserId.matches("^[a-zA-Z0-9_]+$")) {
|
||||
return new ResponseModel("error", "User ID can only contain letters, digits, and underscores.");
|
||||
}
|
||||
|
||||
if (userDB.findByUserId(newUserId) != null) {
|
||||
return new ResponseModel("error", "This user ID is already taken.");
|
||||
}
|
||||
|
||||
User user = userDB.findByInternalUUID(userUUID);
|
||||
if (user == null) {
|
||||
return new ResponseModel("error", "User not found.");
|
||||
}
|
||||
|
||||
String currentUserId = user.getUser_id();
|
||||
if (Objects.equals(currentUserId, newUserId)) {
|
||||
return new ResponseModel("error", "No changes made. User ID is the same.");
|
||||
}
|
||||
|
||||
user.setUser_id(newUserId);
|
||||
|
||||
boolean saved = userDB.updateByUUID(userUUID, user);
|
||||
if (saved) {
|
||||
return new ResponseModel("success", "User ID updated successfully.");
|
||||
} else {
|
||||
user.setUser_id(currentUserId);
|
||||
return new ResponseModel("error", "Failed to update user ID due to server error.");
|
||||
}
|
||||
}
|
||||
|
||||
// Changes user's profile name
|
||||
public static ResponseModel updateProfileName(UUID userUUID, String newProfileName) {
|
||||
if (newProfileName == null || newProfileName.trim().isEmpty()) {
|
||||
return new ResponseModel("error", "Invalid input."); // Invalid input (empty or just spaces)
|
||||
}
|
||||
|
||||
// Fetch the user from database
|
||||
User user = userDB.findByInternalUUID(userUUID);
|
||||
if (user == null) {
|
||||
return new ResponseModel("error", "User not found."); // User doesn't exist
|
||||
}
|
||||
|
||||
String oldName = user.getProfile_name();
|
||||
if (Objects.equals(oldName, newProfileName)) {
|
||||
return new ResponseModel("error", "No changes made. Profile name is the same.");
|
||||
}
|
||||
|
||||
// Only set the profile name *after* successful DB update
|
||||
user.setProfile_name(newProfileName);
|
||||
|
||||
boolean saved = userDB.updateByUUID(userUUID, user);
|
||||
|
||||
if (saved) {
|
||||
return new ResponseModel("success", "Profile name updated successfully.");
|
||||
} else {
|
||||
user.setProfile_name(oldName);
|
||||
return new ResponseModel("error", "Failed to update profile name.");
|
||||
}
|
||||
}
|
||||
|
||||
// Search in user's contact list
|
||||
public static ResponseModel handleSearchContacts(String userUUID, String searchTerm) {
|
||||
if (searchTerm == null || searchTerm.trim().isEmpty()) {
|
||||
return new ResponseModel("error", "Search term cannot be empty.");
|
||||
}
|
||||
|
||||
List<ContactEntry> searchResult = ContactDatabase.searchContacts(UUID.fromString(userUUID), searchTerm);
|
||||
|
||||
if (searchResult.isEmpty()) {
|
||||
return new ResponseModel("error", "No contacts found.");
|
||||
}
|
||||
|
||||
JSONObject data = new JSONObject();
|
||||
JSONArray contacts = new JSONArray();
|
||||
|
||||
for (ContactEntry entry : searchResult) {
|
||||
contacts.put(new JSONObject()
|
||||
.put("contact_id", entry.getContactId())
|
||||
.put("user_id", entry.getUserId())
|
||||
.put("contact_display_id", entry.getContact_displayId())
|
||||
.put("profile_name", entry.getProfileName())
|
||||
.put("image_url", entry.getImageUrl())
|
||||
.put("is_blocked", entry.isBlocked())
|
||||
.put("last_seen", entry.getLastSeenTime())
|
||||
);
|
||||
}
|
||||
data.put("contacts", contacts);
|
||||
|
||||
if (searchResult.isEmpty()) {
|
||||
return new ResponseModel("error", "No contacts found.");
|
||||
}
|
||||
|
||||
return new ResponseModel("success", "Search contacts successfully.", data);
|
||||
}
|
||||
|
||||
// Remove a contact in user's contact list
|
||||
public static ResponseModel handleRemoveContact(UUID userUUID, UUID contactId) {
|
||||
if (userUUID == null || contactId == null) {
|
||||
return new ResponseModel("error", "Invalid input.");
|
||||
}
|
||||
|
||||
boolean removed = ContactDatabase.removeContact(userUUID, contactId);
|
||||
|
||||
if (removed) {
|
||||
return new ResponseModel("success", "Contact removed successfully.");
|
||||
} else {
|
||||
return new ResponseModel("error", "Contact not found.");
|
||||
}
|
||||
}
|
||||
|
||||
// Get saved messages data
|
||||
// public static ResponseModel handleGetSavedMessages(UUID userId) {
|
||||
// try {
|
||||
//
|
||||
// UUID chatId = PrivateChatDatabase.getOrCreateSavedMessagesChat(userId);
|
||||
// if (chatId == null) {
|
||||
// return new ResponseModel("error", "Failed to create or find saved messages chat.");
|
||||
// }
|
||||
//
|
||||
// List<Message> messages = MessageDatabase.privateChatHistory(chatId);
|
||||
//
|
||||
// JSONArray messageArray = new JSONArray();
|
||||
// if (!messages.isEmpty()) {
|
||||
// for (Message msg : messages) {
|
||||
// JSONObject msgJson = new JSONObject();
|
||||
// msgJson.put("message_id", msg.getMessage_id().toString());
|
||||
// msgJson.put("sender_id", msg.getSender_id().toString());
|
||||
// msgJson.put("receiver_type", msg.getReceiver_type());
|
||||
// msgJson.put("receiver_id", msg.getReceiver_id().toString());
|
||||
// msgJson.put("content", msg.getContent());
|
||||
// msgJson.put("message_type", msg.getMessage_type());
|
||||
// msgJson.put("send_at", msg.getSend_at().toString()); // LocalDateTime
|
||||
// msgJson.put("status", msg.getStatus());
|
||||
// msgJson.put("reply_to_id", msg.getReply_to_id() != null ? msg.getReply_to_id().toString() : JSONObject.NULL);
|
||||
// msgJson.put("is_edited", msg.isIs_edited());
|
||||
// msgJson.put("original_message_id", msg.getOriginal_message_id() != null ? msg.getOriginal_message_id().toString() : JSONObject.NULL);
|
||||
// msgJson.put("forwarded_by", msg.getForwarded_by() != null ? msg.getForwarded_by().toString() : JSONObject.NULL);
|
||||
// msgJson.put("forwarded_from", msg.getForwarded_from() != null ? msg.getForwarded_from().toString() : JSONObject.NULL);
|
||||
//
|
||||
// messageArray.put(msgJson);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// JSONObject data = new JSONObject();
|
||||
// data.put("chat_id", chatId.toString());
|
||||
// data.put("messages", messageArray);
|
||||
//
|
||||
// return new ResponseModel("success", "Saved messages retrieved successfully", data);
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// return new ResponseModel("error", "Unexpected server error.");
|
||||
// }
|
||||
// }
|
||||
|
||||
// Save messages to DB
|
||||
public static ResponseModel handleSendMessage(JSONObject requestJson) {
|
||||
try {
|
||||
Message message = new Message(
|
||||
UUID.fromString(requestJson.getString("message_id")),
|
||||
UUID.fromString(requestJson.getString("sender_id")),
|
||||
requestJson.getString("receiver_type"),
|
||||
UUID.fromString(requestJson.getString("receiver_id")),
|
||||
requestJson.optString("content", null),
|
||||
requestJson.optString("message_type", "TEXT"),
|
||||
LocalDateTime.now(), // send_at
|
||||
requestJson.optString("status", "SEND"),
|
||||
requestJson.isNull("reply_to_id") ? null : UUID.fromString(requestJson.getString("reply_to_id")),
|
||||
requestJson.optBoolean("is_edited", false),
|
||||
requestJson.isNull("original_message_id") ? null : UUID.fromString(requestJson.getString("original_message_id")),
|
||||
requestJson.isNull("forwarded_by") ? null : UUID.fromString(requestJson.getString("forwarded_by")),
|
||||
requestJson.isNull("forwarded_from") ? null : UUID.fromString(requestJson.getString("forwarded_from")),
|
||||
requestJson.optBoolean("is_deleted_globally", false),
|
||||
requestJson.isNull("edited_at") ? null :
|
||||
LocalDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(requestJson.getLong("edited_at")),
|
||||
ZoneId.systemDefault()
|
||||
)
|
||||
);
|
||||
|
||||
MessageDatabase.insertSavedMessage(message);
|
||||
return new ResponseModel("success", "Message saved successfully.");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new ResponseModel("error", "Unexpected server error.");
|
||||
}
|
||||
}
|
||||
|
||||
// Changes username
|
||||
public static boolean updateUserName(String userId, String newUserName) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user