Post queue (#5878)
* #5876 * add user to post queue table * add time of post into queue add posting restrictions to queue * fix shouldQueueLogic for guests * add test for post-queue routev1.18.x
parent
1864a50826
commit
f161bbf956
@ -0,0 +1,8 @@
|
||||
{
|
||||
"post-queue": "Post Queue",
|
||||
"description": "There are no posts in the post queue. <br> To enable this feature, go to <a href=\"%1\">Settings → Post → Posting Restrictions</a> and enable <strong>Post Queue</strong>.",
|
||||
"user": "User",
|
||||
"title": "Title",
|
||||
"content": "Content",
|
||||
"posted": "Posted"
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"success": "Success",
|
||||
"topic-post": "You have successfully posted.",
|
||||
"post-queued": "Your post is queued for approval.",
|
||||
"authentication-successful": "Authentication Successful",
|
||||
"settings-saved": "Settings saved!"
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
define('admin/manage/post-queue', function () {
|
||||
var PostQueue = {};
|
||||
|
||||
PostQueue.init = function () {
|
||||
$('.posts-list').on('click', '[data-action]', function () {
|
||||
var parent = $(this).parents('[data-id]');
|
||||
var action = $(this).attr('data-action');
|
||||
var id = parent.attr('data-id');
|
||||
var method = action === 'accept' ? 'posts.accept' : 'posts.reject';
|
||||
|
||||
socket.emit(method, { id: id }, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
parent.remove();
|
||||
});
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
return PostQueue;
|
||||
});
|
@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
|
||||
var db = require('../../database');
|
||||
var user = require('../../user');
|
||||
var pagination = require('../../pagination');
|
||||
var utils = require('../../utils');
|
||||
|
||||
var postQueueController = module.exports;
|
||||
|
||||
postQueueController.get = function (req, res, next) {
|
||||
var page = parseInt(req.query.page, 10) || 1;
|
||||
var postsPerPage = 20;
|
||||
var pageCount = 0;
|
||||
|
||||
var start = (page - 1) * postsPerPage;
|
||||
var stop = start + postsPerPage - 1;
|
||||
|
||||
var postData;
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
count: function (next) {
|
||||
db.sortedSetCard('post:queue', next);
|
||||
},
|
||||
ids: function (next) {
|
||||
db.getSortedSetRange('post:queue', start, stop, next);
|
||||
},
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
pageCount = Math.ceil(results.count / postsPerPage);
|
||||
|
||||
var keys = results.ids.map(function (id) {
|
||||
return 'post:queue:' + id;
|
||||
});
|
||||
|
||||
db.getObjects(keys, next);
|
||||
},
|
||||
function (data, next) {
|
||||
postData = data;
|
||||
data.forEach(function (data) {
|
||||
data.data = JSON.parse(data.data);
|
||||
data.data.timestampISO = utils.toISOString(data.data.timestamp);
|
||||
return data;
|
||||
});
|
||||
var uids = data.map(function (data) {
|
||||
return data && data.uid;
|
||||
});
|
||||
user.getUsersFields(uids, ['username', 'userslug', 'picture'], next);
|
||||
},
|
||||
function (userData) {
|
||||
postData.forEach(function (postData, index) {
|
||||
postData.user = userData[index];
|
||||
});
|
||||
|
||||
res.render('admin/manage/post-queue', {
|
||||
title: '[[pages:post-queue]]',
|
||||
posts: postData,
|
||||
pagination: pagination.create(page, pageCount),
|
||||
});
|
||||
},
|
||||
], next);
|
||||
};
|
@ -0,0 +1,153 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
|
||||
var db = require('../database');
|
||||
var user = require('../user');
|
||||
var meta = require('../meta');
|
||||
var topics = require('../topics');
|
||||
var privileges = require('../privileges');
|
||||
var socketHelpers = require('../socket.io/helpers');
|
||||
|
||||
module.exports = function (Posts) {
|
||||
Posts.shouldQueue = function (uid, data, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.getUserFields(uid, ['reputation', 'postcount'], next);
|
||||
},
|
||||
function (userData, next) {
|
||||
var shouldQueue = parseInt(meta.config.postQueue, 10) === 1 && (!parseInt(uid, 10) || (parseInt(userData.reputation, 10) <= 0 && parseInt(userData.postcount, 10) <= 0));
|
||||
next(null, shouldQueue);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
Posts.addToQueue = function (data, callback) {
|
||||
var type = data.title ? 'topic' : 'reply';
|
||||
var id = type + '-' + Date.now();
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
canPost(type, data, next);
|
||||
},
|
||||
function (next) {
|
||||
db.sortedSetAdd('post:queue', Date.now(), id, next);
|
||||
},
|
||||
function (next) {
|
||||
db.setObject('post:queue:' + id, {
|
||||
id: id,
|
||||
uid: data.uid,
|
||||
type: type,
|
||||
data: JSON.stringify(data),
|
||||
}, next);
|
||||
},
|
||||
function (next) {
|
||||
user.setUserField(data.uid, 'lastposttime', Date.now(), next);
|
||||
},
|
||||
function (next) {
|
||||
next(null, {
|
||||
queued: true,
|
||||
message: '[[success:post-queued]]',
|
||||
});
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
function canPost(type, data, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
if (type === 'topic') {
|
||||
next(null, data.cid);
|
||||
} else if (type === 'reply') {
|
||||
topics.getTopicField(data.tid, 'cid', next);
|
||||
}
|
||||
},
|
||||
function (cid, next) {
|
||||
async.parallel({
|
||||
canPost: function (next) {
|
||||
if (type === 'topic') {
|
||||
privileges.categories.can('topics:create', data.cid, data.uid, next);
|
||||
} else if (type === 'reply') {
|
||||
privileges.categories.can('topics:reply', cid, data.uid, next);
|
||||
}
|
||||
},
|
||||
isReadyToPost: function (next) {
|
||||
user.isReadyToPost(data.uid, cid, next);
|
||||
},
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
if (!results.canPost) {
|
||||
return next(new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
|
||||
Posts.removeFromQueue = function (id, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.sortedSetRemove('post:queue', id, next);
|
||||
},
|
||||
function (next) {
|
||||
db.delete('post:queue:' + id, next);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
Posts.submitFromQueue = function (id, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getObject('post:queue:' + id, next);
|
||||
},
|
||||
function (data, next) {
|
||||
if (!data) {
|
||||
return callback();
|
||||
}
|
||||
try {
|
||||
data.data = JSON.parse(data.data);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (data.type === 'topic') {
|
||||
createTopic(data.data, next);
|
||||
} else if (data.type === 'reply') {
|
||||
createReply(data.data, next);
|
||||
}
|
||||
},
|
||||
function (next) {
|
||||
Posts.removeFromQueue(id, next);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
function createTopic(data, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.post(data, next);
|
||||
},
|
||||
function (result, next) {
|
||||
socketHelpers.notifyNew(data.uid, 'newTopic', { posts: [result.postData], topic: result.topicData });
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
|
||||
function createReply(data, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.reply(data, next);
|
||||
},
|
||||
function (postData, next) {
|
||||
var result = {
|
||||
posts: [postData],
|
||||
'reputation:disabled': parseInt(meta.config['reputation:disabled'], 10) === 1,
|
||||
'downvote:disabled': parseInt(meta.config['downvote:disabled'], 10) === 1,
|
||||
};
|
||||
socketHelpers.notifyNew(data.uid, 'newPost', result);
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
};
|
@ -0,0 +1,59 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="post-queue panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
[[admin/manage/post-queue:post-queue]]
|
||||
</div>
|
||||
|
||||
<!-- IF !posts.length -->
|
||||
<p class="panel-body">
|
||||
[[admin/manage/post-queue:description, {config.relative_path}/admin/settings/post#posting-restrictions]]
|
||||
</p>
|
||||
<!-- ENDIF !posts.length -->
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped posts-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>[[admin/manage/post-queue:user]]</th>
|
||||
<th>[[admin/manage/post-queue:title]]</th>
|
||||
<th>[[admin/manage/post-queue:content]]</th>
|
||||
<th>[[admin/manage/post-queue:posted]]</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- BEGIN posts -->
|
||||
<tr data-id="{posts.id}">
|
||||
<td class="col-md-1">
|
||||
<!-- IF posts.user.userslug -->
|
||||
<a href="/uid/{posts.user.uid}">{posts.user.username}</a>
|
||||
<!-- ELSE -->
|
||||
{posts.user.username}
|
||||
<!-- ENDIF posts.user.userslug -->
|
||||
</td>
|
||||
<td class="col-md-2">
|
||||
{posts.data.title}
|
||||
</td>
|
||||
<td class="col-md-7">
|
||||
{posts.data.content}
|
||||
</td>
|
||||
<td class="col-md-1">
|
||||
<span class="timeago" title={posts.data.timestampISO}></span>
|
||||
</td>
|
||||
<td class="col-md-1">
|
||||
<div class="btn-group pull-right">
|
||||
<button class="btn btn-success btn-xs" data-action="accept"><i class="fa fa-check"></i></button>
|
||||
<button class="btn btn-danger btn-xs" data-action="delete"><i class="fa fa-times"></i></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- END posts -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- IMPORT partials/paginator.tpl -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue