diff --git a/server/db/db.js b/server/db/db.js index 4a15ba0..b90a78b 100644 --- a/server/db/db.js +++ b/server/db/db.js @@ -63,6 +63,39 @@ export default class Database { } } + deleteNode(prefix, id) { + try { + let model = nodeModels[prefix] + if(model) { + this.nodes[model.indices[0] + (id - 1)] = 0 + } else { + throw new Error("Type does not exist for node: " + id) + } + } catch(e) { + throw e + } + } + + editNode(prefix, id, toEdit) { + try { + let model = nodeModels[prefix] + if(model) { + let schema = model.schema + let result = schema.safeParse(toEdit) + if(result.success) { + this.nodes[model.indices[0] + (id - 1)] = toEdit + } else { + console.error(result.error) + throw new global.ServerError(400, "Invalid Data!"); + } + } else { + throw new Error("Type does not exist for node: " + prefix) + } + } catch(e) { + throw e + } + } + addEdge(prefix, edge) { try { let type = prefix @@ -83,7 +116,22 @@ export default class Database { throw new global.ServerError(400, "Invalid Data!"); } } else { - throw new Error("Type does not exist for edge: " + id) + throw new Error("Type does not exist for edge: " + prefix) + } + } catch(e) { + throw e + } + } + + deleteEdge(prefix, id) { + try { + let model = edgeModels[prefix] + if(model) { + console.log(model.indices[0] + (id - 1)) + this.edges[model.indices[0] + (id - 1)] = 0 + console.log(this.edges[model.indices[0] + (id - 1)]) + } else { + throw new Error("Type does not exist for edge: " + prefix) } } catch(e) { throw e diff --git a/server/db/model/edge.js b/server/db/model/edge.js index b3f102c..344362b 100644 --- a/server/db/model/edge.js +++ b/server/db/model/edge.js @@ -1,13 +1,21 @@ export default class Edge { - add(n) { + splitEdge(n) { let toPrefix = n.to.split("-")[0] let fromPrefix = n.from.split("-")[0] let type = n.type - let prefix = `${fromPrefix}_${type}_${toPrefix}` + return `${fromPrefix}_${type}_${toPrefix}` + } + add(n) { + let prefix = this.splitEdge(n) global.db.addEdge(prefix, n) } + delete(n) { + let prefix = this.splitEdge(n) + global.db.deleteEdge(prefix, n.from.split("-")[1]) + } + getByFrom(fromID) { let result = [] for(let i = 0; i < this.entries.length; i++) { diff --git a/server/db/model/edges/POST_BY_MEMBER.js b/server/db/model/edges/POST_BY_MEMBER.js new file mode 100644 index 0000000..fc5bd9c --- /dev/null +++ b/server/db/model/edges/POST_BY_MEMBER.js @@ -0,0 +1,37 @@ +import { z } from 'zod' + +export default class POST_BY_MEMBER { + prefix = "POST_BY_MEMBER" + indices = null + + constructor(indices) { + this.indices = indices + } + + schema = z.object({ + id: z.number(), + type: z.string(), + from: z.string(), + to: z.string(), + created: z.string() + }) + .strict() + + getAuthorId(postId) { + for (let i = this.indices[0]; i < this.indices[1]; i++) { + if (global.db.edges[i].from === postId) { + return Number(global.db.edges[i].to.split("-")[1]); + } + } + } + + getByMember(stringID) { + let result = [] + for(let i = this.indices[0]; i < this.indices[1]; i++) { + if(global.db.edges[i].from === stringID) { + result.push(global.db.edges[i]) + } + } + return result + } +} \ No newline at end of file diff --git a/server/db/model/edges/POST_FROM_NETWORK.js b/server/db/model/edges/POST_FROM_NETWORK.js new file mode 100644 index 0000000..96aeabd --- /dev/null +++ b/server/db/model/edges/POST_FROM_NETWORK.js @@ -0,0 +1,29 @@ +import { z } from 'zod' + +export default class POST_FROM_NETWORK { + prefix = "POST_FROM_NETWORK" + indices = null + + constructor(indices) { + this.indices = indices + } + + schema = z.object({ + id: z.number(), + type: z.string(), + from: z.string(), + to: z.string(), + created: z.string() + }) + .strict() + + getByNetwork(id) { + let result = [] + for(let i = this.indices[0]; i < this.indices[1]; i++) { + if(global.db.edges[i].to === `${global.db.networks.prefix}-${id}`) { + result.push(global.db.edges[i]) + } + } + return result + } +} \ No newline at end of file diff --git a/server/db/model/forum/post.js b/server/db/model/forum/post.js index 00d297c..e3e453c 100644 --- a/server/db/model/forum/post.js +++ b/server/db/model/forum/post.js @@ -1,6 +1,7 @@ import { z } from 'zod'; export default class Post { + prefix = "POST" indices = null constructor(indices) { @@ -8,13 +9,16 @@ export default class Post { } schema = z.object({ + id: z.number(), text: z.string(), time: z.string(), - sentBy: z.string() + sentBy: z.string(), + edited: z.boolean() }) makeID(forum, number) { - return `POST-${forum}-${number}` + // return `POST-${forum}-${number}` + return `POST-${number}` } save(post, id) { @@ -32,30 +36,130 @@ export default class Post { } } - get(forum, number) { + get(forum, by, authorId = null) { let result = [] - let limit = Math.min(number, this.entries.length) - for(let i=1; i<=limit; i++) { - let id = this.makeID(forum, i) - let post = this.entries[this.ids[id]] - let {firstName, lastName} = global.db.members.get(post.sentBy) - let seededObj = { - ...post - } - seededObj.sentByID = post.sentBy - seededObj.sentBy = firstName + " " + lastName - result.push(seededObj) + if (by === "member" && authorId) { + result = this.getByMember(authorId) + } else { // network + let { id: networkId } = global.db.networks.getByAbbreviation(forum) + result = this.getByNetwork(networkId) } return result } + getByID(id) { + if(typeof id === 'string') { + id = id.split("-")[1] + } + return { + id, + authorId: this.getAuthor(id), + ...global.db.nodes[this.indices[0] + (id - 1)] + } + } + + getAuthor(postId) { + return db.POST_BY_MEMBER.getAuthorId(`${this.prefix}-${postId}`); + } + + getByNetwork(id) { + let connections = db.POST_FROM_NETWORK.getByNetwork(id) + let posts = [] + connections.forEach((conn) => { + posts.push(this.getByID(conn.from)) + }) + return posts + } + + getByMember(stringID) { + let connections = db.POST_BY_MEMBER.getByMember(stringID) + let posts = [] + connections.forEach((conn) => { + posts.push(this.getByID(conn.from)) + }) + return posts + } + + async edit(id, text, userEmail) { + try { + let userId = global.db.members.getByEmail(userEmail).id + let postToEdit = this.getByID(id) + + if (postToEdit.authorId !== userId) { + throw new global.ServerError(401, "Not authorized to delete post!") + } + + postToEdit.text = text + postToEdit.time = global.currentTime() + postToEdit.edited = true; + + let { authorId, ...rest } = postToEdit + global.db.editNode(this.prefix, id, rest) + + return postToEdit + } catch(e) { + console.error(e) + throw new global.ServerError(400, "Failed to delete post!") + } + } + + async delete(id, forum, userEmail) { + try { + let userId = global.db.members.getByEmail(userEmail).id + let network = global.db.networks.getByAbbreviation(forum) + + if (this.getAuthor(id) !== userId) { + throw new global.ServerError(401, "Not authorized to delete post!") + } + + global.db.deleteNode(this.prefix, id) + + if(network) { + global.db.edge.delete({ + type: "FROM", + from: `${this.prefix}-${id}`, + to: `NETWORK-${network.id}` + }) + } + global.db.edge.delete({ + type: "BY", + from: `${this.prefix}-${id}`, + to: `MEMBER-${userId}` + }) + } catch(e) { + console.error(e) + throw new global.ServerError(400, "Failed to delete post!") + } + } + async add(text, forum, userEmail) { let newPost = {} - newPost.text = text - newPost.sentBy = db.members.getIDFromEmail(userEmail) - newPost.time = global.currentTime() + let sender = global.db.members.getByEmail(userEmail) + let network = global.db.networks.getByAbbreviation(forum) - let idNumber = this.entries.length+1 - super.add(this.makeID(forum, idNumber), newPost) + newPost.text = text + newPost.time = global.currentTime() + + try { + newPost.sentBy = `${sender.firstName} ${sender.lastName}` + + global.db.addNode(this.prefix, newPost) + if(network) { + global.db.edge.add({ + type: "FROM", + from: `${this.prefix}-${global.db.getCurrentIndex(this)}`, + to: `NETWORK-${network.id}` + }) + } + global.db.edge.add({ + type: "BY", + from: `${this.prefix}-${global.db.getCurrentIndex(this)}`, + to: `MEMBER-${sender.id}` + }) + return `${this.prefix}-${global.db.getCurrentIndex(this)}` + } catch(e) { + console.error(e) + throw new global.ServerError(400, "Failed to add member!"); + } } } \ No newline at end of file diff --git a/server/db/model/import.js b/server/db/model/import.js index 5ecc710..df08dea 100644 --- a/server/db/model/import.js +++ b/server/db/model/import.js @@ -6,6 +6,8 @@ import Post from "./forum/post.js" import Conversation from "./dms/conversation.js" import DM from "./dms/dm.js" import MEMBER_IN_NETWORK from "./edges/MEMBER_IN_NETWORK.js" +import POST_FROM_NETWORK from "./edges/POST_FROM_NETWORK.js" +import POST_BY_MEMBER from "./edges/POST_BY_MEMBER.js" let nIndices = { "MEMBER" : [0, 0], // [id, startIndex, nextEmptyIndex @@ -18,7 +20,9 @@ let nIndices = { } let eIndices = { - "MEMBER_IN_NETWORK": [0, 0] + "MEMBER_IN_NETWORK": [0, 0], + "POST_FROM_NETWORK": [4000, 4000], + "POST_BY_MEMBER": [7000, 7000] } export let nodeModels = { @@ -32,5 +36,7 @@ export let nodeModels = { } export let edgeModels = { - MEMBER_IN_NETWORK: new MEMBER_IN_NETWORK(eIndices.MEMBER_IN_NETWORK) + MEMBER_IN_NETWORK: new MEMBER_IN_NETWORK(eIndices.MEMBER_IN_NETWORK), + POST_FROM_NETWORK: new POST_FROM_NETWORK(eIndices.POST_FROM_NETWORK), + POST_BY_MEMBER: new POST_BY_MEMBER(eIndices.POST_BY_MEMBER) } \ No newline at end of file diff --git a/server/db/model/network.js b/server/db/model/network.js index 21c1c55..70e127c 100644 --- a/server/db/model/network.js +++ b/server/db/model/network.js @@ -24,6 +24,15 @@ export default class Network { return global.db.nodes[index] } + getByAbbreviation(abbreviation) { + for(let i=this.indices[0]; i { + handleMessage = async (msg, ws) => { try { const text = msg.toString(); const req = JSON.parse(text); @@ -72,7 +72,7 @@ export default class Socket { let responseData; switch (req.app) { case "FORUM": - responseData = ForumHandler.handle(req.operation, req.msg, ws) + responseData = await ForumHandler.handle(req.operation, req.msg, ws) break; case "MESSAGES":