From e9f3b3f15aae3e8f4c3325711a6869035c0c2a02 Mon Sep 17 00:00:00 2001 From: jerl Date: Sun, 5 May 2024 00:47:42 -0700 Subject: [PATCH] thread members --- client/app.js | 40 +++++++++++++++++--------- client/index.html | 16 +++++++---- client/message.js | 6 ++-- client/space.js | 6 ++-- src/event/get_thread.js | 64 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 24 deletions(-) create mode 100644 src/event/get_thread.js diff --git a/client/app.js b/client/app.js index 21fa4fc..fb5c51f 100644 --- a/client/app.js +++ b/client/app.js @@ -3,21 +3,36 @@ import loadMessages from '/message.js'; import loadSpace from '/space.js'; function chooseThread() { - if (window.threadId) { - if (window.threadId === this.thread.id) + if (window.currentThread) { + if (window.currentThread.id === this.thread.id) return; - document.getElementById(`thread${window.threadId}`) + document.getElementById(`thread${window.currentThread.id}`) .classList.remove('active'); } document.getElementById('threadname').textContent = this.thread.name; this.classList.add('active'); - window.threadId = this.thread.id; + window.currentThread = this.thread; loadMessages(); if (this.thread.permissions.post) document.getElementById('msginput').classList.remove('hidden'); else document.getElementById('msginput').classList.add('hidden'); switchTab(document.getElementById(this.tab)); + window.emit('get_thread', { thread: this.thread.id }, msg => { + window.currentThread.members = msg.thread.members; + document.getElementById('visibility').innerText = `${ + msg.thread.permissions.everyone?.view.value === 'true' ? + 'this thread is visible to everyone' : + 'members can view this thread'} + ${msg.thread.permissions.everyone?.post.value === 'true' ? + 'anyone can post' : + msg.thread.permissions.members?.post.view ? + 'only members can post' : 'select members can post'}`; + document.getElementById('memberlist').replaceChildren( + ...msg.thread.members.map(member => + html.node`

${member.name}

`) + ); + }); } function switchTab(tab) { @@ -116,7 +131,7 @@ function newThread() { window.threadmembers = [window.name]; document.getElementById('home') .insertAdjacentElement('afterend', html.node` -
`) +
`) .insertAdjacentElement('afterend', html.node`

create thread

@@ -156,7 +171,7 @@ function newThread() { function clickedTab(event) { switchTab(event.target); - document.getElementById(`thread${window.threadId}`).tab = event.target.id; + document.getElementById(`thread${window.currentThread.id}`).tab = event.target.id; } // main app html @@ -172,12 +187,12 @@ document.body.append(html.node` document.getElementById('profile').classList.toggle('hidden') }>${window.name} -
+
-
+
@@ -195,9 +210,10 @@ document.body.append(html.node`
-
+
@@ -220,10 +236,8 @@ window.socket.on('new_thread', thread => { }); window.emit('list_threads', {}, msg => { - const threadlist = document.getElementById('threadlist') - threadlist.innerHTML = ''; - for (let thread of msg.threads) - threadlist.appendChild(makeThread(thread)); + const threadlist = document.getElementById('threadlist'); + threadlist.replaceChildren(...msg.threads.map(makeThread)); chooseThread.call(threadlist.firstChild); }); diff --git a/client/index.html b/client/index.html index bc73e73..0d89bdb 100644 --- a/client/index.html +++ b/client/index.html @@ -170,15 +170,11 @@ flex: 1; overflow: auto; } - #members { - flex: 1; - max-width: 250px; - } #msginput { display: flex; flex-direction: row; > * { - margin: 3px; + margin: 2px; } } #msg { @@ -191,6 +187,16 @@ #loadmore { margin-bottom: 10px; } + #members { + flex: 1; + max-width: 250px; + > * { + margin: 4px; + } + } + #visibility { + white-space: pre-line; + } .member { margin: 5px 0; } diff --git a/client/message.js b/client/message.js index 94cd821..0f29e36 100644 --- a/client/message.js +++ b/client/message.js @@ -8,7 +8,7 @@ function sendMessage(e) { return; window.emit('send_message', { message: msg.value, - thread: window.threadId + thread: window.currentThread.id }); msg.value = ''; } @@ -16,7 +16,7 @@ function sendMessage(e) { let earliestMessage; window.socket.on('new_message', message => { - if (message.thread !== window.threadId) + if (message.thread !== window.currentThread.id) return; const messages = document.getElementById('messages'); let scroll = messages.scrollHeight - messages.scrollTop <= messages.clientHeight; @@ -54,7 +54,7 @@ function loadMessages() { 'get_history', { before: earliestMessage, - thread: window.threadId + thread: window.currentThread.id }, msg => { if (!msg.success) diff --git a/client/space.js b/client/space.js index 78bfe2a..0455160 100644 --- a/client/space.js +++ b/client/space.js @@ -144,11 +144,11 @@ export default function loadSpace() { editing.focus(); }; } - if (spaceId === window.threadId) + if (spaceId === window.window.currentThread.id) return; - spaceId = window.threadId; + spaceId = window.window.currentThread.id; space.innerHTML = ''; - window.emit('get_space', { thread: window.threadId }, msg => { + window.emit('get_space', { thread: window.window.currentThread.id }, msg => { if (!msg.success) console.log('get space failed: ' + msg.message); for (const span of msg.spans) diff --git a/src/event/get_thread.js b/src/event/get_thread.js new file mode 100644 index 0000000..152a12f --- /dev/null +++ b/src/event/get_thread.js @@ -0,0 +1,64 @@ +const db = require('../db'); +const authwrap = require('../authwrap'); +const check_permission = require('../check_permission'); + +const get_thread = async (msg, respond) => { + if (!msg.thread) { + return respond({ + success: false, + message: 'thread ID required' + }); + } + if (!(await check_permission(msg.auth_user.id, msg.thread)).view) { + return respond({ + success: false, + message: "you can't view this thread" + }); + } + const thread = await db.query( + `select thread.name, user.name as user, user.id from thread + left join member on thread.id = member.thread + left join user on user.id = member.user + where thread.id = ?`, + [msg.thread] + ); + const permissions = await db.query( + `select permission.type, permission.user, permission.permission, permission.value, permission.mutable + from thread + join permission on thread.id = permission.thread + where thread.id = ?`, + [msg.thread] + ); + let threadperms = {}; + let members = Object.fromEntries(thread.rows.map(member => [member.id, member.user])); + for (let permission of permissions.rows) { + const member = members[permission.user]; + if (member) { + if (!member.permissions) + member.permissions = {}; + member.permissions[permission.permission] = { + value: permission.value, + mutable: permission.mutable + }; + } + else + (threadperms[permission.type] || (threadperms[permission.type] = {})) + [permission.permission] = { + value: permission.value, + mutable: permission.mutable + }; + } + return respond({ + success: true, + thread: { + name: thread.rows[0].name, + permissions: threadperms, + members: Object.entries(members).map(member => ({ + id: member[0], + name: member[1] + })) + } + }); +}; + +module.exports = authwrap(get_thread);