diff --git a/src/modules/api/submodules/forum.ts b/src/modules/api/submodules/forum.ts index 9ef878b..69e87b5 100644 --- a/src/modules/api/submodules/forum.ts +++ b/src/modules/api/submodules/forum.ts @@ -5,6 +5,18 @@ import utils from '../../../utils/utils' import { Request, SubmoduleData, User } from '../../../types/basicTypes' const adminUsersFile = 'data/admins.json' +const forumContentsFileName = '.contents.json' + +function countComments(comments) { + return comments.reduce((acc, comment) => { + if (comment.subComments) { + acc += countComments(comment.subComments) + 1 + } else { + acc += 1 + } + return acc + }, 0) +} function addComment(obj, path, comment) { if (path.length === 0) { @@ -69,77 +81,171 @@ function addReaction(obj, path, { reaction, isDelete, uid }) { } } +function getForumData( + forumName: string, + forumDir: string +): { forumPath: string; contentFilePath: string; content: any } { + const safeForumName = forumName.replace(/\./g, '').replace(/\/+/g, '') + const forumPath = forumDir + '/' + safeForumName + const contentFilePath = forumPath + '/' + forumContentsFileName + + if (!utils.FileExists(forumPath)) { + utils.CreatePath(forumPath, true) + } + + if (!utils.FileExists(contentFilePath)) { + utils.WriteFile('[]', contentFilePath) + } + const contents = utils.ReadJSON(contentFilePath) + return { + forumPath: forumPath, + contentFilePath: contentFilePath, + contents: contents, + } +} + +function getPostData(postKey, contents, forumPath) { + const safePostKey = postKey.replace(/\./g, '').replace(/\/+/g, '') + const postPath = forumPath + '/' + safePostKey + if (!contents[postKey] || !utils.FileExists(postPath)) { + return + } + return { postData: utils.ReadJSON(postPath), postPath: postPath } +} + function setup(data: SubmoduleData): void { const { app, /* userDB, url, */ publicdirs /*, moduleSpecificData */ } = data const publicDir = publicdirs[0] - const newsFile = publicDir + 'news.json' + const forumDir = publicDir + 'forum' - app.post('/react', (req: Request, res) => { + if (!utils.FileExists(forumDir)) { + utils.CreatePath(forumDir, true) + } + + app.get('/forumEntries', (req: Request, res) => { logger.LogReq(req) - const user: User = req.session.user - const news: any = utils.ReadJSON(newsFile) - - const { newsKey, path, reaction, isDelete } = req.body - if (!newsKey || !reaction) { - res.json({ status: 'fail', msg: 'no newskey or reaction' }) + const forumName: any = req.query.forumName + if (!forumName) { + res.json({ + success: false, + msg: `Forum name is not specified!`, + }) return } - if (!path || path.length === 0) { - if (news[newsKey]) { - if (isDelete) { - if (news[newsKey].reacts) { - news[newsKey].reacts[reaction] = news[newsKey].reacts[ - reaction - ].filter((uid) => { - return uid !== user.id - }) - if (news[newsKey].reacts[reaction].length === 0) { - delete news[newsKey].reacts[reaction] - } - } - } else { - if (!news[newsKey].reacts) { - news[newsKey].reacts = { [reaction]: [user.id] } - } else { - if (Array.isArray(news[newsKey].reacts[reaction])) { - if (!news[newsKey].reacts[reaction].includes(user.id)) { - news[newsKey].reacts[reaction].push(user.id) - } - } else { - news[newsKey].reacts[reaction] = [user.id] - } - } - } - } - } else { - addReaction(news[newsKey].comments, path, { - reaction: reaction, - isDelete: isDelete, - uid: user.id, + + const { forumPath, contents } = getForumData(forumName, forumDir) + + res.json({ + entriesPath: forumPath.replace(publicDir, ''), + contents: contents, + }) + }) + + app.post('/addPost', (req: Request, res) => { + logger.LogReq(req) + + const { title, content } = req.body + const forumName: any = req.query.forumName + if (!forumName) { + res.json({ + success: false, + msg: `Forum name is not specified!`, }) + return + } + const { contents } = getForumData(forumName, forumDir) + const user: User = req.session.user + const admins: any = utils.FileExists(adminUsersFile) + ? utils.ReadJSON(adminUsersFile) + : [] + + const newPostKey = uuidv4() + const postData = { + date: utils.GetDateString(), + user: user.id, + title: title, + admin: admins.includes(user.id), + commentCount: 0, } - utils.WriteFile(JSON.stringify(news, null, 2), newsFile) - res.json({ status: 'ok', news: news }) + contents[newPostKey] = postData + utils.WriteFile( + JSON.stringify({ ...postData, content: content }), + newPostKey + '.json' + ) + + res.json({ success: true, newEntry: { ...postData, content: content } }) + }) + + app.post('/rmPost', (req: Request, res) => { + logger.LogReq(req) + const { postKey } = req.body + const forumName: any = req.query.forumName + if (!forumName) { + res.json({ + success: false, + msg: `Forum name is not specified!`, + }) + return + } + const { forumPath, contentFilePath, contents } = getForumData( + forumName, + forumDir + ) + const user: User = req.session.user + + if (contents[postKey] && contents[postKey].user === user.id) { + utils.deleteFile(forumPath + '/' + postKey + '.json') + delete contents[postKey] + utils.WriteFile(JSON.stringify(contents), contentFilePath) + + res.json({ success: true, deletedId: postKey }) + } else { + res.json({ + success: false, + msg: + 'Entry does not exists, or you are not authorized to delete this post', + }) + return + } }) app.post('/comment', (req: Request, res) => { logger.LogReq(req) + const forumName: any = req.query.forumName + if (!forumName) { + res.json({ + success: false, + msg: `Forum name is not specified!`, + }) + return + } + const { forumPath, contentFilePath, contents } = getForumData( + forumName, + forumDir + ) const user: User = req.session.user - const news: any = utils.ReadJSON(newsFile) const admins: any = utils.FileExists(adminUsersFile) ? utils.ReadJSON(adminUsersFile) : [] - const { type, path, newsKey } = req.body - if (!type || !path || !newsKey) { - res.json({ status: 'fail', msg: ' type or path or newsKey is undefined' }) + const { type, path, postKey } = req.body + if (!postKey || !type || !path) { + res.json({ success: false, msg: 'type or path or postKey is undefined' }) return } + const { postPath, postData } = getPostData(postKey, contents, forumPath) + if (!postData) { + res.json({ + success: false, + msg: `Post entry '${postKey}' from forum '${forumName}' does not exits!`, + }) + } + if (type === 'add') { const { content } = req.body const comment = { @@ -148,70 +254,99 @@ function setup(data: SubmoduleData): void { content: content, admin: admins.includes(user.id), } - if (!news[newsKey].comments) { - news[newsKey].comments = [] + if (!postData.comments) { + postData.comments = [] } - addComment(news[newsKey].comments, path, comment) + addComment(postData.comments, path, comment) } else if (type === 'delete') { - if (news[newsKey].comments) { - const success = deleteComment(news[newsKey].comments, path, user.id) + if (postData.comments) { + const success = deleteComment(postData.comments, path, user.id) if (!success) { res.json({ - status: 'fail', + success: false, msg: 'you cant delete other users comments', - news: news, + postData: postData, }) return } } } else { - res.json({ status: 'fail', msg: 'no such type', news: news }) + res.json({ success: false, msg: 'no such type' }) return } - utils.WriteFile(JSON.stringify(news, null, 2), newsFile) - res.json({ status: 'ok', news: news }) + + contents[postKey].commentCount = countComments(postData.comments) + + utils.WriteFile(JSON.stringify(postData, null, 2), postPath) + utils.WriteFile(JSON.stringify(contents, null, 2), contentFilePath) + res.json({ success: true, postData: postData }) }) - app.post('/rmPost', (req: Request, res) => { + app.post('/react', (req: Request, res) => { logger.LogReq(req) - const user: User = req.session.user - const news: any = utils.ReadJSON(newsFile) - const { newsKey } = req.body - if (news[newsKey].user === user.id) { - delete news[newsKey] - } else { + const forumName: any = req.query.forumName + if (!forumName) { res.json({ - status: 'fail', - msg: 'u cant delete other users posts!', - news: news, + success: false, + msg: `Forum name is not specified!`, }) return } - - utils.WriteFile(JSON.stringify(news, null, 2), newsFile) - res.json({ status: 'ok', news: news }) - }) - - app.post('/addPost', (req: Request, res) => { - logger.LogReq(req) + const { forumPath, contents } = getForumData(forumName, forumDir) const user: User = req.session.user - const news: any = utils.ReadJSON(newsFile) - const admins: any = utils.FileExists(adminUsersFile) - ? utils.ReadJSON(adminUsersFile) - : [] - const { title, content } = req.body - news[uuidv4()] = { - date: utils.GetDateString(), - user: user.id, - title: title, - content: content, - admin: admins.includes(user.id), + const { postKey, path, reaction, isDelete } = req.body + if (!postKey || !reaction) { + res.json({ success: false, msg: 'no postkey or reaction' }) + return } - utils.WriteFile(JSON.stringify(news, null, 2), newsFile) - res.json({ status: 'ok', news: news }) + const { postPath, postData } = getPostData(postKey, contents, forumPath) + if (!postData) { + res.json({ + success: false, + msg: `Post entry '${postKey}' from forum '${forumName}' does not exits!`, + }) + } + + if (!path || path.length === 0) { + if (postData) { + if (isDelete) { + if (postData.reacts) { + postData.reacts[reaction] = postData.reacts[reaction].filter( + (uid) => { + return uid !== user.id + } + ) + if (postData.reacts[reaction].length === 0) { + delete postData.reacts[reaction] + } + } + } else { + if (!postData.reacts) { + postData.reacts = { [reaction]: [user.id] } + } else { + if (Array.isArray(postData.reacts[reaction])) { + if (!postData.reacts[reaction].includes(user.id)) { + postData.reacts[reaction].push(user.id) + } + } else { + postData.reacts[reaction] = [user.id] + } + } + } + } + } else { + addReaction(postData.comments, path, { + reaction: reaction, + isDelete: isDelete, + uid: user.id, + }) + } + + utils.WriteFile(JSON.stringify(postData, null, 2), postPath) + res.json({ success: true, postData: postData }) }) }