Spaces:
Sleeping
Sleeping
ausername-12345 commited on
Commit Β·
eab9f14
1
Parent(s): 1e13409
auto-create dms on first message + notifications
Browse files- src/static/app.js +31 -9
- src/ws_manager.py +24 -1
src/static/app.js
CHANGED
|
@@ -346,6 +346,15 @@ async function handleIncomingDm(msg) {
|
|
| 346 |
const withPlain = { ...message, plaintext };
|
| 347 |
msgCache[conversation_id].push(withPlain);
|
| 348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
// If this is the active chat, append the message
|
| 350 |
if (currentChat && currentChat.type === "dm" && currentChat.id === conversation_id) {
|
| 351 |
appendMessage(withPlain, currentChat.other_user);
|
|
@@ -627,12 +636,13 @@ async function sendDm(text) {
|
|
| 627 |
const ciphertextForRecipient = await Crypto.encryptForRecipient(text, pubKeyCache[other.id]);
|
| 628 |
const ciphertextForSender = myPubKey ? await Crypto.encryptForRecipient(text, myPubKey) : ciphertextForRecipient;
|
| 629 |
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
conversation_id
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
}
|
|
|
|
| 636 |
}
|
| 637 |
|
| 638 |
async function sendGroupMsg(text) {
|
|
@@ -724,12 +734,24 @@ async function searchUsers() {
|
|
| 724 |
}, 300);
|
| 725 |
}
|
| 726 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 727 |
async function startDmWith(userId, user) {
|
| 728 |
closeModal("modal-new-chat");
|
| 729 |
-
const conv = await apiFetch(`/chat/conversations?target_user_id=${userId}`, token, "POST");
|
| 730 |
setTab("dms");
|
| 731 |
-
|
| 732 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 733 |
}
|
| 734 |
|
| 735 |
// ββ New Group βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 346 |
const withPlain = { ...message, plaintext };
|
| 347 |
msgCache[conversation_id].push(withPlain);
|
| 348 |
|
| 349 |
+
// For pending DM (no id yet), link it when we get the echo or a reply
|
| 350 |
+
if (currentChat && currentChat.type === "dm" && !currentChat.id) {
|
| 351 |
+
const matchesEcho = message.sender_id === me.id;
|
| 352 |
+
const matchesReply = message.sender_id === currentChat.other_user?.id;
|
| 353 |
+
if (matchesEcho || matchesReply) {
|
| 354 |
+
currentChat.id = conversation_id;
|
| 355 |
+
}
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
// If this is the active chat, append the message
|
| 359 |
if (currentChat && currentChat.type === "dm" && currentChat.id === conversation_id) {
|
| 360 |
appendMessage(withPlain, currentChat.other_user);
|
|
|
|
| 636 |
const ciphertextForRecipient = await Crypto.encryptForRecipient(text, pubKeyCache[other.id]);
|
| 637 |
const ciphertextForSender = myPubKey ? await Crypto.encryptForRecipient(text, myPubKey) : ciphertextForRecipient;
|
| 638 |
|
| 639 |
+
const payload = { type: "dm", ciphertext_for_recipient: ciphertextForRecipient, ciphertext_for_sender: ciphertextForSender };
|
| 640 |
+
if (currentChat.id) {
|
| 641 |
+
payload.conversation_id = currentChat.id;
|
| 642 |
+
} else {
|
| 643 |
+
payload.target_user_id = other.id;
|
| 644 |
+
}
|
| 645 |
+
ws.send(JSON.stringify(payload));
|
| 646 |
}
|
| 647 |
|
| 648 |
async function sendGroupMsg(text) {
|
|
|
|
| 734 |
}, 300);
|
| 735 |
}
|
| 736 |
|
| 737 |
+
function showChatHeader(user) {
|
| 738 |
+
document.getElementById("chat-avatar").textContent = user.display_name[0].toUpperCase();
|
| 739 |
+
document.getElementById("chat-avatar").style.background = user.avatar_color;
|
| 740 |
+
document.getElementById("chat-name").textContent = user.display_name;
|
| 741 |
+
document.getElementById("chat-sub").textContent = "@" + user.username;
|
| 742 |
+
document.getElementById("group-settings-btn").classList.add("hidden");
|
| 743 |
+
}
|
| 744 |
+
|
| 745 |
async function startDmWith(userId, user) {
|
| 746 |
closeModal("modal-new-chat");
|
|
|
|
| 747 |
setTab("dms");
|
| 748 |
+
currentChat = { type: "dm", id: null, other_user: user };
|
| 749 |
+
showChatHeader(user);
|
| 750 |
+
document.getElementById("empty-state").classList.add("hidden");
|
| 751 |
+
document.getElementById("chat-window").classList.remove("hidden");
|
| 752 |
+
document.getElementById("chat-window").classList.add("flex");
|
| 753 |
+
document.getElementById("messages").innerHTML = "";
|
| 754 |
+
document.getElementById("msg-input").focus();
|
| 755 |
}
|
| 756 |
|
| 757 |
// ββ New Group βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
src/ws_manager.py
CHANGED
|
@@ -28,10 +28,33 @@ class ConnectionManager:
|
|
| 28 |
|
| 29 |
async def handle_dm(self, msg: dict, sender: User, db: Session):
|
| 30 |
conversation_id = msg.get("conversation_id")
|
|
|
|
| 31 |
ciphertext_for_recipient = msg.get("ciphertext_for_recipient")
|
| 32 |
ciphertext_for_sender = msg.get("ciphertext_for_sender")
|
| 33 |
|
| 34 |
-
if not
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
return
|
| 36 |
|
| 37 |
# Verify sender is in conversation
|
|
|
|
| 28 |
|
| 29 |
async def handle_dm(self, msg: dict, sender: User, db: Session):
|
| 30 |
conversation_id = msg.get("conversation_id")
|
| 31 |
+
target_user_id = msg.get("target_user_id")
|
| 32 |
ciphertext_for_recipient = msg.get("ciphertext_for_recipient")
|
| 33 |
ciphertext_for_sender = msg.get("ciphertext_for_sender")
|
| 34 |
|
| 35 |
+
if not ciphertext_for_recipient:
|
| 36 |
+
return
|
| 37 |
+
|
| 38 |
+
# Auto-create conversation if target_user_id is provided instead of conversation_id
|
| 39 |
+
if not conversation_id and target_user_id:
|
| 40 |
+
target = db.query(User).filter(User.id == target_user_id).first()
|
| 41 |
+
if not target:
|
| 42 |
+
return
|
| 43 |
+
my_ids = set(m.conversation_id for m in db.query(ConversationMember).filter(ConversationMember.user_id == sender.id).all())
|
| 44 |
+
their_ids = set(m.conversation_id for m in db.query(ConversationMember).filter(ConversationMember.user_id == target_user_id).all())
|
| 45 |
+
common = my_ids & their_ids
|
| 46 |
+
if common:
|
| 47 |
+
conversation_id = common.pop()
|
| 48 |
+
else:
|
| 49 |
+
conv = Conversation()
|
| 50 |
+
db.add(conv)
|
| 51 |
+
db.flush()
|
| 52 |
+
db.add(ConversationMember(conversation_id=conv.id, user_id=sender.id))
|
| 53 |
+
db.add(ConversationMember(conversation_id=conv.id, user_id=target_user_id))
|
| 54 |
+
db.flush()
|
| 55 |
+
conversation_id = conv.id
|
| 56 |
+
|
| 57 |
+
if not conversation_id:
|
| 58 |
return
|
| 59 |
|
| 60 |
# Verify sender is in conversation
|