You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nodebb/src/topics/create.js

333 lines
9.2 KiB
JavaScript

'use strict';
var async = require('async'),
validator = require('validator'),
11 years ago
db = require('../database'),
utils = require('../../public/src/utils'),
plugins = require('../plugins'),
user = require('../user'),
meta = require('../meta'),
posts = require('../posts'),
privileges = require('../privileges'),
11 years ago
categories = require('../categories');
module.exports = function(Topics) {
Topics.create = function(data, callback) {
// This is an interal method, consider using Topics.post instead
10 years ago
var timestamp = data.timestamp || Date.now();
var topicData;
10 years ago
async.waterfall([
function(next) {
db.incrObjectField('global', 'nextTid', next);
},
function(tid, next) {
var slug = utils.slugify(data.title);
10 years ago
if (!slug.length) {
return callback(new Error('[[error:invalid-title]]'));
}
10 years ago
slug = tid + '/' + slug;
topicData = {
'tid': tid,
'uid': data.uid,
'cid': data.cid,
'mainPid': 0,
'title': data.title,
'slug': slug,
'timestamp': timestamp,
'lastposttime': 0,
'postcount': 0,
'viewcount': 0,
'locked': 0,
'deleted': 0,
'pinned': 0
};
if (data.thumb) {
topicData.thumb = data.thumb;
}
10 years ago
plugins.fireHook('filter:topic.create', {topic: topicData}, next);
},
function(data, next) {
topicData = data.topic;
db.setObject('topic:' + topicData.tid, topicData, next);
},
function(next) {
async.parallel([
function(next) {
10 years ago
db.sortedSetsAdd([
'topics:tid',
10 years ago
'cid:' + topicData.cid + ':tids',
'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids'
], timestamp, topicData.tid, next);
},
function(next) {
10 years ago
user.addTopicIdToUser(topicData.uid, topicData.tid, timestamp, next);
},
function(next) {
10 years ago
db.incrObjectField('category:' + topicData.cid, 'topic_count', next);
},
function(next) {
db.incrObjectField('global', 'topicCount', next);
},
function(next) {
10 years ago
Topics.createTags(data.tags, topicData.tid, timestamp, next);
}
10 years ago
], next);
},
function(results, next) {
plugins.fireHook('action:topic.save', topicData);
next(null, topicData.tid);
}
], callback);
};
Topics.post = function(data, callback) {
10 years ago
var uid = data.uid;
var title = data.title ? data.title.trim() : data.title;
data.tags = data.tags || [];
async.waterfall([
10 years ago
function(next) {
check(title, meta.config.minimumTitleLength, meta.config.maximumTitleLength, 'title-too-short', 'title-too-long', next);
10 years ago
},
function(next) {
check(data.tags, meta.config.minimumTagsPerTopic, meta.config.maximumTagsPerTopic, 'not-enough-tags', 'too-many-tags', next);
},
10 years ago
function(next) {
9 years ago
if (data.content) {
data.content = data.content.rtrim();
}
check(data.content, meta.config.minimumPostLength, meta.config.maximumPostLength, 'content-too-short', 'content-too-long', next);
10 years ago
},
function(next) {
10 years ago
categories.exists(data.cid, next);
},
function(categoryExists, next) {
if (!categoryExists) {
return next(new Error('[[error:no-category]]'));
}
10 years ago
privileges.categories.can('topics:create', data.cid, data.uid, next);
},
11 years ago
function(canCreate, next) {
10 years ago
if (!canCreate) {
return next(new Error('[[error:no-privileges]]'));
}
if (!guestHandleValid(data)) {
return next(new Error('[[error:guest-handle-invalid]]'));
}
10 years ago
user.isReadyToPost(data.uid, data.cid, next);
},
function(next) {
plugins.fireHook('filter:topic.post', data, next);
},
function(filteredData, next) {
10 years ago
data = filteredData;
Topics.create({uid: data.uid, title: data.title, cid: data.cid, thumb: data.thumb, tags: data.tags, timestamp: data.timestamp}, next);
},
function(tid, next) {
10 years ago
posts.create({uid: data.uid, tid: tid, handle: data.handle, content: data.content, timestamp: data.timestamp, ip: data.req ? data.req.ip : null}, next);
},
function(postData, next) {
onNewPost(postData, data, next);
},
function(postData, next) {
11 years ago
async.parallel({
postData: function(next) {
next(null, postData);
},
settings: function(next) {
user.getSettings(uid, function(err, settings) {
if (err) {
return next(err);
}
if (settings.followTopicsOnCreate) {
10 years ago
Topics.follow(postData.tid, uid, next);
11 years ago
} else {
next();
}
});
},
topicData: function(next) {
10 years ago
Topics.getTopicsByTids([postData.tid], uid, next);
}
11 years ago
}, next);
},
function(data, next) {
10 years ago
if (!Array.isArray(data.topicData) || !data.topicData.length) {
11 years ago
return next(new Error('[[error:no-topic]]'));
}
data.topicData = data.topicData[0];
data.topicData.unreplied = 1;
data.topicData.mainPost = data.postData;
10 years ago
data.postData.index = 0;
11 years ago
plugins.fireHook('action:topic.post', data.topicData);
11 years ago
if (parseInt(uid, 10)) {
user.notifications.sendTopicNotificationToFollowers(uid, data.topicData, data.postData);
}
11 years ago
next(null, {
topicData: data.topicData,
postData: data.postData
});
}
], callback);
};
Topics.reply = function(data, callback) {
9 years ago
var tid = data.tid;
var uid = data.uid;
var content = data.content;
var postData;
10 years ago
var cid;
9 years ago
async.waterfall([
function(next) {
10 years ago
Topics.getTopicField(tid, 'cid', next);
},
function(_cid, next) {
cid = _cid;
async.parallel({
10 years ago
exists: async.apply(Topics.exists, tid),
locked: async.apply(Topics.isLocked, tid),
canReply: async.apply(privileges.topics.can, 'topics:reply', tid, uid),
10 years ago
isAdmin: async.apply(user.isAdministrator, uid),
isModerator: async.apply(user.isModerator, uid, cid)
}, next);
},
function(results, next) {
if (!results.exists) {
return next(new Error('[[error:no-topic]]'));
}
10 years ago
if (results.locked && !results.isAdmin && !results.isModerator) {
return next(new Error('[[error:topic-locked]]'));
}
10 years ago
if (!results.canReply) {
return next(new Error('[[error:no-privileges]]'));
}
if (!guestHandleValid(data)) {
return next(new Error('[[error:guest-handle-invalid]]'));
}
10 years ago
user.isReadyToPost(uid, cid, next);
},
function(next) {
plugins.fireHook('filter:topic.reply', data, next);
},
function(filteredData, next) {
content = filteredData.content || data.content;
if (content) {
9 years ago
content = content.rtrim();
}
check(content, meta.config.minimumPostLength, meta.config.maximumPostLength, 'content-too-short', 'content-too-long', next);
10 years ago
},
function(next) {
posts.create({uid: uid, tid: tid, handle: data.handle, content: content, toPid: data.toPid, timestamp: data.timestamp, ip: data.req ? data.req.ip : null}, next);
},
10 years ago
function(_postData, next) {
postData = _postData;
onNewPost(postData, data, next);
},
function(postData, next) {
user.getSettings(uid, next);
},
function(settings, next) {
if (settings.followTopicsOnReply) {
Topics.follow(postData.tid, uid);
}
if (parseInt(uid, 10)) {
user.setUserField(uid, 'lastonline', Date.now());
}
Topics.notifyFollowers(postData, uid);
10 years ago
plugins.fireHook('action:topic.reply', postData);
next(null, postData);
}
], callback);
};
function onNewPost(postData, data, callback) {
var tid = postData.tid;
var uid = postData.uid;
async.waterfall([
function (next) {
Topics.markAsUnreadForAll(tid, next);
},
function (next) {
Topics.markAsRead([tid], uid, next);
},
function (markedRead, next) {
async.parallel({
userInfo: function(next) {
posts.getUserInfoForPosts([postData.uid], uid, next);
},
topicInfo: function(next) {
10 years ago
Topics.getTopicFields(tid, ['tid', 'title', 'slug', 'cid', 'postcount'], next);
},
9 years ago
parents: function(next) {
Topics.addParentPosts([postData], next);
},
content: function(next) {
posts.parsePost(postData, next);
}
}, next);
11 years ago
},
function (results, next) {
postData.user = results.userInfo[0];
postData.topic = results.topicInfo;
postData.index = parseInt(results.topicInfo.postcount, 10) - 1;
// Username override for guests, if enabled
if (parseInt(meta.config.allowGuestHandles, 10) === 1 && parseInt(postData.uid, 10) === 0 && data.handle) {
postData.user.username = validator.escape(data.handle);
}
postData.favourited = false;
postData.votes = 0;
postData.display_moderator_tools = true;
postData.display_move_tools = true;
postData.selfPost = false;
postData.relativeTime = utils.toISOString(postData.timestamp);
10 years ago
postData.topic.title = validator.escape(postData.topic.title);
10 years ago
next(null, postData);
}
], callback);
10 years ago
}
function check(item, min, max, minError, maxError, callback) {
if (!item || item.length < parseInt(min, 10)) {
return callback(new Error('[[error:'+ minError + ', ' + min + ']]'));
} else if (item.length > parseInt(max, 10)) {
return callback(new Error('[[error:'+ maxError + ', ' + max + ']]'));
10 years ago
}
callback();
}
function guestHandleValid(data) {
if (parseInt(meta.config.allowGuestHandles, 10) === 1 && parseInt(data.uid, 10) === 0 &&
data.handle && data.handle.length > meta.config.maximumUsernameLength) {
return false;
}
return true;
}
};