v1.18.x
barisusakli 10 years ago
parent 8ef46ebc7d
commit 47e2dd9478

@ -32,7 +32,6 @@
"bookmark_instructions" : "Click here to return to the last unread post in this thread.",
"flag_title": "Flag this post for moderation",
"flag_confirm": "Are you sure you want to flag this post?",
"flag_success": "This post has been flagged for moderation.",
"deleted_message": "This topic has been deleted. Only users with topic management privileges can see it.",
@ -117,5 +116,10 @@
"most_votes": "Most votes",
"most_posts": "Most posts",
"stale_topic_warning": "The topic you are replying to is quite old. Would you like to create a new topic instead, and reference this one in your reply?"
"stale_topic_warning": "The topic you are replying to is quite old. Would you like to create a new topic instead, and reference this one in your reply?",
"spam": "Spam",
"offensive": "Offensive",
"custom-flag-reason": "Enter a flagging reason"
}

@ -0,0 +1,64 @@
'use strict';
/* globals define, app, socket, templates, translator */
define('forum/topic/flag', [], function() {
var Flag = {},
flagModal,
flagCommit;
Flag.showFlagModal = function(pid) {
parseModal(function(html) {
flagModal = $(html);
flagModal.on('hidden.bs.modal', function() {
flagModal.remove();
});
flagCommit = flagModal.find('#flag-post-commit');
flagModal.on('click', '.flag-reason', function() {
flagPost(pid, $(this).text());
});
flagCommit.on('click', function() {
flagPost(pid, flagModal.find('#flag-reason-custom').val());
});
flagModal.modal('show');
flagModal.find('#flag-reason-custom').on('keyup blur change', checkFlagButtonEnable);
});
};
function parseModal(callback) {
templates.parse('partials/modals/flag_post_modal', {}, function(html) {
translator.translate(html, callback);
});
}
function flagPost(pid, reason) {
if (!pid || !reason) {
return;
}
socket.emit('posts.flag', {pid: pid, reason: reason}, function(err) {
if (err) {
return app.alertError(err.message);
}
flagModal.modal('hide');
app.alertSuccess('[[topic:flag_success]]');
});
}
function checkFlagButtonEnable() {
if (flagModal.find('#flag-reason-custom').val()) {
flagCommit.removeAttr('disabled');
} else {
flagCommit.attr('disabled', true);
}
}
return Flag;
});

@ -1,6 +1,6 @@
'use strict';
/* globals define, app, ajaxify, bootbox, socket, templates, utils */
/* globals define, app, ajaxify, bootbox, socket, templates, utils, config */
define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator'], function(share, navigator, components, translator) {
@ -110,33 +110,36 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
});
postContainer.on('click', '[component="post/flag"]', function() {
flagPost(getData($(this), 'data-pid'));
var pid = getData($(this), 'data-pid');
require(['forum/topic/flag'], function(flag) {
flag.showFlagModal(pid);
});
});
postContainer.on('click', '[component="post/edit"]', function(e) {
postContainer.on('click', '[component="post/edit"]', function() {
var btn = $(this);
$(window).trigger('action:composer.post.edit', {
pid: getData(btn, 'data-pid')
});
});
postContainer.on('click', '[component="post/delete"]', function(e) {
postContainer.on('click', '[component="post/delete"]', function() {
togglePostDelete($(this), tid);
});
postContainer.on('click', '[component="post/restore"]', function(e) {
postContainer.on('click', '[component="post/restore"]', function() {
togglePostDelete($(this), tid);
});
postContainer.on('click', '[component="post/purge"]', function(e) {
postContainer.on('click', '[component="post/purge"]', function() {
purgePost($(this), tid);
});
postContainer.on('click', '[component="post/move"]', function(e) {
postContainer.on('click', '[component="post/move"]', function() {
openMovePostModal($(this));
});
postContainer.on('click', '[component="post/chat"]', function(e) {
postContainer.on('click', '[component="post/chat"]', function() {
openChat($(this));
});
}
@ -369,22 +372,7 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
});
}
function flagPost(pid) {
translator.translate('[[topic:flag_confirm]]', function(message) {
bootbox.confirm(message, function(confirm) {
if (!confirm) {
return;
}
socket.emit('posts.flag', pid, function(err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[topic:flag_success]]');
});
});
});
}
function openChat(button) {
var post = button.parents('[data-pid]');

@ -9,7 +9,10 @@ var async = require('async'),
module.exports = function(Posts) {
Posts.flag = function(post, uid, callback) {
Posts.flag = function(post, uid, reason, callback) {
if (!parseInt(uid, 10) || !reason) {
return callback();
}
async.parallel({
hasFlagged: async.apply(hasFlagged, post.pid, uid),
exists: async.apply(Posts.exists, post.pid)
@ -36,6 +39,9 @@ module.exports = function(Posts) {
function(next) {
db.sortedSetAdd('pid:' + post.pid + ':flag:uids', now, uid, next);
},
function(next) {
db.sortedSetAdd('pid:' + post.pid + ':flag:uid:reason', 0, uid + ':' + reason, next);
},
function(next) {
if (parseInt(post.uid, 10)) {
db.sortedSetAdd('uid:' + post.uid + ':flag:pids', now, post.pid, next);
@ -50,7 +56,7 @@ module.exports = function(Posts) {
next();
}
}
], function(err, results) {
], function(err) {
callback(err);
});
});
@ -80,8 +86,11 @@ module.exports = function(Posts) {
},
function(next) {
db.delete('pid:' + pid + ':flag:uids', next);
},
function(next) {
db.delete('pid:' + pid + ':flag:uid:reason', next);
}
], function(err, results) {
], function(err) {
callback(err);
});
};
@ -96,15 +105,56 @@ module.exports = function(Posts) {
};
Posts.getFlags = function(set, uid, start, stop, callback) {
db.getSortedSetRevRange(set, start, stop, function(err, pids) {
if (err) {
return callback(err);
async.waterfall([
function (next) {
db.getSortedSetRevRange(set, start, stop, next);
},
function (pids, next) {
getFlaggedPostsWithReasons(pids, uid, next);
}
Posts.getPostSummaryByPids(pids, uid, {stripTags: false, extraFields: ['flags']}, callback);
});
], callback);
};
function getFlaggedPostsWithReasons(pids, uid, callback) {
async.waterfall([
function (next) {
async.parallel({
uidsReasons: function(next) {
async.map(pids, function(pid, next) {
db.getSortedSetRange('pid:' + pid + ':flag:uid:reason', 0, -1, next);
}, next);
},
posts: function(next) {
Posts.getPostSummaryByPids(pids, uid, {stripTags: false, extraFields: ['flags']}, next);
}
}, next);
},
function (results, next) {
async.map(results.uidsReasons, function(uidReasons, next) {
async.map(uidReasons, function(uidReason, next) {
var uid = uidReason.split(':')[0];
var reason = uidReason.substr(uidReason.indexOf(':') + 1);
user.getUserFields(uid, ['username', 'userslug', 'picture'], function(err, userData) {
next(err, {user: userData, reason: reason});
});
}, next);
}, function(err, reasons) {
if (err) {
return callback(err);
}
results.posts.forEach(function(post, index) {
if (post) {
post.flagReasons = reasons[index];
}
});
next(null, results.posts);
});
}
], callback);
}
Posts.getUserFlags = function(byUsername, sortBy, callerUID, start, stop, callback) {
async.waterfall([
function(next) {
@ -117,7 +167,7 @@ module.exports = function(Posts) {
db.getSortedSetRevRange('uid:' + uid + ':flag:pids', 0, -1, next);
},
function(pids, next) {
Posts.getPostSummaryByPids(pids, callerUID, {stripTags: false, extraFields: ['flags']}, next);
getFlaggedPostsWithReasons(pids, callerUID, next);
},
function(posts, next) {
if (sortBy === 'count') {
@ -125,6 +175,7 @@ module.exports = function(Posts) {
return b.flags - a.flags;
});
}
next(null, posts.slice(start, stop));
}
], callback);

@ -13,17 +13,21 @@ var meta = require('../../meta');
module.exports = function(SocketPosts) {
SocketPosts.flag = function(socket, pid, callback) {
SocketPosts.flag = function(socket, data, callback) {
if (!socket.uid) {
return callback(new Error('[[error:not-logged-in]]'));
}
if (!data || !data.pid || !data.reason) {
return callback(new Error('[[error:invalid-data]]'));
}
var flaggingUser = {},
post;
async.waterfall([
function (next) {
posts.getPostFields(pid, ['pid', 'tid', 'uid', 'content', 'deleted'], next);
posts.getPostFields(data.pid, ['pid', 'tid', 'uid', 'content', 'deleted'], next);
},
function (postData, next) {
if (parseInt(postData.deleted, 10) === 1) {
@ -55,7 +59,7 @@ module.exports = function(SocketPosts) {
flaggingUser = user.userData;
flaggingUser.uid = socket.uid;
posts.flag(post, socket.uid, next);
posts.flag(post, socket.uid, data.reason, next);
},
function (next) {
async.parallel({
@ -74,8 +78,8 @@ module.exports = function(SocketPosts) {
notifications.create({
bodyShort: '[[notifications:user_flagged_post_in, ' + flaggingUser.username + ', ' + post.topic.title + ']]',
bodyLong: post.content,
pid: pid,
nid: 'post_flag:' + pid + ':uid:' + socket.uid,
pid: data.pid,
nid: 'post_flag:' + data.pid + ':uid:' + socket.uid,
from: socket.uid
}, function(err, notification) {
if (err || !notification) {

@ -58,6 +58,11 @@
</div>
<span class="badge badge-warning"><i class="fa fa-flag"></i> {posts.flags}</span>
<br/>
<!-- BEGIN posts.flagReasons -->
<a target="_blank" href="{config.relative_path}/user/{../user.userslug}"><img class="user-img" src="{../user.picture}">{../user.username}</a>: "{../reason}" <br/>
<!-- END posts.flagReasons -->
<br/>
<button class="btn btn-warning dismiss">Dismiss</button>
<button class="btn btn-danger delete">Delete</button>
<br/><br/>

Loading…
Cancel
Save