mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-06 23:52:58 +01:00
Merge remote-tracking branch 'origin/master' into email-revamp
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
"name": "nodebb",
|
||||
"license": "GPLv3 or later",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"reply": "Reply",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"fork": "Fork",
|
||||
"banned": "banned",
|
||||
"link": "Link",
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ define(function() {
|
||||
return parent.attr('data-uid');
|
||||
}
|
||||
|
||||
function updateUserButtons() {
|
||||
function updateUserBanButtons() {
|
||||
jQuery('.ban-btn').each(function(index, element) {
|
||||
var banBtn = $(element);
|
||||
var uid = getUID(banBtn);
|
||||
@@ -27,15 +27,37 @@ define(function() {
|
||||
banBtn.addClass('disabled');
|
||||
else if (isUserBanned(banBtn))
|
||||
banBtn.addClass('btn-warning');
|
||||
else if (!isUserAdmin(banBtn))
|
||||
banBtn.removeClass('disabled');
|
||||
else
|
||||
banBtn.removeClass('btn-warning');
|
||||
updateUserAdminButtons();
|
||||
});
|
||||
}
|
||||
|
||||
function updateUserAdminButtons() {
|
||||
jQuery('.admin-btn').each(function(index, element) {
|
||||
var adminBtn = $(element);
|
||||
var uid = getUID(adminBtn);
|
||||
if (isUserAdmin(adminBtn)) {
|
||||
adminBtn.attr('value', 'UnMake Admin').html('Remove Admin');
|
||||
if (uid === yourid) {
|
||||
adminBtn.addClass('disabled');
|
||||
}
|
||||
}
|
||||
else if (isUserBanned(adminBtn))
|
||||
adminBtn.addClass('disabled');
|
||||
else if (!isUserBanned(adminBtn))
|
||||
adminBtn.removeClass('disabled');
|
||||
else
|
||||
adminBtn.removeClass('btn-warning');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function initUsers() {
|
||||
|
||||
updateUserButtons();
|
||||
updateUserBanButtons();
|
||||
updateUserAdminButtons();
|
||||
|
||||
$('#users-container').on('click', '.ban-btn', function() {
|
||||
var banBtn = $(this);
|
||||
@@ -49,17 +71,56 @@ define(function() {
|
||||
socket.emit('api:admin.user.unbanUser', uid);
|
||||
banBtn.removeClass('btn-warning');
|
||||
parent.attr('data-banned', 0);
|
||||
updateUserAdminButtons();
|
||||
} else {
|
||||
bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') + '"?', function(confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('api:admin.user.banUser', uid);
|
||||
banBtn.addClass('btn-warning');
|
||||
parent.attr('data-banned', 1);
|
||||
updateUserAdminButtons();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#users-container').on('click', '.admin-btn', function() {
|
||||
var adminBtn = $(this);
|
||||
var isAdmin = isUserAdmin(adminBtn);
|
||||
var parent = adminBtn.parents('.users-box');
|
||||
var isBanned = isUserBanned(adminBtn);
|
||||
var uid = getUID(adminBtn);
|
||||
|
||||
if(uid === yourid){
|
||||
app.alert({
|
||||
title: 'Error',
|
||||
message: 'You can\'t remove yourself as Administrator!',
|
||||
type: 'danger',
|
||||
timeout: 5000
|
||||
});
|
||||
}
|
||||
else if (!isAdmin) {
|
||||
socket.emit('api:admin.user.makeAdmin', uid);
|
||||
adminBtn.attr('value', 'UnMake Admin').html('Remove Admin');
|
||||
parent.attr('data-admin', 1);
|
||||
updateUserBanButtons();
|
||||
|
||||
} else if(uid !== yourid) {
|
||||
bootbox.confirm('Do you really want to remove this user as admin "' + parent.attr('data-username') + '"?', function(confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('api:admin.user.removeAdmin', uid);
|
||||
adminBtn.attr('value', 'Make Admin').html('Make Admin');
|
||||
parent.attr('data-admin', 0);
|
||||
updateUserBanButtons();
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -334,13 +334,13 @@ define(['composer'], function(composer) {
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#post-container').delegate('.edit', 'click', function(e) {
|
||||
$('#post-container').on('click', '.edit', function(e) {
|
||||
var pid = $(this).parents('li').attr('data-pid');
|
||||
|
||||
composer.editPost(pid);
|
||||
});
|
||||
|
||||
$('#post-container').delegate('.delete', 'click', function(e) {
|
||||
$('#post-container').on('click', '.delete', function(e) {
|
||||
var pid = $(this).parents('li').attr('data-pid'),
|
||||
postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')),
|
||||
deleteAction = !postEl.hasClass('deleted') ? true : false,
|
||||
@@ -369,6 +369,21 @@ define(['composer'], function(composer) {
|
||||
}
|
||||
});
|
||||
|
||||
$('#post-container').on('click', '.fork-post', function(e) {
|
||||
var post = $(this).parents('li'),
|
||||
pid = post.attr('data-pid');
|
||||
|
||||
socket.emit('api:topic.createTopicFromPost', {pid:pid}, function(err) {
|
||||
if(err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
post.fadeOut(500, function() {
|
||||
post.remove();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#post-container').on('click', '.chat', function(e) {
|
||||
var username = $(this).parents('li.row').attr('data-username');
|
||||
var touid = $(this).parents('li.row').attr('data-uid');
|
||||
|
||||
@@ -478,7 +478,6 @@ define(['taskbar'], function(taskbar) {
|
||||
|
||||
$(reader).on('loadend', function(e) {
|
||||
var regex = /^data:.*;base64,(.*)$/;
|
||||
console.log(file);
|
||||
var matches = this.result.match(regex);
|
||||
|
||||
var fileData = {
|
||||
|
||||
@@ -349,7 +349,9 @@
|
||||
|
||||
if (blockInfo) {
|
||||
checkConditional('@first', blockInfo.iterator === 0);
|
||||
checkConditional('!@first', blockInfo.iterator !== 0);
|
||||
checkConditional('@last', blockInfo.iterator === blockInfo.total);
|
||||
checkConditional('!@last', blockInfo.iterator !== blockInfo.total);
|
||||
}
|
||||
|
||||
template = replace(namespace + d, data[d], template);
|
||||
|
||||
@@ -76,6 +76,21 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="cid-{categories.cid}-class">Custom Class</label>
|
||||
<input id="cid-{categories.cid}-class" type="text" class="form-control" placeholder="col-md-6 col-xs-6" data-name="class" value="{categories.class}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="cid-{categories.cid}-numRecentReplies"># of Recent Replies Displayed</label>
|
||||
<input id="cid-{categories.cid}-numRecentReplies" type="text" class="form-control" placeholder="2" data-name="numRecentReplies" value="{categories.numRecentReplies}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<input type="hidden" data-name="order" data-value="{categories.order}"></input>
|
||||
</form>
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
<i class='fa fa-pencil'></i>
|
||||
<span id='postcount'>{users.postcount}</span>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#" class="btn btn-default admin-btn">Make Admin</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#" class="btn btn-default ban-btn">Ban</a>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<div class="row home" itemscope itemtype="http://www.schema.org/ItemList">
|
||||
<!-- BEGIN categories -->
|
||||
<div class="col-md-3 col-xs-6">
|
||||
<div class="{categories.class}">
|
||||
<a href="category/{categories.slug}" itemprop="url">
|
||||
<meta itemprop="name" content="{categories.name}">
|
||||
<h4><span class="badge {categories.badgeclass}">{categories.topic_count} </span> {categories.name}</h4>
|
||||
|
||||
@@ -97,6 +97,9 @@
|
||||
<div class="btn-group post-tools">
|
||||
<button class="btn btn-sm btn-default edit" type="button" title="[[topic:edit]]"><i class="fa fa-pencil"></i></button>
|
||||
<button class="btn btn-sm btn-default delete" type="button" title="[[topic:delete]]"><i class="fa fa-trash-o"></i></button>
|
||||
<!-- IF !@first -->
|
||||
<button class="btn btn-sm btn-default fork-post" type="button" title="[[topic:fork]]"><i class="fa fa-code-fork"></i></button>
|
||||
<!-- ENDIF !@first -->
|
||||
</div>
|
||||
<!-- ENDIF posts.display_moderator_tools -->
|
||||
</div>
|
||||
|
||||
@@ -138,9 +138,7 @@ var db = require('./database.js'),
|
||||
db.getSortedSetRevRange('categories:' + cid + ':tid', start, stop, callback);
|
||||
};
|
||||
|
||||
Categories.getActiveUsers = function(cid, callback) {
|
||||
db.getSetMembers('cid:' + cid + ':active_users', callback);
|
||||
};
|
||||
|
||||
|
||||
Categories.getAllCategories = function(current_user, callback) {
|
||||
db.getListRange('categories:cid', 0, -1, function(err, cids) {
|
||||
@@ -217,6 +215,10 @@ var db = require('./database.js'),
|
||||
};
|
||||
|
||||
Categories.getRecentReplies = function(cid, count, callback) {
|
||||
if(count === 0) {
|
||||
return callback(null, []);
|
||||
}
|
||||
|
||||
db.getSortedSetRevRange('categories:recent_posts:cid:' + cid, 0, count - 1, function(err, pids) {
|
||||
|
||||
if (err) {
|
||||
@@ -264,25 +266,7 @@ var db = require('./database.js'),
|
||||
});
|
||||
};
|
||||
|
||||
Categories.moveActiveUsers = function(tid, oldCid, cid, callback) {
|
||||
function updateUser(uid) {
|
||||
Categories.addActiveUser(cid, uid);
|
||||
Categories.isUserActiveIn(oldCid, uid, function(err, active) {
|
||||
|
||||
if (!err && !active) {
|
||||
Categories.removeActiveUser(oldCid, uid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
topics.getUids(tid, function(err, uids) {
|
||||
if (!err && uids) {
|
||||
for (var i = 0; i < uids.length; ++i) {
|
||||
updateUser(uids[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Categories.getCategoryData = function(cid, callback) {
|
||||
db.exists('category:' + cid, function(err, exists) {
|
||||
@@ -391,14 +375,38 @@ var db = require('./database.js'),
|
||||
});
|
||||
};
|
||||
|
||||
Categories.addActiveUser = function(cid, uid) {
|
||||
Categories.addActiveUser = function(cid, uid, timestamp) {
|
||||
if(parseInt(uid, 10)) {
|
||||
db.setAdd('cid:' + cid + ':active_users', uid);
|
||||
db.sortedSetAdd('cid:' + cid + ':active_users', timestamp, uid);
|
||||
}
|
||||
};
|
||||
|
||||
Categories.removeActiveUser = function(cid, uid) {
|
||||
db.setRemove('cid:' + cid + ':active_users', uid);
|
||||
db.sortedSetRemove('cid:' + cid + ':active_users', uid);
|
||||
};
|
||||
|
||||
Categories.getActiveUsers = function(cid, callback) {
|
||||
db.getSortedSetRevRange('cid:' + cid + ':active_users', 0, 15, callback);
|
||||
};
|
||||
|
||||
Categories.moveActiveUsers = function(tid, oldCid, cid, callback) {
|
||||
function updateUser(uid) {
|
||||
Categories.addActiveUser(cid, uid);
|
||||
Categories.isUserActiveIn(oldCid, uid, function(err, active) {
|
||||
|
||||
if (!err && !active) {
|
||||
Categories.removeActiveUser(oldCid, uid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
topics.getUids(tid, function(err, uids) {
|
||||
if (!err && uids) {
|
||||
for (var i = 0; i < uids.length; ++i) {
|
||||
updateUser(uids[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Categories.onNewPostMade = function(uid, tid, pid, timestamp) {
|
||||
@@ -412,13 +420,7 @@ var db = require('./database.js'),
|
||||
db.sortedSetAdd('categories:' + cid + ':tid', timestamp, tid);
|
||||
}
|
||||
|
||||
db.setCount('cid:' + cid + ':active_users', function(err, amount) {
|
||||
if (amount > 15) {
|
||||
db.setRemoveRandom('cid:' + cid + ':active_users');
|
||||
}
|
||||
|
||||
Categories.addActiveUser(cid, uid);
|
||||
});
|
||||
Categories.addActiveUser(cid, uid, timestamp);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -738,6 +738,21 @@
|
||||
});
|
||||
}
|
||||
|
||||
module.listRemoveAll = function(key, value, callback) {
|
||||
db.collection('objects').update({_key: key }, { $pull: { array: value } }, function(err, result) {
|
||||
if(err) {
|
||||
if(callback) {
|
||||
return callback(err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(callback) {
|
||||
callback(null, result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.getListRange = function(key, start, stop, callback) {
|
||||
|
||||
if(stop === -1) {
|
||||
|
||||
@@ -402,6 +402,10 @@
|
||||
redisClient.rpop(key, callback);
|
||||
}
|
||||
|
||||
module.listRemoveAll = function(key, value, callback) {
|
||||
redisClient.lrem(key, 0, value, callback);
|
||||
}
|
||||
|
||||
module.getListRange = function(key, start, stop, callback) {
|
||||
redisClient.lrange(key, start, stop, callback);
|
||||
}
|
||||
|
||||
@@ -134,6 +134,11 @@ var async = require('async'),
|
||||
return next(new Error('unknown database : ' + config.database));
|
||||
}
|
||||
|
||||
var allQuestions = install.redisQuestions.concat(install.mongoQuestions);
|
||||
for(var x=0;x<allQuestions.length;x++) {
|
||||
delete config[allQuestions[x].name];
|
||||
}
|
||||
|
||||
config.bcrypt_rounds = 12;
|
||||
config.upload_path = '/public/uploads';
|
||||
config.use_port = config.use_port.slice(0, 1) === 'y';
|
||||
@@ -258,6 +263,21 @@ var async = require('async'),
|
||||
}, function (err) {
|
||||
meta.configs.init(next);
|
||||
});
|
||||
|
||||
if (install.values) {
|
||||
if (install.values['social:twitter:key'] && install.values['social:twitter:secret']) {
|
||||
meta.configs.setOnEmpty('social:twitter:key', install.values['social:twitter:key']);
|
||||
meta.configs.setOnEmpty('social:twitter:secret', install.values['social:twitter:secret']);
|
||||
}
|
||||
if (install.values['social:google:id'] && install.values['social:google:secret']) {
|
||||
meta.configs.setOnEmpty('social:google:id', install.values['social:google:id']);
|
||||
meta.configs.setOnEmpty('social:google:secret', install.values['social:google:secret']);
|
||||
}
|
||||
if (install.values['social:facebook:key'] && install.values['social:facebook:secret']) {
|
||||
meta.configs.setOnEmpty('social:facebook:app_id', install.values['social:facebook:app_id']);
|
||||
meta.configs.setOnEmpty('social:facebook:secret', install.values['social:facebook:secret']);
|
||||
}
|
||||
}
|
||||
},
|
||||
function (next) {
|
||||
// Check if an administrator needs to be created
|
||||
|
||||
@@ -137,7 +137,7 @@ var winston = require('winston'),
|
||||
events.logPostDelete(uid, pid);
|
||||
|
||||
posts.getPostFields(pid, ['tid', 'uid'], function(err, postData) {
|
||||
db.incrObjectFieldBy('topic:' + postData.tid, 'postcount', -1);
|
||||
topics.decreasePostCount(postData.tid);
|
||||
|
||||
user.decrementUserFieldBy(postData.uid, 'postcount', 1, function(err, postcount) {
|
||||
db.sortedSetAdd('users:postcount', postcount, postData.uid);
|
||||
@@ -193,7 +193,7 @@ var winston = require('winston'),
|
||||
events.logPostRestore(uid, pid);
|
||||
|
||||
posts.getPostFields(pid, ['tid', 'uid', 'content'], function(err, postData) {
|
||||
db.incrObjectFieldBy('topic:' + postData.tid, 'postcount', 1);
|
||||
topics.increasePostCount(postData.tid);
|
||||
|
||||
user.incrementUserFieldBy(postData.uid, 'postcount', 1);
|
||||
|
||||
|
||||
95
src/posts.js
95
src/posts.js
@@ -28,63 +28,70 @@ var db = require('./database'),
|
||||
return callback(new Error('invalid-user'), null);
|
||||
}
|
||||
|
||||
topics.isLocked(tid, function(err, locked) {
|
||||
if(err) {
|
||||
return callback(err, null);
|
||||
} else if(locked) {
|
||||
return callback(new Error('topic-locked'), null);
|
||||
}
|
||||
|
||||
db.incrObjectField('global', 'nextPid', function(err, pid) {
|
||||
if(err) {
|
||||
return callback(err, null);
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
topics.isLocked(tid, next);
|
||||
},
|
||||
function(locked, next) {
|
||||
if(locked) {
|
||||
return next(new Error('topic-locked'));
|
||||
}
|
||||
|
||||
db.incrObjectField('global', 'nextPid', next);
|
||||
},
|
||||
function(pid, next) {
|
||||
plugins.fireHook('filter:post.save', content, function(err, newContent) {
|
||||
next(err, pid, newContent)
|
||||
});
|
||||
},
|
||||
function(pid, newContent, next) {
|
||||
var timestamp = Date.now(),
|
||||
postData = {
|
||||
'pid': pid,
|
||||
'uid': uid,
|
||||
'tid': tid,
|
||||
'content': newContent,
|
||||
'timestamp': timestamp,
|
||||
'reputation': 0,
|
||||
'editor': '',
|
||||
'edited': 0,
|
||||
'deleted': 0
|
||||
};
|
||||
|
||||
db.setObject('post:' + pid, postData, function(err) {
|
||||
if(err) {
|
||||
return callback(err, null);
|
||||
return next(err);
|
||||
}
|
||||
|
||||
var timestamp = Date.now(),
|
||||
postData = {
|
||||
'pid': pid,
|
||||
'uid': uid,
|
||||
'tid': tid,
|
||||
'content': newContent,
|
||||
'timestamp': timestamp,
|
||||
'reputation': 0,
|
||||
'editor': '',
|
||||
'edited': 0,
|
||||
'deleted': 0
|
||||
};
|
||||
|
||||
db.setObject('post:' + pid, postData);
|
||||
db.incrObjectField('global', 'postCount');
|
||||
|
||||
topics.onNewPostMade(tid, pid, timestamp);
|
||||
categories.onNewPostMade(uid, tid, pid, timestamp);
|
||||
user.onNewPostMade(uid, tid, pid, timestamp);
|
||||
|
||||
plugins.fireHook('filter:post.get', postData, function(err, newPostData) {
|
||||
if(err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
postTools.parse(newPostData.content, function(err, content) {
|
||||
if(err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
newPostData.content = content;
|
||||
|
||||
plugins.fireHook('action:post.save', newPostData);
|
||||
|
||||
db.searchIndex('post', content, pid);
|
||||
|
||||
callback(null, newPostData);
|
||||
});
|
||||
});
|
||||
next(null, postData);
|
||||
});
|
||||
});
|
||||
},
|
||||
function(postData, next) {
|
||||
plugins.fireHook('filter:post.get', postData, next);
|
||||
},
|
||||
function(postData, next) {
|
||||
postTools.parse(postData.content, function(err, content) {
|
||||
if(err) {
|
||||
return next(err, null);
|
||||
}
|
||||
|
||||
postData.content = content;
|
||||
|
||||
plugins.fireHook('action:post.save', postData);
|
||||
|
||||
db.searchIndex('post', content, postData.pid);
|
||||
|
||||
next(null, postData);
|
||||
});
|
||||
}
|
||||
], function(err, postData) {
|
||||
callback(err, postData);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -55,9 +55,9 @@ var path = require('path'),
|
||||
});
|
||||
|
||||
function iterator(category, callback) {
|
||||
categories.getRecentReplies(category.cid, 2, function (err, posts) {
|
||||
categories.getRecentReplies(category.cid, parseInt(category.numRecentReplies, 10), function (err, posts) {
|
||||
category.posts = posts;
|
||||
category.post_count = posts.length > 2 ? 2 : posts.length;
|
||||
category.post_count = posts.length > 2 ? 2 : posts.length; // this was a hack to make metro work back in the day, post_count should just = length
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
118
src/topics.js
118
src/topics.js
@@ -23,6 +23,50 @@ var async = require('async'),
|
||||
|
||||
(function(Topics) {
|
||||
|
||||
Topics.create = function(uid, title, cid, callback) {
|
||||
db.incrObjectField('global', 'nextTid', function(err, tid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
db.setAdd('topics:tid', tid);
|
||||
|
||||
var slug = tid + '/' + utils.slugify(title),
|
||||
timestamp = Date.now();
|
||||
|
||||
db.setObject('topic:' + tid, {
|
||||
'tid': tid,
|
||||
'uid': uid,
|
||||
'cid': cid,
|
||||
'title': title,
|
||||
'slug': slug,
|
||||
'timestamp': timestamp,
|
||||
'lastposttime': 0,
|
||||
'postcount': 0,
|
||||
'viewcount': 0,
|
||||
'locked': 0,
|
||||
'deleted': 0,
|
||||
'pinned': 0
|
||||
}, function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
db.searchIndex('topic', title, tid);
|
||||
|
||||
user.addTopicIdToUser(uid, tid);
|
||||
|
||||
// in future it may be possible to add topics to several categories, so leaving the door open here.
|
||||
db.sortedSetAdd('categories:' + cid + ':tid', timestamp, tid);
|
||||
db.incrObjectField('category:' + cid, 'topic_count');
|
||||
db.incrObjectField('global', 'topicCount');
|
||||
|
||||
feed.updateCategory(cid);
|
||||
|
||||
callback(null, tid);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Topics.post = function(uid, title, content, cid, callback) {
|
||||
|
||||
categoryTools.privileges(cid, uid, function(err, privileges) {
|
||||
@@ -61,41 +105,11 @@ var async = require('async'),
|
||||
return callback(new Error('too-many-posts'), null);
|
||||
}
|
||||
|
||||
db.incrObjectField('global', 'nextTid', function(err, tid) {
|
||||
Topics.create(uid, title, cid, function(err, tid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
db.setAdd('topics:tid', tid);
|
||||
|
||||
var slug = tid + '/' + utils.slugify(title);
|
||||
var timestamp = Date.now();
|
||||
db.setObject('topic:' + tid, {
|
||||
'tid': tid,
|
||||
'uid': uid,
|
||||
'cid': cid,
|
||||
'title': title,
|
||||
'slug': slug,
|
||||
'timestamp': timestamp,
|
||||
'lastposttime': 0,
|
||||
'postcount': 0,
|
||||
'viewcount': 0,
|
||||
'locked': 0,
|
||||
'deleted': 0,
|
||||
'pinned': 0
|
||||
});
|
||||
|
||||
db.searchIndex('topic', title, tid);
|
||||
|
||||
user.addTopicIdToUser(uid, tid);
|
||||
|
||||
// in future it may be possible to add topics to several categories, so leaving the door open here.
|
||||
db.sortedSetAdd('categories:' + cid + ':tid', timestamp, tid);
|
||||
db.incrObjectField('category:' + cid, 'topic_count');
|
||||
db.incrObjectField('global', 'topicCount');
|
||||
|
||||
feed.updateCategory(cid);
|
||||
|
||||
Topics.reply(tid, uid, content, function(err, postData) {
|
||||
if(err) {
|
||||
return callback(err, null);
|
||||
@@ -184,6 +198,40 @@ var async = require('async'),
|
||||
});
|
||||
}
|
||||
|
||||
Topics.createTopicFromPost = function(pid, callback) {
|
||||
posts.getPostData(pid, function(err, postData) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
posts.getCidByPid(pid, function(err, cid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// TODO : title should be given by client
|
||||
var title = postData.content.substr(0, 20);
|
||||
|
||||
Topics.create(postData.uid, title, cid, function(err, tid) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
Topics.removePostFromTopic(postData.tid, postData.pid);
|
||||
Topics.decreasePostCount(postData.tid);
|
||||
|
||||
posts.setPostField(pid, 'tid', tid);
|
||||
|
||||
Topics.onNewPostMade(tid, postData.pid, postData.timestamp);
|
||||
|
||||
Topics.getTopicData(tid, function(err, topicData) {
|
||||
callback(err, topicData);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Topics.getTopicData = function(tid, callback) {
|
||||
db.getObject('topic:' + tid, function(err, data) {
|
||||
if(err) {
|
||||
@@ -916,6 +964,10 @@ var async = require('async'),
|
||||
db.incrObjectField('topic:' + tid, 'postcount', callback);
|
||||
}
|
||||
|
||||
Topics.decreasePostCount = function(tid, callback) {
|
||||
db.decrObjectField('topic:' + tid, 'postcount', callback);
|
||||
}
|
||||
|
||||
Topics.increaseViewCount = function(tid, callback) {
|
||||
db.incrObjectField('topic:' + tid, 'viewcount', callback);
|
||||
}
|
||||
@@ -944,6 +996,10 @@ var async = require('async'),
|
||||
db.listAppend('tid:' + tid + ':posts', pid);
|
||||
}
|
||||
|
||||
Topics.removePostFromTopic = function(tid, pid) {
|
||||
db.listRemoveAll('tid:' + tid + ':posts', pid);
|
||||
}
|
||||
|
||||
Topics.getPids = function(tid, callback) {
|
||||
db.getListRange('tid:' + tid + ':posts', 0, -1, callback);
|
||||
}
|
||||
|
||||
105
src/upgrade.js
105
src/upgrade.js
@@ -14,7 +14,7 @@ var db = require('./database'),
|
||||
|
||||
Upgrade.check = function(callback) {
|
||||
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
|
||||
var latestSchema = new Date(2014, 0, 1).getTime();
|
||||
var latestSchema = new Date(2014, 0, 5).getTime();
|
||||
|
||||
db.get('schemaDate', function(err, value) {
|
||||
if (parseInt(value, 10) >= latestSchema) {
|
||||
@@ -65,8 +65,16 @@ Upgrade.upgrade = function(callback) {
|
||||
|
||||
async.each(uids, function(uid, next) {
|
||||
User.getUserField(uid, 'username', function(err, username) {
|
||||
newUserSlug = Utils.slugify(username);
|
||||
User.setUserField(uid, 'userslug', newUserSlug, next);
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
if(username) {
|
||||
newUserSlug = Utils.slugify(username);
|
||||
User.setUserField(uid, 'userslug', newUserSlug, next);
|
||||
} else {
|
||||
winston.warn('uid '+ uid + ' doesn\'t have a valid username (' + username + '), skipping');
|
||||
next(null);
|
||||
}
|
||||
});
|
||||
}, function(err) {
|
||||
next(err);
|
||||
@@ -108,6 +116,97 @@ Upgrade.upgrade = function(callback) {
|
||||
winston.info('[2013/12/31] maximumTitleLength skipped');
|
||||
next();
|
||||
}
|
||||
},
|
||||
function(next) {
|
||||
// Custom classes for each category, adding link field for each category
|
||||
thisSchemaDate = new Date(2014, 0, 3).getTime();
|
||||
if (schemaDate < thisSchemaDate) {
|
||||
updatesMade = true;
|
||||
|
||||
db.getListRange('categories:cid', 0, -1, function(err, cids) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
for (var cid in cids) {
|
||||
db.setObjectField('category:' + cids[cid], 'link', '');
|
||||
db.setObjectField('category:' + cids[cid], 'class', 'col-md-3 col-xs-6');
|
||||
}
|
||||
|
||||
winston.info('[2014/1/3] Added categories.class, categories.link fields');
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
winston.info('[2014/1/3] categories.class, categories.link fields skipped');
|
||||
next();
|
||||
}
|
||||
},
|
||||
function(next) {
|
||||
// Custom classes for each category, adding link field for each category
|
||||
thisSchemaDate = new Date(2014, 0, 4).getTime();
|
||||
if (schemaDate < thisSchemaDate) {
|
||||
updatesMade = true;
|
||||
|
||||
db.getListRange('categories:cid', 0, -1, function(err, cids) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
for (var cid in cids) {
|
||||
db.setObjectField('category:' + cids[cid], 'numRecentReplies', '2');
|
||||
}
|
||||
|
||||
winston.info('[2014/1/4] Added categories.numRecentReplies fields');
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
winston.info('[2014/1/4] categories.numRecentReplies fields skipped');
|
||||
next();
|
||||
}
|
||||
},
|
||||
function(next) {
|
||||
thisSchemaDate = new Date(2014, 0, 5).getTime();
|
||||
if (schemaDate < thisSchemaDate) {
|
||||
updatesMade = true;
|
||||
|
||||
db.getListRange('categories:cid', 0, -1, function(err, cids) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
var timestamp = Date.now();
|
||||
|
||||
function upgradeCategory(cid, next) {
|
||||
db.getSetMembers('cid:' + cid + ':active_users', function(err, uids) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
db.delete('cid:' + cid + ':active_users', function(err) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
for(var i=0; i<uids.length; ++i) {
|
||||
db.sortedSetAdd('cid:' + cid + ':active_users', timestamp, uids[i]);
|
||||
}
|
||||
next();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async.each(cids, upgradeCategory, function(err) {
|
||||
if(err) {
|
||||
return next(err)
|
||||
}
|
||||
winston.info('[2014/1/5] Upgraded categories active users');
|
||||
next();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
winston.info('[2014/1/5] categories active users skipped');
|
||||
next();
|
||||
}
|
||||
}
|
||||
// Add new schema updates here
|
||||
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 17!!!
|
||||
|
||||
@@ -622,6 +622,12 @@ websockets.init = function(io) {
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('api:topic.createTopicFromPost', function(data, callback) {
|
||||
topics.createTopicFromPost(data.pid, function(err, data) {
|
||||
callback(err?{message:err.message}:null, data);
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('api:topic.move', function(data) {
|
||||
threadTools.move(data.tid, data.cid, socket);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user