From 9738e202077be02ecb3b45c118015ccce7dbf05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 17 Oct 2020 15:07:04 -0400 Subject: [PATCH] refactor: merge post.edit fix: dont fadeout/fadeint if title/post didnt change --- public/src/client/topic/events.js | 42 ++++++++++--------- src/api/index.js | 1 + src/api/posts.js | 65 +++++++++++++++++++++++++++++ src/controllers/write/posts.js | 68 +++---------------------------- src/posts/edit.js | 1 + src/socket.io/posts/edit.js | 56 +------------------------ 6 files changed, 97 insertions(+), 136 deletions(-) create mode 100644 src/api/posts.js diff --git a/public/src/client/topic/events.js b/public/src/client/topic/events.js index 104d741068de..0d158044f36d 100644 --- a/public/src/client/topic/events.js +++ b/public/src/client/topic/events.js @@ -110,7 +110,7 @@ define('forum/topic/events', [ var navbarTitle = components.get('navbar/title').find('span'); var breadCrumb = components.get('breadcrumb/current'); - if (topicTitle.length && data.topic.title && topicTitle.html() !== data.topic.title) { + if (topicTitle.length && data.topic.title && data.topic.renamed) { ajaxify.data.title = data.topic.title; var newUrl = 'topic/' + data.topic.slug + (window.location.search ? window.location.search : ''); history.replaceState({ url: newUrl }, null, window.location.protocol + '//' + window.location.host + config.relative_path + '/' + newUrl); @@ -126,27 +126,29 @@ define('forum/topic/events', [ }); } - editedPostEl.fadeOut(250, function () { - editedPostEl.html(translator.unescape(data.post.content)); - editedPostEl.find('img:not(.not-responsive)').addClass('img-responsive'); - images.wrapImagesInLinks(editedPostEl.parent()); - posts.addBlockquoteEllipses(editedPostEl.parent()); - editedPostEl.fadeIn(250); - - var editData = { - editor: data.editor, - editedISO: utils.toISOString(data.post.edited), - }; - - Benchpress.parse('partials/topic/post-editor', editData, function (html) { - translator.translate(html, function (translated) { - html = $(translated); - editorEl.replaceWith(html); - $('[data-pid="' + data.post.pid + '"] [component="post/editor"] .timeago').timeago(); - $(window).trigger('action:posts.edited', data); + if (data.post.changed) { + editedPostEl.fadeOut(250, function () { + editedPostEl.html(translator.unescape(data.post.content)); + editedPostEl.find('img:not(.not-responsive)').addClass('img-responsive'); + images.wrapImagesInLinks(editedPostEl.parent()); + posts.addBlockquoteEllipses(editedPostEl.parent()); + editedPostEl.fadeIn(250); + + var editData = { + editor: data.editor, + editedISO: utils.toISOString(data.post.edited), + }; + + Benchpress.parse('partials/topic/post-editor', editData, function (html) { + translator.translate(html, function (translated) { + html = $(translated); + editorEl.replaceWith(html); + $('[data-pid="' + data.post.pid + '"] [component="post/editor"] .timeago').timeago(); + $(window).trigger('action:posts.edited', data); + }); }); }); - }); + } if (data.topic.tags && tagsUpdated(data.topic.tags)) { Benchpress.parse('partials/topic/tags', { tags: data.topic.tags }, function (html) { diff --git a/src/api/index.js b/src/api/index.js index 592092d0482c..32caa26db53a 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -4,5 +4,6 @@ module.exports = { users: require('./users'), groups: require('./groups'), topics: require('./topics'), + posts: require('./posts'), categories: require('./categories'), }; diff --git a/src/api/posts.js b/src/api/posts.js new file mode 100644 index 000000000000..8550222e2290 --- /dev/null +++ b/src/api/posts.js @@ -0,0 +1,65 @@ +'use strict'; + +const validator = require('validator'); +const _ = require('lodash'); + +const utils = require('../utils'); +const posts = require('../posts'); +const groups = require('../groups'); +const meta = require('../meta'); +const events = require('../events'); +const apiHelpers = require('./helpers'); +const websockets = require('../socket.io'); + +const postsAPI = module.exports; + +postsAPI.edit = async function (caller, data) { + if (!data || !data.pid || (meta.config.minimumPostLength !== 0 && !data.content)) { + throw new Error('[[error:invalid-data]]'); + } + // Trim and remove HTML (latter for composers that send in HTML, like redactor) + const contentLen = utils.stripHTMLTags(data.content).trim().length; + + if (data.title && data.title.length < meta.config.minimumTitleLength) { + throw new Error('[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]'); + } else if (data.title && data.title.length > meta.config.maximumTitleLength) { + throw new Error('[[error:title-too-long, ' + meta.config.maximumTitleLength + ']]'); + } else if (meta.config.minimumPostLength !== 0 && contentLen < meta.config.minimumPostLength) { + throw new Error('[[error:content-too-short, ' + meta.config.minimumPostLength + ']]'); + } else if (contentLen > meta.config.maximumPostLength) { + throw new Error('[[error:content-too-long, ' + meta.config.maximumPostLength + ']]'); + } + + data.uid = caller.uid; + data.req = apiHelpers.buildReqObject(caller); + + const editResult = await posts.edit(data); + if (editResult.topic.renamed) { + await events.log({ + type: 'topic-rename', + uid: caller.uid, + ip: caller.ip, + tid: editResult.topic.tid, + oldTitle: validator.escape(String(editResult.topic.oldTitle)), + newTitle: validator.escape(String(editResult.topic.title)), + }); + } + const postObj = await posts.getPostSummaryByPids([editResult.post.pid], caller.uid, {}); + const returnData = { ...postObj[0], ...editResult.post }; + + if (!editResult.post.deleted) { + websockets.in('topic_' + editResult.topic.tid).emit('event:post_edited', editResult); + return returnData; + } + + const memberData = await groups.getMembersOfGroups([ + 'administrators', + 'Global Moderators', + 'cid:' + editResult.topic.cid + ':privileges:moderate', + 'cid:' + editResult.topic.cid + ':privileges:groups:moderate', + ]); + + const uids = _.uniq(_.flatten(memberData).concat(String(caller.uid))); + uids.forEach(uid => websockets.in('uid_' + uid).emit('event:post_edited', editResult)); + return returnData; +}; diff --git a/src/controllers/write/posts.js b/src/controllers/write/posts.js index eaf90339223b..28ef17cd110e 100644 --- a/src/controllers/write/posts.js +++ b/src/controllers/write/posts.js @@ -1,16 +1,11 @@ 'use strict'; -const validator = require('validator'); -const _ = require('lodash'); - -const meta = require('../../meta'); const privileges = require('../../privileges'); -const groups = require('../../groups'); const posts = require('../../posts'); const topics = require('../../topics'); const events = require('../../events'); -const utils = require('../../utils'); +const api = require('../../api'); const helpers = require('../helpers'); const sockets = require('../../socket.io'); const apiHelpers = require('../../api/helpers'); @@ -19,65 +14,14 @@ const socketPostHelpers = require('../../socket.io/posts/helpers'); // eehhh... const Posts = module.exports; Posts.edit = async (req, res) => { - // Trim and remove HTML (latter for composers that send in HTML, like redactor) - var contentLen = utils.stripHTMLTags(req.body.content).trim().length; - - if (req.body.title && req.body.title.length < meta.config.minimumTitleLength) { - throw new Error('[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]'); - } else if (req.body.title && req.body.title.length > meta.config.maximumTitleLength) { - throw new Error('[[error:title-too-long, ' + meta.config.maximumTitleLength + ']]'); - } else if (meta.config.minimumPostLength !== 0 && contentLen < meta.config.minimumPostLength) { - throw new Error('[[error:content-too-short, ' + meta.config.minimumPostLength + ']]'); - } else if (contentLen > meta.config.maximumPostLength) { - throw new Error('[[error:content-too-long, ' + meta.config.maximumPostLength + ']]'); - } - - // Payload construction - var payload = { - req, - uid: req.user.uid, + const editResult = await api.posts.edit(req, { + ...req.body, pid: req.params.pid, - content: req.body.content, - options: {}, - }; - ['handle', 'title'].forEach((prop) => { - if (req.body.hasOwnProperty(prop)) { - payload[prop] = req.body[prop]; - } - }); - ['topic_thumb', 'tags'].forEach((prop) => { - if (req.body.hasOwnProperty(prop)) { - payload.options[prop] = req.body[prop]; - } + uid: req.uid, + req: apiHelpers.buildReqObject(req), }); - const editResult = await posts.edit(payload); - helpers.formatApiResponse(200, res, await posts.getPostSummaryByPids([editResult.pid], req.user.uid, {})); - - if (editResult.topic.renamed) { - await events.log({ - type: 'topic-rename', - uid: req.user.uid, - ip: req.ip, - tid: editResult.topic.tid, - oldTitle: validator.escape(String(editResult.topic.oldTitle)), - newTitle: validator.escape(String(editResult.topic.title)), - }); - } - - if (!editResult.post.deleted) { - sockets.in('topic_' + editResult.topic.tid).emit('event:post_edited', editResult); - } - - const memberData = await groups.getMembersOfGroups([ - 'administrators', - 'Global Moderators', - 'cid:' + editResult.topic.cid + ':privileges:moderate', - 'cid:' + editResult.topic.cid + ':privileges:groups:moderate', - ]); - - const uids = _.uniq(_.flatten(memberData).concat(req.user.uid.toString())); - uids.forEach(uid => sockets.in('uid_' + uid).emit('event:post_edited', editResult)); + helpers.formatApiResponse(200, res, editResult); }; Posts.purge = async (req, res) => { diff --git a/src/posts/edit.js b/src/posts/edit.js index 9c15c5ee1b32..91dcd8de26a5 100644 --- a/src/posts/edit.js +++ b/src/posts/edit.js @@ -67,6 +67,7 @@ module.exports = function (Posts) { returnPostData.cid = topic.cid; returnPostData.topic = topic; returnPostData.editedISO = utils.toISOString(now); + returnPostData.changed = oldContent !== data.content; await topics.notifyFollowers(returnPostData, data.uid, { type: 'post-edit', diff --git a/src/socket.io/posts/edit.js b/src/socket.io/posts/edit.js index 0b2a08ff171d..e679c4639519 100644 --- a/src/socket.io/posts/edit.js +++ b/src/socket.io/posts/edit.js @@ -1,14 +1,6 @@ 'use strict'; -const validator = require('validator'); -const _ = require('lodash'); - -const posts = require('../../posts'); -const groups = require('../../groups'); -const events = require('../../events'); -const meta = require('../../meta'); -const utils = require('../../utils'); -const apiHelpers = require('../../api/helpers'); +const api = require('../../api'); const websockets = require('../index'); module.exports = function (SocketPosts) { @@ -17,52 +9,8 @@ module.exports = function (SocketPosts) { if (!socket.uid) { throw new Error('[[error:not-logged-in]]'); - } else if (!data || !data.pid || (meta.config.minimumPostLength !== 0 && !data.content)) { - throw new Error('[[error:invalid-data]]'); - } - - // Trim and remove HTML (latter for composers that send in HTML, like redactor) - var contentLen = utils.stripHTMLTags(data.content).trim().length; - - if (data.title && data.title.length < meta.config.minimumTitleLength) { - throw new Error('[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]'); - } else if (data.title && data.title.length > meta.config.maximumTitleLength) { - throw new Error('[[error:title-too-long, ' + meta.config.maximumTitleLength + ']]'); - } else if (meta.config.minimumPostLength !== 0 && contentLen < meta.config.minimumPostLength) { - throw new Error('[[error:content-too-short, ' + meta.config.minimumPostLength + ']]'); - } else if (contentLen > meta.config.maximumPostLength) { - throw new Error('[[error:content-too-long, ' + meta.config.maximumPostLength + ']]'); - } - - data.uid = socket.uid; - data.req = apiHelpers.buildReqObject(socket); - - const editResult = await posts.edit(data); - if (editResult.topic.renamed) { - await events.log({ - type: 'topic-rename', - uid: socket.uid, - ip: socket.ip, - tid: editResult.topic.tid, - oldTitle: validator.escape(String(editResult.topic.oldTitle)), - newTitle: validator.escape(String(editResult.topic.title)), - }); } - if (!editResult.post.deleted) { - websockets.in('topic_' + editResult.topic.tid).emit('event:post_edited', editResult); - return editResult.post; - } - - const memberData = await groups.getMembersOfGroups([ - 'administrators', - 'Global Moderators', - 'cid:' + editResult.topic.cid + ':privileges:moderate', - 'cid:' + editResult.topic.cid + ':privileges:groups:moderate', - ]); - - const uids = _.uniq(_.flatten(memberData).concat(socket.uid.toString())); - uids.forEach(uid => websockets.in('uid_' + uid).emit('event:post_edited', editResult)); - return editResult.post; + return await api.posts.edit(socket, data); }; };