spaces working real
parent
26530690b9
commit
59d0b9eab2
169
client/app.js
169
client/app.js
|
@ -1,28 +1,34 @@
|
||||||
import { render, html } from '/uhtml.js';
|
import { render, html } from '/uhtml.js';
|
||||||
|
import loadSpace from '/space.js';
|
||||||
|
|
||||||
window.currentThreadId = 1;
|
window.currentThreadId = 1;
|
||||||
|
|
||||||
function chooseThread(thread) {
|
function chooseThread(thread) {
|
||||||
if (window.currentThreadId)
|
if (window.currentThreadId) {
|
||||||
document
|
if (window.currentThreadId === thread.id)
|
||||||
.getElementById(`thread${window.currentThreadId}`)
|
return;
|
||||||
.classList.remove("active");
|
document.getElementById(`thread${window.currentThreadId}`)
|
||||||
document.getElementById(`thread${thread.id}`).classList.add("active");
|
.classList.remove('active');
|
||||||
|
}
|
||||||
|
const el = document.getElementById(`thread${thread.id}`);
|
||||||
|
el.classList.add('active');
|
||||||
window.currentThreadId = thread.id;
|
window.currentThreadId = thread.id;
|
||||||
window.earliestMessage = null;
|
window.earliestMessage = null;
|
||||||
document.getElementById("messages").innerHTML = "";
|
document.getElementById('threadname').textContent = thread.name;
|
||||||
document.getElementById("threadname").textContent = thread.name;
|
if (thread.permissions.post)
|
||||||
if (!thread.permissions.post) {
|
document.getElementById('msginput').classList.remove('hidden');
|
||||||
document.getElementById("msginput").classList.add("hidden");
|
else
|
||||||
} else {
|
document.getElementById('msginput').classList.add('hidden');
|
||||||
document.getElementById("msginput").classList.remove("hidden");
|
switchTab(document.getElementById(el.tab));
|
||||||
}
|
|
||||||
loadMessages();
|
loadMessages();
|
||||||
|
if (el.tab === 'spacetab')
|
||||||
|
loadSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMessages() {
|
function loadMessages() {
|
||||||
|
document.getElementById('messages').innerHTML = '';
|
||||||
window.emit(
|
window.emit(
|
||||||
"get_history",
|
'get_history',
|
||||||
{
|
{
|
||||||
before: window.earliestMessage,
|
before: window.earliestMessage,
|
||||||
thread: window.currentThreadId,
|
thread: window.currentThreadId,
|
||||||
|
@ -31,16 +37,16 @@ function loadMessages() {
|
||||||
if (msg.messages.length > 0) {
|
if (msg.messages.length > 0) {
|
||||||
window.earliestMessage = msg.messages[msg.messages.length - 1].id;
|
window.earliestMessage = msg.messages[msg.messages.length - 1].id;
|
||||||
for (let message of msg.messages)
|
for (let message of msg.messages)
|
||||||
document.getElementById("messages").prepend(html.node`
|
document.getElementById('messages').prepend(html.node`
|
||||||
<div class='message'>
|
<div class='message'>
|
||||||
<strong>${message.name}: </strong>
|
<strong>${message.name}: </strong>
|
||||||
${message.message}
|
${message.message}
|
||||||
</div>`);
|
</div>`);
|
||||||
}
|
}
|
||||||
if (!msg.more)
|
if (!msg.more)
|
||||||
document.getElementById("loadmore").classList.add("hidden");
|
document.getElementById('loadmore').classList.add('hidden');
|
||||||
else
|
else
|
||||||
document.getElementById("loadmore").classList.remove("hidden");
|
document.getElementById('loadmore').classList.remove('hidden');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -51,21 +57,35 @@ function addThread(thread, top) {
|
||||||
thread.name
|
thread.name
|
||||||
}</div>`;
|
}</div>`;
|
||||||
node.id = `thread${thread.id}`;
|
node.id = `thread${thread.id}`;
|
||||||
document.getElementById("threadlist")[top ? "prepend" : "appendChild"](node);
|
node.tab = 'messagetab';
|
||||||
|
document.getElementById('threadlist')[top ? 'prepend' : 'appendChild'](node);
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchTab(tab) {
|
||||||
|
for (let tab of document.querySelectorAll('.tab'))
|
||||||
|
tab.classList.remove('active');
|
||||||
|
for (let tab of document.querySelectorAll('.tabcontent'))
|
||||||
|
tab.classList.add('hidden');
|
||||||
|
tab.classList.add('active');
|
||||||
|
document
|
||||||
|
.getElementById(tab.id.slice(0, -3))
|
||||||
|
.classList.remove('hidden');
|
||||||
|
if (tab.id === 'spacetab')
|
||||||
|
loadSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMember() {
|
function addMember() {
|
||||||
const name = document.getElementById("membername").value;
|
const name = document.getElementById('membername').value;
|
||||||
window.threadmembers.push(name);
|
window.threadmembers.push(name);
|
||||||
document
|
document
|
||||||
.getElementById("memberlist")
|
.getElementById('memberlist')
|
||||||
.appendChild(html.node`<p class='member'>${name}</p>`);
|
.appendChild(html.node`<p class='member'>${name}</p>`);
|
||||||
document.getElementById("membername").value = "";
|
document.getElementById('membername').value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createThread(e) {
|
async function createThread(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let name = document.getElementById("newthreadname");
|
let name = document.getElementById('newthreadname');
|
||||||
if (!name.value) {
|
if (!name.value) {
|
||||||
name.insertAdjacentHTML('afterend', `<p>name cannot be empty</p>`);
|
name.insertAdjacentHTML('afterend', `<p>name cannot be empty</p>`);
|
||||||
return;
|
return;
|
||||||
|
@ -74,24 +94,24 @@ async function createThread(e) {
|
||||||
const perms = document.querySelector(
|
const perms = document.querySelector(
|
||||||
'input[name="permissions"]:checked'
|
'input[name="permissions"]:checked'
|
||||||
).value;
|
).value;
|
||||||
if (perms === "private_view")
|
if (perms === 'private_view')
|
||||||
members = (
|
members = (
|
||||||
await new Promise(resolve =>
|
await new Promise(resolve =>
|
||||||
window.emit("get_keys", { names: window.threadmembers }, resolve)
|
window.emit('get_keys', { names: window.threadmembers }, resolve)
|
||||||
)
|
)
|
||||||
).keys;
|
).keys;
|
||||||
let permissions;
|
let permissions;
|
||||||
if (perms === "public") {
|
if (perms === 'public') {
|
||||||
permissions = {
|
permissions = {
|
||||||
view_limited: false,
|
view_limited: false,
|
||||||
post_limited: false
|
post_limited: false
|
||||||
};
|
};
|
||||||
} else if (perms === "private_post") {
|
} else if (perms === 'private_post') {
|
||||||
permissions = {
|
permissions = {
|
||||||
view_limited: false,
|
view_limited: false,
|
||||||
post_limited: true
|
post_limited: true
|
||||||
};
|
};
|
||||||
} else if (perms === "private_view") {
|
} else if (perms === 'private_view') {
|
||||||
permissions = {
|
permissions = {
|
||||||
view_limited: true,
|
view_limited: true,
|
||||||
post_limited: true
|
post_limited: true
|
||||||
|
@ -112,11 +132,11 @@ async function createThread(e) {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
window.emit(
|
window.emit(
|
||||||
"create_thread",
|
'create_thread',
|
||||||
{
|
{
|
||||||
name: name.value,
|
name: name.value,
|
||||||
permissions,
|
permissions,
|
||||||
members,
|
members
|
||||||
},
|
},
|
||||||
msg => {
|
msg => {
|
||||||
chooseThread({
|
chooseThread({
|
||||||
|
@ -130,113 +150,106 @@ async function createThread(e) {
|
||||||
});
|
});
|
||||||
// since the form exists, this will perform cleanup
|
// since the form exists, this will perform cleanup
|
||||||
newThread();
|
newThread();
|
||||||
document.getElementById("loadmore").classList.add("hidden");
|
document.getElementById('loadmore').classList.add('hidden');
|
||||||
document.getElementById("msginput").classList.remove("hidden");
|
document.getElementById('msginput').classList.remove('hidden');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendMessage(e) {
|
function sendMessage(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const msg = document.getElementById("msg").value;
|
const msg = document.getElementById('msg').value;
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return;
|
return;
|
||||||
window.emit("send_message", {
|
window.emit('send_message', {
|
||||||
message: msg,
|
message: msg,
|
||||||
thread: window.currentThreadId
|
thread: window.currentThreadId
|
||||||
});
|
});
|
||||||
document.getElementById("msg").value = "";
|
document.getElementById('msg').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("newthread").textContent = 'create';
|
document.getElementById('newthread').textContent = 'create';
|
||||||
} else {
|
} else {
|
||||||
window.threadmembers = [window.name];
|
window.threadmembers = [window.name];
|
||||||
document.getElementById('threads').insertAdjacentElement('afterend', html.node`
|
document.getElementById('threads').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>
|
||||||
<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' id='public' name='permissions' value='public' checked />
|
||||||
<label for="public">anyone can view and post</label><br />
|
<label for='public'>anyone can view and post</label><br />
|
||||||
<input type="radio" id="private_post"
|
<input type='radio' id='private_post'
|
||||||
name="permissions" value="private_post"
|
name='permissions' 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' id='private_view'
|
||||||
name="permissions" value="private_view"
|
name='permissions' value='private_view'
|
||||||
/>
|
/>
|
||||||
<label for="private_view">only members can view and post</label
|
<label for='private_view'>only members can view and post</label
|
||||||
><br /><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=${(e) => {
|
<input type='text' id='membername' placeholder='username' onkeydown=${(e) => {
|
||||||
if (e.key == "Enter") {
|
if (e.key == 'Enter') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
addMember();
|
addMember();
|
||||||
}
|
}
|
||||||
}}/>
|
}}/>
|
||||||
<button id="addmember" onclick=${addMember}>add</button>
|
<button id='addmember' onclick=${addMember}>add</button>
|
||||||
<div id="memberlist">
|
<div id='memberlist'>
|
||||||
<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';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchTab(event) {
|
function clickedTab(event) {
|
||||||
for (let tab of document.querySelectorAll('.tab'))
|
switchTab(event.target);
|
||||||
tab.classList.remove('active');
|
document.getElementById(`thread${window.currentThreadId}`).tab = event.target.id;
|
||||||
for (let tab of document.querySelectorAll('.tabcontent'))
|
|
||||||
tab.classList.add('hidden');
|
|
||||||
event.target.classList.add('active');
|
|
||||||
document
|
|
||||||
.getElementById(event.target.id.substring(0, event.target.id.length - 3))
|
|
||||||
.classList.remove('hidden');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(document.body, html`
|
render(document.body, html`
|
||||||
<div id="threads" class="column">
|
<div id='threads' class='column'>
|
||||||
<h3>vybe</h3>
|
<h3>vybe</h3>
|
||||||
<h4>threads</h4>
|
<h4>threads</h4>
|
||||||
<div id="threadlist">loading...</div>
|
<div id='threadlist'>loading...</div>
|
||||||
<button id='newthread' onclick=${newThread}>create</button>
|
<button id='newthread' onclick=${newThread}>create</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="thread" class="column">
|
<hr class='separator' color='#666'>
|
||||||
|
<div id='thread' class='column'>
|
||||||
<div id='title'>
|
<div id='title'>
|
||||||
thread: <strong id="threadname">meow</strong>
|
thread: <strong id='threadname'>meow</strong>
|
||||||
</div>
|
</div>
|
||||||
<div id='tabs'>
|
<div id='tabs'>
|
||||||
<button id='messagetab' class='tab active' onclick=${switchTab}>
|
<button id='messagetab' class='tab active' onclick=${clickedTab}>messages</button><button id='spacetab' class='tab' onclick=${clickedTab}>space</button>
|
||||||
messages
|
|
||||||
</button><button id='spacetab' class='tab' onclick=${switchTab}>space</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div id='message' class='tabcontent'>
|
<div id='message' class='tabcontent'>
|
||||||
<button id="loadmore" class="hidden" onclick=${loadMessages}>
|
<button id='loadmore' class='hidden' onclick=${loadMessages}>
|
||||||
load more messages
|
load more messages
|
||||||
</button>
|
</button>
|
||||||
<div id='messages'></div>
|
<div id='messages'></div>
|
||||||
<form id="msginput" onsubmit=${sendMessage}>
|
<form id='msginput' onsubmit=${sendMessage}>
|
||||||
<input type="text" placeholder="write a message..." id="msg" />
|
<input type='text' placeholder='write a message...' id='msg' />
|
||||||
<button type="submit" id="sendmsg">send</button>
|
<button type='submit' id='sendmsg'>send</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div id='space' class='tabcontent hidden'></div>
|
<div id='space' class='tabcontent hidden'></div>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
window.socket.on("new_message", msg => {
|
window.socket.on('new_message', msg => {
|
||||||
if (msg.thread !== window.currentThreadId)
|
if (msg.thread !== window.currentThreadId)
|
||||||
return;
|
return;
|
||||||
document.getElementById("messages").appendChild(html.node`
|
document.getElementById('messages').appendChild(html.node`
|
||||||
<div class='message'>
|
<div class='message'>
|
||||||
<strong>${msg.name}: </strong>
|
<strong>${msg.name}: </strong>
|
||||||
${msg.message}
|
${msg.message}
|
||||||
|
@ -244,13 +257,11 @@ window.socket.on("new_message", msg => {
|
||||||
if (!window.earliestMessage)
|
if (!window.earliestMessage)
|
||||||
window.earliestMessage = msg.id;
|
window.earliestMessage = msg.id;
|
||||||
});
|
});
|
||||||
window.socket.on("new_thread", thread => addThread(thread, true));
|
window.socket.on('new_thread', thread => addThread(thread, true));
|
||||||
|
|
||||||
window.emit("list_threads", {}, msg => {
|
window.emit('list_threads', {}, msg => {
|
||||||
document.getElementById("threadlist").innerHTML = "";
|
document.getElementById('threadlist').innerHTML = '';
|
||||||
for (let thread of msg.threads)
|
for (let thread of msg.threads)
|
||||||
addThread(thread);
|
addThread(thread);
|
||||||
chooseThread(msg.threads[0]);
|
chooseThread(msg.threads[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
import('/space.js');
|
|
||||||
|
|
|
@ -91,11 +91,14 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
|
.separator {
|
||||||
|
margin: 8px 2px;
|
||||||
|
}
|
||||||
#threads {
|
#threads {
|
||||||
max-width: 250px;
|
max-width: 250px;
|
||||||
}
|
}
|
||||||
.thread {
|
.thread {
|
||||||
padding: 2px;
|
padding: 2px 4px;
|
||||||
}
|
}
|
||||||
#newthread {
|
#newthread {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
@ -139,6 +142,7 @@
|
||||||
#msginput {
|
#msginput {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
margin: 2px;
|
||||||
}
|
}
|
||||||
#msg {
|
#msg {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
let space = document.getElementById('space');
|
let space;
|
||||||
|
|
||||||
let scale = 1;
|
let scale = 1;
|
||||||
|
|
||||||
|
@ -13,23 +13,32 @@ function mousemove(event) {
|
||||||
dragging.style.left = `${left < 0 ? 0 : left}px`;
|
dragging.style.left = `${left < 0 ? 0 : left}px`;
|
||||||
dragging.style.top = `${top < 0 ? 0 : top}px`;
|
dragging.style.top = `${top < 0 ? 0 : top}px`;
|
||||||
moved = true;
|
moved = true;
|
||||||
//save
|
save(dragging);
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove(span) {
|
function save(span) {
|
||||||
//remove
|
window.emit('save_span', {
|
||||||
span.remove();
|
thread: window.space,
|
||||||
|
id: span.id ? span.id.slice(4) : '',
|
||||||
|
content: span.innerText,
|
||||||
|
x: span.style.left.slice(0, -2),
|
||||||
|
y: span.style.top.slice(0, -2),
|
||||||
|
scale: span.scale
|
||||||
|
}, msg => {
|
||||||
|
if (!span.id)
|
||||||
|
span.id = 'span' + msg.id;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(x, y) {
|
function add(x, y, scale = 1) {
|
||||||
let span = document.createElement('span');
|
let span = document.createElement('span');
|
||||||
span.classList.add('span');
|
span.classList.add('span');
|
||||||
span.contentEditable = true;
|
span.contentEditable = true;
|
||||||
span.spellcheck = false;
|
span.spellcheck = false;
|
||||||
span.scale = 1;
|
span.scale = scale;
|
||||||
span.style.left = `${x}px`;
|
span.style.left = `${x}px`;
|
||||||
span.style.top = `${y}px`;
|
span.style.top = `${y}px`;
|
||||||
span.style.transform = 'translate(-50%, -50%)';
|
span.style.transform = `translate(-50%, -50%) scale(${scale})`;
|
||||||
span.onkeydown = function(event) {
|
span.onkeydown = function(event) {
|
||||||
if (event.key === 'Enter' && !event.getModifierState('Shift')) {
|
if (event.key === 'Enter' && !event.getModifierState('Shift')) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -38,12 +47,13 @@ function add(x, y) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
span.oninput = function(event) {
|
span.oninput = function(event) {
|
||||||
this.time = Date.now();
|
save(this);
|
||||||
//save
|
|
||||||
};
|
};
|
||||||
span.onblur = function(event) {
|
span.onblur = function(event) {
|
||||||
if (!this.innerText)
|
if (this.innerText)
|
||||||
remove(this);
|
return;
|
||||||
|
save(this);
|
||||||
|
this.remove();
|
||||||
};
|
};
|
||||||
span.onwheel = function(event) {
|
span.onwheel = function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -76,14 +86,15 @@ function add(x, y) {
|
||||||
return span;
|
return span;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function loadSpace() {
|
||||||
|
if (!space) {
|
||||||
|
space = document.getElementById('space');
|
||||||
space.onmouseup = event => {
|
space.onmouseup = event => {
|
||||||
if (dragging) {
|
if (dragging) {
|
||||||
dragging.onmouseup(event);
|
dragging.onmouseup(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (editing) {
|
if (editing) {
|
||||||
if (!editing.innerText)
|
|
||||||
remove(editing);
|
|
||||||
if (event.target !== editing)
|
if (event.target !== editing)
|
||||||
editing = null;
|
editing = null;
|
||||||
return;
|
return;
|
||||||
|
@ -91,3 +102,16 @@ space.onmouseup = event => {
|
||||||
editing = add(event.offsetX + space.scrollLeft, event.offsetY + space.scrollTop);
|
editing = add(event.offsetX + space.scrollLeft, event.offsetY + space.scrollTop);
|
||||||
editing.focus();
|
editing.focus();
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
if (window.space === window.currentThreadId)
|
||||||
|
return;
|
||||||
|
window.space = window.currentThreadId;
|
||||||
|
space.innerHTML = '';
|
||||||
|
window.emit('get_space', { thread: window.space }, msg => {
|
||||||
|
for (const span of msg.spans) {
|
||||||
|
let el = add(span.x, span.y, span.scale);
|
||||||
|
el.innerText = span.content;
|
||||||
|
el.id = 'span' + span.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -54,13 +54,11 @@ create table post (
|
||||||
create table span (
|
create table span (
|
||||||
id integer primary key asc,
|
id integer primary key asc,
|
||||||
thread integer,
|
thread integer,
|
||||||
creator integer,
|
deleted bool default false,
|
||||||
created timestamp default current_timestamp,
|
|
||||||
content text,
|
content text,
|
||||||
x integer,
|
x decimal,
|
||||||
y integer,
|
y decimal,
|
||||||
scale decimal,
|
scale decimal,
|
||||||
foreign key(creator) references user(id),
|
|
||||||
foreign key(thread) references thread(id)
|
foreign key(thread) references thread(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
24
index.js
24
index.js
|
@ -1,17 +1,19 @@
|
||||||
const express = require("express");
|
const express = require('express');
|
||||||
const http = require("http");
|
const http = require('http');
|
||||||
const { Server } = require("socket.io");
|
const { Server } = require('socket.io');
|
||||||
const compression = require("compression");
|
const compression = require('compression');
|
||||||
|
|
||||||
const events = Object.fromEntries(
|
const events = Object.fromEntries(
|
||||||
[
|
[
|
||||||
'create_user',
|
|
||||||
'get_history',
|
|
||||||
'send_message',
|
|
||||||
'authenticate',
|
'authenticate',
|
||||||
'create_thread',
|
'create_thread',
|
||||||
'list_threads',
|
'create_user',
|
||||||
|
'get_history',
|
||||||
'get_keys',
|
'get_keys',
|
||||||
|
'get_space',
|
||||||
|
'list_threads',
|
||||||
|
'save_span',
|
||||||
|
'send_message'
|
||||||
].map(event => [event, require('./src/' + event)])
|
].map(event => [event, require('./src/' + event)])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -28,7 +30,7 @@ const PORT = process.env.PORT || 3435;
|
||||||
|
|
||||||
io.cache = {};
|
io.cache = {};
|
||||||
|
|
||||||
io.on("connection", (socket) => {
|
io.on('connection', (socket) => {
|
||||||
for (let event in events) {
|
for (let event in events) {
|
||||||
socket.on(event, (msg, callback) =>
|
socket.on(event, (msg, callback) =>
|
||||||
events[event](msg, callback, socket, io)
|
events[event](msg, callback, socket, io)
|
||||||
|
@ -42,7 +44,7 @@ io.on("connection", (socket) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen(PORT, () => {
|
server.listen(PORT, () => {
|
||||||
console.log("server running on port " + PORT);
|
console.log('server running on port ' + PORT);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(express.static("client"));
|
app.use(express.static('client'));
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
const db = require('../db');
|
||||||
|
const authwrap = require('./authwrap');
|
||||||
|
const check_permission = require('./helpers/check_permission');
|
||||||
|
|
||||||
|
const get_space = 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 spans = await db.query(
|
||||||
|
'select id, content, x, y, scale from span where thread=? and deleted=false',
|
||||||
|
[msg.thread]
|
||||||
|
);
|
||||||
|
return respond({
|
||||||
|
success: true,
|
||||||
|
spans: spans.rows
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = authwrap(get_space);
|
|
@ -30,7 +30,7 @@ const check_permission = async (user_id, thread_id) => {
|
||||||
return {
|
return {
|
||||||
is_member,
|
is_member,
|
||||||
view: get_permission("view"),
|
view: get_permission("view"),
|
||||||
post: get_permission("post"),
|
post: get_permission("post")
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
const db = require('../db');
|
||||||
|
const authwrap = require('./authwrap');
|
||||||
|
const check_permission = require('./helpers/check_permission');
|
||||||
|
|
||||||
|
const save_span = async (msg, respond, socket, io) => {
|
||||||
|
if (!msg.thread) {
|
||||||
|
return respond({
|
||||||
|
success: false,
|
||||||
|
message: 'thread ID required',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!(await check_permission(msg.auth_user.id, msg.thread)).post) {
|
||||||
|
return respond({
|
||||||
|
success: false,
|
||||||
|
message: "you can't post to this thread",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// save span and send it to everyone
|
||||||
|
let id;
|
||||||
|
if (msg.id) {
|
||||||
|
id = msg.id;
|
||||||
|
if (msg.content)
|
||||||
|
await db.query('update span set content=?, x=?, y=?, scale=?, deleted=false where id=?',
|
||||||
|
[msg.content, msg.x, msg.y, msg.scale, msg.id]);
|
||||||
|
else
|
||||||
|
await db.query('update span set deleted=true where id=?', [msg.id]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
id = (await db.query(
|
||||||
|
'insert into span (thread, content, x, y, scale) values (?, ?, ?, ?, ?) returning id',
|
||||||
|
[msg.thread, msg.content, msg.x, msg.y, msg.scale]
|
||||||
|
)).rows[0].id;
|
||||||
|
}
|
||||||
|
// get thread members
|
||||||
|
const members = (
|
||||||
|
await db.query(
|
||||||
|
'select name from user join member on member.user = user.id where member.thread = ?',
|
||||||
|
[msg.thread]
|
||||||
|
)
|
||||||
|
).rows.map(i => i.name);
|
||||||
|
// get perms
|
||||||
|
const permissions = await db.query(
|
||||||
|
"select * from permission where thread = ? and type = 'everyone' and value = 'true' and permission = 'view'",
|
||||||
|
[msg.thread]
|
||||||
|
);
|
||||||
|
for (let username in io.cache) {
|
||||||
|
if (permissions.rows.length > 0 || members.includes(username)) {
|
||||||
|
const sockets = io.cache[username];
|
||||||
|
for (let s of sockets) {
|
||||||
|
io.to(s).emit('span', {
|
||||||
|
id,
|
||||||
|
thread: msg.thread,
|
||||||
|
content: msg.content,
|
||||||
|
x: msg.x,
|
||||||
|
y: msg.y,
|
||||||
|
scale: msg.scale
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return respond({
|
||||||
|
success: true,
|
||||||
|
id
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = authwrap(save_span);
|
|
@ -33,17 +33,7 @@ const send_message = async (msg, respond, socket, io) => {
|
||||||
[msg.thread]
|
[msg.thread]
|
||||||
);
|
);
|
||||||
for (let username in io.cache) {
|
for (let username in io.cache) {
|
||||||
if (members.includes(username)) {
|
if (permissions.rows.length > 0 || members.includes(username)) {
|
||||||
const sockets = io.cache[username];
|
|
||||||
for (let s of sockets) {
|
|
||||||
io.to(s).emit("new_message", {
|
|
||||||
id: id.rows[0].id,
|
|
||||||
name: msg.auth_user.name,
|
|
||||||
message: msg.message,
|
|
||||||
thread: msg.thread,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (permissions.rows.length > 0) {
|
|
||||||
const sockets = io.cache[username];
|
const sockets = io.cache[username];
|
||||||
for (let s of sockets) {
|
for (let s of sockets) {
|
||||||
io.to(s).emit("new_message", {
|
io.to(s).emit("new_message", {
|
||||||
|
|
Loading…
Reference in New Issue