edit thread
parent
e9f3b3f15a
commit
6531e692f7
222
client/app.js
222
client/app.js
|
@ -2,13 +2,34 @@ import { render, html } from '/uhtml.js';
|
||||||
import loadMessages from '/message.js';
|
import loadMessages from '/message.js';
|
||||||
import loadSpace from '/space.js';
|
import loadSpace from '/space.js';
|
||||||
|
|
||||||
|
function setVisibility() {
|
||||||
|
document.getElementById('visibility').innerText = `${
|
||||||
|
window.currentThread.permissions.everyone.view.value ?
|
||||||
|
'this thread is visible to everyone' :
|
||||||
|
'members can view this thread'}
|
||||||
|
${window.currentThread.permissions.everyone.post.value ?
|
||||||
|
'anyone can post' :
|
||||||
|
window.currentThread.permissions.members.post.value ?
|
||||||
|
'only members can post' : 'some members can post'}`;
|
||||||
|
}
|
||||||
|
|
||||||
function chooseThread() {
|
function chooseThread() {
|
||||||
|
const edit = document.getElementById('edit');
|
||||||
if (window.currentThread) {
|
if (window.currentThread) {
|
||||||
if (window.currentThread.id === this.thread.id)
|
if (window.currentThread.id === this.thread.id)
|
||||||
return;
|
return;
|
||||||
document.getElementById(`thread${window.currentThread.id}`)
|
document.getElementById(`thread${window.currentThread.id}`)
|
||||||
.classList.remove('active');
|
.classList.remove('active');
|
||||||
|
let editform = document.getElementById('editthread');
|
||||||
|
if (editform) {
|
||||||
|
editform.remove();
|
||||||
|
edit.textContent = 'edit';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (this.thread.permissions.admin)
|
||||||
|
edit.classList.remove('hidden');
|
||||||
|
else
|
||||||
|
edit.classList.add('hidden');
|
||||||
document.getElementById('threadname').textContent = this.thread.name;
|
document.getElementById('threadname').textContent = this.thread.name;
|
||||||
this.classList.add('active');
|
this.classList.add('active');
|
||||||
window.currentThread = this.thread;
|
window.currentThread = this.thread;
|
||||||
|
@ -19,15 +40,8 @@ function chooseThread() {
|
||||||
document.getElementById('msginput').classList.add('hidden');
|
document.getElementById('msginput').classList.add('hidden');
|
||||||
switchTab(document.getElementById(this.tab));
|
switchTab(document.getElementById(this.tab));
|
||||||
window.emit('get_thread', { thread: this.thread.id }, msg => {
|
window.emit('get_thread', { thread: this.thread.id }, msg => {
|
||||||
window.currentThread.members = msg.thread.members;
|
window.currentThread = msg.thread;
|
||||||
document.getElementById('visibility').innerText = `${
|
setVisibility();
|
||||||
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(
|
document.getElementById('memberlist').replaceChildren(
|
||||||
...msg.thread.members.map(member =>
|
...msg.thread.members.map(member =>
|
||||||
html.node`<p class='member'>${member.name}</p>`)
|
html.node`<p class='member'>${member.name}</p>`)
|
||||||
|
@ -48,48 +62,23 @@ function switchTab(tab) {
|
||||||
loadSpace();
|
loadSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMember() {
|
|
||||||
const name = document.getElementById('membername').value;
|
|
||||||
window.threadmembers.push(name);
|
|
||||||
document
|
|
||||||
.getElementById('newmembers')
|
|
||||||
.appendChild(html.node`<p class='member'>${name}</p>`);
|
|
||||||
document.getElementById('membername').value = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createThread(event) {
|
async function createThread(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let name = document.getElementById('newthreadname').value;
|
let name = document.getElementById('newthreadname').value;
|
||||||
if (!name) {
|
if (!name) {
|
||||||
document.getElementById('nameempty').classList.remove('hidden');
|
document.getElementById('newnameempty').classList.remove('hidden');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let members = window.threadmembers.map(name => ({ name }));
|
|
||||||
const perms = document.querySelector(
|
const perms = document.querySelector(
|
||||||
'input[name="permissions"]:checked'
|
'input[name="newpermissions"]:checked'
|
||||||
).value;
|
).value;
|
||||||
if (perms === 'private_view')
|
|
||||||
members = (
|
|
||||||
await new Promise(resolve =>
|
|
||||||
window.emit('get_keys', { names: window.threadmembers }, resolve)
|
|
||||||
)
|
|
||||||
).keys;
|
|
||||||
let permissions;
|
let permissions;
|
||||||
if (perms === 'public') {
|
if (perms === 'public')
|
||||||
permissions = {
|
permissions = { view_limited: false, post_limited: false };
|
||||||
view_limited: false,
|
else if (perms === 'private_post')
|
||||||
post_limited: false
|
permissions = { view_limited: false, post_limited: true };
|
||||||
};
|
else if (perms === 'private_view') {
|
||||||
} else if (perms === 'private_post') {
|
permissions = { view_limited: true, post_limited: true };
|
||||||
permissions = {
|
|
||||||
view_limited: false,
|
|
||||||
post_limited: true
|
|
||||||
};
|
|
||||||
} else if (perms === 'private_view') {
|
|
||||||
permissions = {
|
|
||||||
view_limited: true,
|
|
||||||
post_limited: true
|
|
||||||
};
|
|
||||||
// generate key
|
// generate key
|
||||||
/* wip
|
/* wip
|
||||||
var buf = new Uint8Array(32);
|
var buf = new Uint8Array(32);
|
||||||
|
@ -100,18 +89,13 @@ async function createThread(event) {
|
||||||
const member = newmembers[i];
|
const member = newmembers[i];
|
||||||
const sig = await openpgp.encrypt({
|
const sig = await openpgp.encrypt({
|
||||||
message: await openpgp.createMessage({ text: key }),
|
message: await openpgp.createMessage({ text: key }),
|
||||||
signingKeys: window.keys.priv,
|
signingKeys: window.keys.priv
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
window.emit(
|
window.emit('create_thread',
|
||||||
'create_thread',
|
{ name, permissions, members: window.threadmembers },
|
||||||
{
|
|
||||||
name,
|
|
||||||
permissions,
|
|
||||||
members
|
|
||||||
},
|
|
||||||
msg => {
|
msg => {
|
||||||
chooseThread.call(document.getElementById('thread' + msg.id));
|
chooseThread.call(document.getElementById('thread' + msg.id));
|
||||||
// since the form exists, this will perform cleanup
|
// since the form exists, this will perform cleanup
|
||||||
|
@ -121,35 +105,44 @@ async function createThread(event) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addMember() {
|
||||||
|
const name = document.getElementById('membername');
|
||||||
|
if (!name.value)
|
||||||
|
return;
|
||||||
|
window.threadmembers.push({ name: name.value });
|
||||||
|
document.getElementById('newmembers')
|
||||||
|
.appendChild(html.node`<p class='member'>${name.value}</p>`);
|
||||||
|
name.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
function newThread() {
|
function newThread() {
|
||||||
let form = document.getElementById('createthread');
|
let form = document.getElementById('createthread');
|
||||||
if (form) {
|
if (form) {
|
||||||
form.remove();
|
form.remove();
|
||||||
document.getElementById('createseparator').remove();
|
|
||||||
document.getElementById('newthread').textContent = 'create';
|
document.getElementById('newthread').textContent = 'create';
|
||||||
} else {
|
return;
|
||||||
window.threadmembers = [window.name];
|
}
|
||||||
document.getElementById('home')
|
window.threadmembers = [{
|
||||||
.insertAdjacentElement('afterend', html.node`
|
name: window.name,
|
||||||
<hr id='createseparator' class='separator' color='#505050'>`)
|
permissions: { admin: 'true' }
|
||||||
.insertAdjacentElement('afterend', html.node`
|
}];
|
||||||
|
document.querySelector('#home + .separator').insertAdjacentElement('afterend', html.node`
|
||||||
<form id='createthread' class='column' onsubmit=${createThread}>
|
<form id='createthread' class='column' onsubmit=${createThread}>
|
||||||
<h3>create thread</h3>
|
<h3>create thread</h3>
|
||||||
<label for='newthreadname' class='heading'>thread name</label>
|
<label for='newthreadname' class='heading'>thread name</label>
|
||||||
<p id='nameempty' class='hidden'>name cannot be empty</p>
|
<p id='newnameempty' class='hidden'>name cannot be empty</p>
|
||||||
<input type='text' id='newthreadname' />
|
<input type='text' id='newthreadname' />
|
||||||
<p id='permissions'>thread permissions</p>
|
<p id='permissions'>thread permissions</p>
|
||||||
<input type='radio' id='public' name='permissions' value='public' checked />
|
<input type='radio' name='newpermissions'
|
||||||
<label for='public'>anyone can view and post</label><br />
|
id='public' value='public' checked />
|
||||||
<input type='radio' id='private_post'
|
<label for='public'>anyone can view and post</label><br>
|
||||||
name='permissions' value='private_post'
|
<input type='radio' name='newpermissions'
|
||||||
/>
|
id='private_post' value='private_post' />
|
||||||
<label for='private_post'>anyone can view, only members can post</label><br/>
|
<label for='private_post'>anyone can view, only members can post</label><br>
|
||||||
<input type='radio' id='private_view'
|
<input type='radio' name='newpermissions'
|
||||||
name='permissions' value='private_view'
|
id='private_view' value='private_view' />
|
||||||
/>
|
<label for='private_view'>only members can view and post</label><br>
|
||||||
<label for='private_view'>only members can view and post</label
|
<br>
|
||||||
><br /><br />
|
|
||||||
<label class='heading' for='membername'>members</label>
|
<label class='heading' for='membername'>members</label>
|
||||||
<input type='text' id='membername' placeholder='username' onkeydown=${event => {
|
<input type='text' id='membername' placeholder='username' onkeydown=${event => {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
|
@ -157,16 +150,80 @@ function newThread() {
|
||||||
addMember();
|
addMember();
|
||||||
}
|
}
|
||||||
}} />
|
}} />
|
||||||
<button id='addmember' onclick=${addMember}>add</button>
|
<button id='addmember' type='button' onclick=${addMember}>add</button>
|
||||||
<div id='newmembers'>
|
<div id='newmembers'>
|
||||||
<p class='member'>${window.name}</p>
|
<p class='member'>${window.name}</p>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br>
|
||||||
<button id='submitthread' type='submit'>create</button>
|
<button id='submitthread' type='submit'>create</button>
|
||||||
</form>
|
</form>`);
|
||||||
`);
|
|
||||||
document.getElementById('newthread').textContent = 'cancel';
|
document.getElementById('newthread').textContent = 'cancel';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function saveThread(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
let name = document.getElementById('editthreadname').value;
|
||||||
|
if (!name) {
|
||||||
|
document.getElementById('nameempty').classList.remove('hidden');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const perms = document.querySelector(
|
||||||
|
'input[name="permissions"]:checked'
|
||||||
|
).value;
|
||||||
|
let permissions;
|
||||||
|
if (perms === 'public')
|
||||||
|
permissions = { view_limited: false, post_limited: false };
|
||||||
|
else if (perms === 'private_post')
|
||||||
|
permissions = { view_limited: false, post_limited: true };
|
||||||
|
else if (perms === 'private_view') {
|
||||||
|
permissions = { view_limited: true, post_limited: true };
|
||||||
|
// todo: generate key and encrypt
|
||||||
|
}
|
||||||
|
window.emit('edit_thread',
|
||||||
|
{ id: window.currentThread.id, name, permissions },
|
||||||
|
msg => {
|
||||||
|
if (!msg.success) {
|
||||||
|
console.log('edit_thread failed: ', msg.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
editThread();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function editThread() {
|
||||||
|
let form = document.getElementById('editthread');
|
||||||
|
if (form) {
|
||||||
|
form.remove();
|
||||||
|
document.getElementById('edit').textContent = 'edit';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
form = html.node`
|
||||||
|
<form id='editthread' class='column' onsubmit=${saveThread}>
|
||||||
|
<label for='editthreadname' class='heading'>thread name</label>
|
||||||
|
<input type='text' id='editthreadname' />
|
||||||
|
<p id='nameempty' class='hidden'>name cannot be empty</p>
|
||||||
|
<p id='permissions'>thread permissions</p>
|
||||||
|
<input type='radio' name='permissions'
|
||||||
|
id='public' value='public' />
|
||||||
|
<label for='public'>anyone can view and post</label><br>
|
||||||
|
<input type='radio' name='permissions'
|
||||||
|
id='private_post' value='private_post' />
|
||||||
|
<label for='private_post'>anyone can view, only members can post</label><br>
|
||||||
|
<input type='radio' name='permissions'
|
||||||
|
id='private_view' value='private_view' />
|
||||||
|
<label for='private_view'>only members can view and post</label><br>
|
||||||
|
<br>
|
||||||
|
<button id='savethread'>save</button>
|
||||||
|
</form>`;
|
||||||
|
form['editthreadname'].value = window.currentThread.name;
|
||||||
|
if (window.currentThread.permissions.everyone.post.value)
|
||||||
|
form['public'].checked = true;
|
||||||
|
else if (window.currentThread.permissions.everyone.view.value)
|
||||||
|
form['private_post'].checked = true;
|
||||||
|
else
|
||||||
|
form['private_view'].checked = true;
|
||||||
|
document.querySelector('#thread').append(form);
|
||||||
|
document.getElementById('edit').textContent = 'cancel';
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickedTab(event) {
|
function clickedTab(event) {
|
||||||
|
@ -188,6 +245,8 @@ document.body.append(html.node`
|
||||||
}>${window.name}</div>
|
}>${window.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<hr class='separator' color='#505050'>
|
<hr class='separator' color='#505050'>
|
||||||
|
<!-- create thread column goes here -->
|
||||||
|
<hr class='separator' color='#505050'>
|
||||||
<div id='profile' class='column hidden'>
|
<div id='profile' class='column hidden'>
|
||||||
<p><strong>authentication requests</strong></p>
|
<p><strong>authentication requests</strong></p>
|
||||||
<div id='authrequests'></div>
|
<div id='authrequests'></div>
|
||||||
|
@ -196,7 +255,8 @@ document.body.append(html.node`
|
||||||
<div id='thread' class='column'>
|
<div id='thread' class='column'>
|
||||||
<div id='content'>
|
<div id='content'>
|
||||||
<div id='title'>
|
<div id='title'>
|
||||||
thread: <strong id='threadname'>meow</strong>
|
<span>thread: <strong id='threadname'>meow</strong></span>
|
||||||
|
<button id='edit' class='hidden' onclick=${editThread}>edit</button>
|
||||||
</div>
|
</div>
|
||||||
<div id='buttons'>
|
<div id='buttons'>
|
||||||
<div id='tabs'>
|
<div id='tabs'>
|
||||||
|
@ -217,6 +277,7 @@ document.body.append(html.node`
|
||||||
<div id='memberlist'>
|
<div id='memberlist'>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr class='separator' color='#505050'>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
@ -231,7 +292,18 @@ function makeThread(thread) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.socket.on('new_thread', thread => {
|
window.socket.on('thread', thread => {
|
||||||
|
let el = document.getElementById('thread' + thread.id);
|
||||||
|
if (el) {
|
||||||
|
el.thread = thread;
|
||||||
|
el.textContent = thread.name;
|
||||||
|
if (window.currentThread.id === thread.id) {
|
||||||
|
Object.assign(window.currentThread, thread);
|
||||||
|
document.getElementById('threadname').textContent = thread.name;
|
||||||
|
setVisibility();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
document.getElementById('threadlist').prepend(makeThread(thread));
|
document.getElementById('threadlist').prepend(makeThread(thread));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
button,
|
button,
|
||||||
input,
|
input,
|
||||||
.tab {
|
.tab {
|
||||||
padding: 5px 7px;
|
padding: 4px 7px;
|
||||||
}
|
}
|
||||||
input {
|
input {
|
||||||
background: #1b1b1b;
|
background: #1b1b1b;
|
||||||
|
@ -81,9 +81,11 @@
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
h3,
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
h4 {
|
h4 {
|
||||||
margin: 10px 0;
|
margin: 6px 0;
|
||||||
}
|
}
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
@ -96,7 +98,8 @@
|
||||||
margin: 8px 2px;
|
margin: 8px 2px;
|
||||||
}
|
}
|
||||||
.separator:has(+ .separator),
|
.separator:has(+ .separator),
|
||||||
.separator:has(+ *.hidden) {
|
.separator:has(+ *.hidden),
|
||||||
|
.separator:last-child {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#home {
|
#home {
|
||||||
|
@ -107,6 +110,12 @@
|
||||||
}
|
}
|
||||||
#threads {
|
#threads {
|
||||||
margin: 3px;
|
margin: 3px;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
#threadlist {
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
#user {
|
#user {
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
|
@ -127,25 +136,26 @@
|
||||||
}
|
}
|
||||||
#newthread {
|
#newthread {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
width: fit-content;
|
||||||
}
|
}
|
||||||
#createthread {
|
#createthread {
|
||||||
max-width: fit-content;
|
max-width: fit-content;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
#permissions {
|
#permissions {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
#thread {
|
#thread {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
#content {
|
#content {
|
||||||
|
margin: 2px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
#title {
|
#title, #buttons {
|
||||||
margin: 4px;
|
|
||||||
}
|
|
||||||
#buttons {
|
|
||||||
margin: 4px 2px;
|
margin: 4px 2px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
@ -194,8 +204,12 @@
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#editthread {
|
||||||
|
max-width: fit-content;
|
||||||
|
}
|
||||||
#visibility {
|
#visibility {
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
.member {
|
.member {
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
|
|
|
@ -7,31 +7,20 @@ const check_permission = async (user_id, thread_id) => {
|
||||||
[thread_id]
|
[thread_id]
|
||||||
);
|
);
|
||||||
// check if the user is a member
|
// check if the user is a member
|
||||||
const is_member =
|
const is_member = (
|
||||||
(
|
await db.query('select * from member where thread = ? and user = ?',
|
||||||
await db.query('select * from member where thread = ? and user = ?', [
|
[thread_id, user_id])
|
||||||
thread_id,
|
|
||||||
user_id,
|
|
||||||
])
|
|
||||||
).rows.length > 0;
|
).rows.length > 0;
|
||||||
const get_permission = (permission) => {
|
let perms = { is_member };
|
||||||
const relevant = permissions.rows.filter(
|
for (let p of permissions.rows) {
|
||||||
(i) => i.permission === permission
|
if (p.type === 'everyone' && p.value === 'true')
|
||||||
);
|
perms[p.permission] = true;
|
||||||
for (let i of relevant) {
|
else if (p.type === 'members' && is_member && p.value === 'true')
|
||||||
if (i.type === 'everyone' && i.value === 'true') {
|
perms[p.permission] = true;
|
||||||
return true;
|
else if (p.type === 'user' && p.user === user_id && p.value === 'true')
|
||||||
|
perms[p.permission] = true;
|
||||||
}
|
}
|
||||||
if (i.type === 'members' && i.value === 'true' && is_member) {
|
return perms;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
is_member,
|
|
||||||
view: get_permission('view'),
|
|
||||||
post: get_permission('post')
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = check_permission;
|
module.exports = check_permission;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const db = require('../db');
|
const db = require('../db');
|
||||||
const authwrap = require('../authwrap');
|
const authwrap = require('../authwrap');
|
||||||
|
|
||||||
const create_thread = async (msg, respond, socket) => {
|
const create_thread = async (msg, respond) => {
|
||||||
// validate inputs
|
// validate inputs
|
||||||
if (typeof msg.name !== 'string') {
|
if (typeof msg.name !== 'string') {
|
||||||
return respond({
|
return respond({
|
||||||
|
@ -26,52 +26,61 @@ const create_thread = async (msg, respond, socket) => {
|
||||||
await db.query(
|
await db.query(
|
||||||
`insert into permission (thread, type, mutable, permission, value)
|
`insert into permission (thread, type, mutable, permission, value)
|
||||||
values (?, ?, ?, ?, ?)`,
|
values (?, ?, ?, ?, ?)`,
|
||||||
[thread_id, 'everyone', false, 'view', 'true']
|
[thread_id, 'everyone', true, 'view', 'true']
|
||||||
);
|
);
|
||||||
if (!msg.permissions || !msg.permissions.post_limited) {
|
if (!msg.permissions || !msg.permissions.post_limited) {
|
||||||
await db.query(
|
await db.query(
|
||||||
`insert into permission (thread, type, mutable, permission, value)
|
`insert into permission (thread, type, mutable, permission, value)
|
||||||
values (?, ?, ?, ?, ?)`,
|
values (?, ?, ?, ?, ?)`,
|
||||||
[thread_id, 'everyone', false, 'post', 'true']
|
[thread_id, 'everyone', true, 'post', 'true']
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await db.query(
|
await db.query(
|
||||||
`insert into permission (thread, type, mutable, permission, value)
|
`insert into permission (thread, type, mutable, permission, value)
|
||||||
values (?, ?, ?, ?, ?)`,
|
values (?, ?, ?, ?, ?)`,
|
||||||
[thread_id, 'members', false, 'post', 'true']
|
[thread_id, 'members', true, 'post', 'true']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await db.query(
|
await db.query(
|
||||||
`insert into permission (thread, type, mutable, permission, value)
|
`insert into permission (thread, type, mutable, permission, value)
|
||||||
values (?, ?, ?, ?, ?)`,
|
values (?, ?, ?, ?, ?)`,
|
||||||
[thread_id, 'members', false, 'view', 'true']
|
[thread_id, 'members', true, 'view', 'true']
|
||||||
);
|
);
|
||||||
await db.query(
|
await db.query(
|
||||||
`insert into permission (thread, type, mutable, permission, value)
|
`insert into permission (thread, type, mutable, permission, value)
|
||||||
values (?, ?, ?, ?, ?)`,
|
values (?, ?, ?, ?, ?)`,
|
||||||
[thread_id, 'members', false, 'post', 'true']
|
[thread_id, 'members', true, 'post', 'true']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// add members
|
// add members
|
||||||
for (let user of msg.members) {
|
if (Array.isArray(msg.members)) {
|
||||||
if (!user) continue;
|
for (let member of msg.members) {
|
||||||
|
if (!member) continue;
|
||||||
// get user id
|
// get user id
|
||||||
const id = await db.query('select id from user where name = ?', [
|
const id = await db.query('select id from user where name = ?', [
|
||||||
user.name,
|
member.name,
|
||||||
]);
|
]);
|
||||||
if (id.rows.length > 0) {
|
if (id.rows.length === 0) {
|
||||||
const user_id = id.rows[0].id;
|
console.log('user not found: ' + member.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
await db.query(
|
await db.query(
|
||||||
'insert into member (thread, user) values (?, ?)',
|
'insert into member (thread, user) values (?, ?)',
|
||||||
[thread_id, user_id]
|
[thread_id, id.rows[0].id]
|
||||||
);
|
);
|
||||||
|
if (typeof member.permissions === 'object')
|
||||||
|
for (let permission in member.permissions)
|
||||||
|
await db.query(`
|
||||||
|
insert into permission (thread, type, user, mutable, permission, value)
|
||||||
|
values (?, ?, ?, ?, ?, ?)`,
|
||||||
|
[thread_id, 'user', id.rows[0].id, true, permission, member.permissions[permission]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!msg.permissions || !msg.permissions.view_limited) {
|
if (!msg.permissions || !msg.permissions.view_limited) {
|
||||||
for (let username in vybe.users) {
|
for (let username in vybe.users) {
|
||||||
for (let socket of vybe.users[username].sockets) {
|
for (let socket of vybe.users[username].sockets) {
|
||||||
socket.emit('new_thread', {
|
socket.emit('thread', {
|
||||||
name: msg.name,
|
name: msg.name,
|
||||||
id: insert.rows[0].id,
|
id: insert.rows[0].id,
|
||||||
permissions: {
|
permissions: {
|
||||||
|
@ -83,10 +92,12 @@ const create_thread = async (msg, respond, socket) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (Array.isArray(msg.members)) {
|
||||||
for (let member of msg.members) {
|
for (let member of msg.members) {
|
||||||
|
if (!vybe.users[member.name])
|
||||||
|
continue;
|
||||||
for (let socket of vybe.users[member.name].sockets) {
|
for (let socket of vybe.users[member.name].sockets) {
|
||||||
socket.emit('new_thread', {
|
socket.emit('thread', {
|
||||||
name: msg.name,
|
name: msg.name,
|
||||||
id: insert.rows[0].id,
|
id: insert.rows[0].id,
|
||||||
permissions: {
|
permissions: {
|
||||||
|
@ -101,7 +112,7 @@ const create_thread = async (msg, respond, socket) => {
|
||||||
// respond
|
// respond
|
||||||
return respond({
|
return respond({
|
||||||
success: true,
|
success: true,
|
||||||
id: insert.rows[0].id
|
id: thread_id
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
const db = require('../db');
|
||||||
|
const authwrap = require('../authwrap');
|
||||||
|
const check_permission = require('../check_permission');
|
||||||
|
|
||||||
|
const edit_thread = async (msg, respond) => {
|
||||||
|
// validate inputs
|
||||||
|
if (!msg.id || typeof msg.name !== 'string') {
|
||||||
|
return respond({
|
||||||
|
success: false,
|
||||||
|
message: 'invalid msg'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (msg.name.length > 200) {
|
||||||
|
return respond({
|
||||||
|
success: false,
|
||||||
|
message: 'thread name 200 chars max'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const perms = await check_permission(msg.auth_user.id, msg.id);
|
||||||
|
if (!perms.admin) {
|
||||||
|
return respond({
|
||||||
|
success: false,
|
||||||
|
message: "user doesn't have permission"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// update name
|
||||||
|
await db.query(
|
||||||
|
'update thread set name = ? where id = ?',
|
||||||
|
[msg.name, msg.id]
|
||||||
|
);
|
||||||
|
// update permissions
|
||||||
|
let permissions = {};
|
||||||
|
for (const p of (await db.query(
|
||||||
|
`select type, permission, value, mutable
|
||||||
|
from permission
|
||||||
|
where type != 'user' and thread = ?`,
|
||||||
|
[msg.id]
|
||||||
|
)).rows) {
|
||||||
|
(permissions[p.type] || (permissions[p.type] = {}))
|
||||||
|
[p.permission] = {
|
||||||
|
value: p.value,
|
||||||
|
mutable: p.mutable
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async function setPermission(type, permission, value) {
|
||||||
|
if (permissions[type] && permissions[type][permission]) {
|
||||||
|
if (!permissions[type][permission].mutable) {
|
||||||
|
respond({
|
||||||
|
success: false,
|
||||||
|
message: 'permission not mutable'
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (permissions[type][permission].value !== value) {
|
||||||
|
await db.query(`
|
||||||
|
update permission set value = ?
|
||||||
|
where thread = ? and type = ? and permission = ?`,
|
||||||
|
[value, msg.id, type, permission]
|
||||||
|
);
|
||||||
|
permissions[type][permission].value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await db.query(
|
||||||
|
`insert into permission (thread, type, mutable, permission, value)
|
||||||
|
values (?, ?, ?, ?, ?)`,
|
||||||
|
[msg.id, type, true, permission, value]
|
||||||
|
);
|
||||||
|
(permissions[type] || (permissions[type] = {}))
|
||||||
|
[permission] = {
|
||||||
|
value,
|
||||||
|
mutable: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!msg.permissions || !msg.permissions.view_limited) {
|
||||||
|
if (!await setPermission('everyone', 'view', 'true'))
|
||||||
|
return;
|
||||||
|
if (!msg.permissions || !msg.permissions.post_limited) {
|
||||||
|
if (!await setPermission('everyone', 'post', 'true'))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!await setPermission('members', 'post', 'true'))
|
||||||
|
return;
|
||||||
|
if (!await setPermission('everyone', 'post', 'false'))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!await setPermission('members', 'view', 'true'))
|
||||||
|
return;
|
||||||
|
if (!await setPermission('members', 'post', 'true'))
|
||||||
|
return;
|
||||||
|
if (!await setPermission('everyone', 'view', 'false'))
|
||||||
|
return;
|
||||||
|
if (!await setPermission('everyone', 'post', 'false'))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!msg.permissions || !msg.permissions.view_limited) {
|
||||||
|
for (let username in vybe.users) {
|
||||||
|
for (let socket of vybe.users[username].sockets) {
|
||||||
|
socket.emit('thread', {
|
||||||
|
name: msg.name,
|
||||||
|
id: msg.id,
|
||||||
|
permissions: {
|
||||||
|
is_member: false,
|
||||||
|
view: true,
|
||||||
|
post: !msg.permissions || !msg.permissions.post_limited,
|
||||||
|
...permissions
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (let member of (await db.query(
|
||||||
|
`select user.name from thread
|
||||||
|
join member on thread.id = member.thread
|
||||||
|
join user on user.id = member.user
|
||||||
|
where thread.id = ?`,
|
||||||
|
[msg.id]
|
||||||
|
)).rows) {
|
||||||
|
if (!vybe.users[member.name])
|
||||||
|
continue;
|
||||||
|
for (let socket of vybe.users[member.name].sockets) {
|
||||||
|
socket.emit('thread', {
|
||||||
|
name: msg.name,
|
||||||
|
id: msg.id,
|
||||||
|
permissions: {
|
||||||
|
is_member: true,
|
||||||
|
view: true,
|
||||||
|
post: true,
|
||||||
|
...permissions
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return respond({
|
||||||
|
success: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = authwrap(edit_thread);
|
|
@ -9,7 +9,8 @@ const get_thread = async (msg, respond) => {
|
||||||
message: 'thread ID required'
|
message: 'thread ID required'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!(await check_permission(msg.auth_user.id, msg.thread)).view) {
|
let perms = await check_permission(msg.auth_user.id, msg.thread);
|
||||||
|
if (!perms.view) {
|
||||||
return respond({
|
return respond({
|
||||||
success: false,
|
success: false,
|
||||||
message: "you can't view this thread"
|
message: "you can't view this thread"
|
||||||
|
@ -23,39 +24,50 @@ const get_thread = async (msg, respond) => {
|
||||||
[msg.thread]
|
[msg.thread]
|
||||||
);
|
);
|
||||||
const permissions = await db.query(
|
const permissions = await db.query(
|
||||||
`select permission.type, permission.user, permission.permission, permission.value, permission.mutable
|
`select type, user, permission, value, mutable
|
||||||
from thread
|
from permission where thread = ?`,
|
||||||
join permission on thread.id = permission.thread
|
|
||||||
where thread.id = ?`,
|
|
||||||
[msg.thread]
|
[msg.thread]
|
||||||
);
|
);
|
||||||
let threadperms = {};
|
let members = Object.fromEntries(thread.rows.map(member =>
|
||||||
let members = Object.fromEntries(thread.rows.map(member => [member.id, member.user]));
|
[member.id, { name: member.user }]
|
||||||
|
));
|
||||||
for (let permission of permissions.rows) {
|
for (let permission of permissions.rows) {
|
||||||
const member = members[permission.user];
|
const member = members[permission.user];
|
||||||
if (member) {
|
if (member)
|
||||||
if (!member.permissions)
|
(member.permissions || (member.permissions = {}))
|
||||||
member.permissions = {};
|
[permission.permission] = {
|
||||||
member.permissions[permission.permission] = {
|
|
||||||
value: permission.value,
|
value: permission.value,
|
||||||
mutable: permission.mutable
|
mutable: permission.mutable
|
||||||
};
|
};
|
||||||
}
|
|
||||||
else
|
else
|
||||||
(threadperms[permission.type] || (threadperms[permission.type] = {}))
|
(perms[permission.type] || (perms[permission.type] = {}))
|
||||||
[permission.permission] = {
|
[permission.permission] = {
|
||||||
value: permission.value,
|
value: permission.value,
|
||||||
mutable: permission.mutable
|
mutable: permission.mutable
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
function makeBool(type, permission) {
|
||||||
|
if (perms[type]) {
|
||||||
|
if (perms[type][permission])
|
||||||
|
perms[type][permission].value = perms[type][permission].value === 'true' ? true : false;
|
||||||
|
else
|
||||||
|
perms[type][permission] = { value: false, mutable: true };
|
||||||
|
} else
|
||||||
|
(perms[type] = {})[permission] = { value: false, mutable: true };
|
||||||
|
}
|
||||||
|
makeBool('everyone', 'view');
|
||||||
|
makeBool('everyone', 'post');
|
||||||
|
makeBool('members', 'view');
|
||||||
|
makeBool('members', 'post');
|
||||||
return respond({
|
return respond({
|
||||||
success: true,
|
success: true,
|
||||||
thread: {
|
thread: {
|
||||||
|
id: msg.thread,
|
||||||
name: thread.rows[0].name,
|
name: thread.rows[0].name,
|
||||||
permissions: threadperms,
|
permissions: perms,
|
||||||
members: Object.entries(members).map(member => ({
|
members: Object.entries(members).map(member => ({
|
||||||
id: member[0],
|
id: member[0],
|
||||||
name: member[1]
|
...member[1]
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue