From 22f7eb7a62f1e0622370a4725e50c74203e51176 Mon Sep 17 00:00:00 2001 From: denis0001-dev Date: Mon, 25 Aug 2025 17:10:36 +0300 Subject: [PATCH] Implement working DMs --- backend/routes/account.py | 18 +++++++++- frontend/index.html | 11 +----- frontend/src/chat/dm.ts | 74 ++++++++++++++++++++++++++++----------- 3 files changed, 72 insertions(+), 31 deletions(-) diff --git a/backend/routes/account.py b/backend/routes/account.py index 3f3a0fd..5b51f54 100644 --- a/backend/routes/account.py +++ b/backend/routes/account.py @@ -201,4 +201,20 @@ def logout( return { "status": "success", "message": "Logged out successfully" - } \ No newline at end of file + } + + +@router.get("/users") +def list_users(current_user: User = Depends(get_current_user), db: Session = Depends(get_db)): + users = db.query(User).order_by(User.username.asc()).all() + return { + "users": [ + convert_user(u) for u in users if u.id != current_user.id + ] + } + + +@router.get("/crypto/public-key/of/{user_id}") +def get_public_key_of(user_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)): + row = db.query(CryptoPublicKey).filter(CryptoPublicKey.user_id == user_id).first() + return {"publicKey": row.public_key_b64 if row else None} \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html index 645c17b..606d2b5 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -164,16 +164,7 @@ Скоро будет... Скоро будет... - - -
- - - Отправить -
-
-
-
+
diff --git a/frontend/src/chat/dm.ts b/frontend/src/chat/dm.ts index 1ad0f77..a13e4b6 100644 --- a/frontend/src/chat/dm.ts +++ b/frontend/src/chat/dm.ts @@ -70,7 +70,7 @@ export async function decryptDm(envelope: DmEnvelope, senderPublicKeyB64: string } function appendDmMessage(text: string, isAuthor: boolean) { - const container = document.getElementById("dm-messages")!; + const container = document.getElementById("chat-messages")!; const div = document.createElement("div"); div.className = `message ${isAuthor ? "sent" : "received"}`; const inner = document.createElement("div"); @@ -84,30 +84,64 @@ function appendDmMessage(text: string, isAuthor: boolean) { container.scrollTop = container.scrollHeight; } -async function fetchRecipient(userName: string): Promise<{ id: number; publicKey: string | null } | null> { - const res = await fetch(`${API_BASE_URL}/profile/${encodeURIComponent(userName)}`); - if (!res.ok) return null; +// removed unused helper + +let activeDm: { userId: number; username: string; publicKey: string | null } | null = null; +let usersLoaded = false; + +async function loadUsers() { + const res = await fetch(`${API_BASE_URL}/users`, { headers: getAuthHeaders(true) }); + if (!res.ok) return; const data = await res.json(); - // This assumes an endpoint returns profile with id; adapt if different - const pkRes = await fetch(`${API_BASE_URL}/crypto/public-key`, { headers: getAuthHeaders(true) }); - // For simplicity, we reuse current user's endpoint; in real case, need GET by userId - // Minimal v1: assume recipient has same endpoint at /profile/public-key?userId=... (not implemented) - return { id: data.id, publicKey: null }; + const list = document.getElementById("dm-users")!; + list.innerHTML = ""; + (data.users || []).forEach((u: any) => { + const item = document.createElement("mdui-list-item"); + item.setAttribute("headline", u.username); + item.addEventListener("click", async () => { + activeDm = { userId: u.id, username: u.username, publicKey: null }; + document.getElementById("chat-name")!.textContent = u.username; + (document.getElementById("chat-messages") as HTMLElement).innerHTML = ""; + const resPk = await fetch(`${API_BASE_URL}/crypto/public-key/of/${u.id}`, { headers: getAuthHeaders(true) }); + if (resPk.ok) { + const pkData = await resPk.json(); + activeDm!.publicKey = pkData.publicKey; + } + }); + list.appendChild(item); + }); } document.addEventListener("DOMContentLoaded", () => { - const sendBtn = document.getElementById("dm-send"); - if (!sendBtn) return; - sendBtn.addEventListener("click", async () => { - const userEl = document.getElementById("dm-username") as HTMLInputElement; - const textEl = document.getElementById("dm-input") as HTMLInputElement; - const username = userEl.value.trim(); - const text = textEl.value.trim(); - if (!username || !text) return; - // TODO: replace with real lookup for recipientId and publicKey - appendDmMessage(text, true); - textEl.value = ""; + const tabs = document.querySelector(".chat-tabs mdui-tabs"); + const dmTab = tabs?.querySelector('mdui-tab[value="dms"]'); + function ensureUsersLoaded() { + if (!usersLoaded) { + usersLoaded = true; + loadUsers(); + } + } + dmTab?.addEventListener("click", ensureUsersLoaded); + (tabs as any)?.addEventListener("change", (e: any) => { + if (e?.detail?.value === "dms") ensureUsersLoaded(); }); + const form = document.getElementById("message-form"); + if (form) { + form.addEventListener("submit", async (e) => { + if (!activeDm) return; // Let global chat handler proceed + e.preventDefault(); + const input = document.getElementById("message-input") as HTMLInputElement; + const text = input.value.trim(); + if (!text) return; + appendDmMessage(text, true); + input.value = ""; + if (activeDm.publicKey) { + try { + await sendDm(activeDm.userId, activeDm.publicKey, text); + } catch {} + } + }); + } });