'use strict'; var winston = require('winston'), async = require('async'), nconf = require('nconf'), validator = require('validator'), db = require('./database'), posts = require('./posts'), topics = require('./topics'), threadTools = require('./threadTools'), privileges = require('./privileges'), user = require('./user'), utils = require('../public/src/utils'), plugins = require('./plugins'), events = require('./events'), meta = require('./meta'); (function(PostTools) { PostTools.edit = function(uid, pid, title, content, options, callback) { options = options || {}; async.waterfall([ function (next) { privileges.posts.canEdit(pid, uid, next); }, function(canEdit, next) { if (!canEdit) { return next(new Error('[[error:no-privileges]]')); } posts.getPostData(pid, next); }, function(postData, next) { postData.content = content; plugins.fireHook('filter:post.save', postData, next); } ], function(err, postData) { if (err) { return callback(err); } async.parallel({ post: function(next) { posts.setPostFields(pid, { edited: Date.now(), editor: uid, content: postData.content }, next); }, topic: function(next) { var tid = postData.tid; posts.isMain(pid, function(err, isMainPost) { if (err) { return next(err); } options.tags = options.tags || []; if (isMainPost) { title = title.trim(); var topicData = { title: title, slug: tid + '/' + utils.slugify(title) }; if (options.topic_thumb) { topicData.thumb = options.topic_thumb; } db.setObject('topic:' + tid, topicData, function(err) { plugins.fireHook('action:topic.edit', tid); }); topics.updateTags(tid, options.tags); } next(null, { tid: tid, title: validator.escape(title), isMainPost: isMainPost, tags: options.tags.map(function(tag) { return {name:tag}; }) }); }); }, content: function(next) { PostTools.parse(postData.content, next); } }, function(err, results) { if (err) { return callback(err); } events.logPostEdit(uid, pid); plugins.fireHook('action:post.edit', postData); callback(null, results); }); }); }; PostTools.delete = function(uid, pid, callback) { togglePostDelete(uid, pid, true, callback); }; PostTools.restore = function(uid, pid, callback) { togglePostDelete(uid, pid, false, callback); }; function togglePostDelete(uid, pid, isDelete, callback) { async.waterfall([ function(next) { posts.getPostField(pid, 'deleted', next); }, function(deleted, next) { if(parseInt(deleted, 10) === 1 && isDelete) { return next(new Error('[[error:post-already-deleted]]')); } else if(parseInt(deleted, 10) !== 1 && !isDelete) { return next(new Error('[[error:post-already-restored]]')); } privileges.posts.canEdit(pid, uid, next); }, function(canEdit, next) { if (!canEdit) { return next(new Error('[[error:no-privileges]]')); } next(); } ], function(err) { if(err) { return callback(err); } posts.setPostField(pid, 'deleted', isDelete ? 1 : 0, function(err) { if (err) { return callback(err); } events[isDelete ? 'logPostDelete' : 'logPostRestore'](uid, pid); db.incrObjectFieldBy('global', 'postCount', isDelete ? -1 : 1); posts.getPostFields(pid, ['pid', 'tid', 'uid', 'content', 'timestamp'], function(err, postData) { if (err) { return callback(err); } if (isDelete) { plugins.fireHook('action:post.delete', pid); } else { plugins.fireHook('action:post.restore', postData); } async.parallel([ function(next) { topics[isDelete ? 'decreasePostCount' : 'increasePostCount'](postData.tid, next); }, function(next) { user.incrementUserPostCountBy(postData.uid, isDelete ? -1 : 1, next); }, function(next) { updateTopicTimestamp(postData.tid, next); }, function(next) { addOrRemoveFromCategory(pid, postData.tid, postData.timestamp, isDelete, next); } ], function(err) { if (!isDelete) { PostTools.parse(postData.content, function(err, parsed) { postData.content = parsed; callback(err, postData); }); return; } callback(err, postData); }); }); }); }); } PostTools.purge = function(uid, pid, callback) { privileges.posts.canEdit(pid, uid, function(err, canEdit) { if (err || !canEdit) { return callback(err || new Error('[[error:no-privileges]]')); } posts.purge(pid, callback); }); }; function updateTopicTimestamp(tid, callback) { topics.getLatestUndeletedPid(tid, function(err, pid) { if(err || !pid) { return callback(err); } posts.getPostField(pid, 'timestamp', function(err, timestamp) { if (err) { return callback(err); } if (timestamp) { topics.updateTimestamp(tid, timestamp); } callback(); }); }); } function addOrRemoveFromCategory(pid, tid, timestamp, isDelete, callback) { topics.getTopicField(tid, 'cid', function(err, cid) { if (err) { return callback(err); } db.incrObjectFieldBy('category:' + cid, 'post_count', isDelete ? -1 : 1); if (isDelete) { db.sortedSetRemove('categories:recent_posts:cid:' + cid, pid, callback); } else { db.sortedSetAdd('categories:recent_posts:cid:' + cid, timestamp, pid, callback); } }); } PostTools.parse = function(raw, callback) { parse('filter:post.parse', raw, callback); }; PostTools.parseSignature = function(raw, callback) { parse('filter:post.parseSignature', raw, callback); }; function parse(hook, raw, callback) { raw = raw || ''; plugins.fireHook(hook, raw, function(err, parsed) { callback(null, !err ? parsed : raw); }); } }(exports));