mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-07-07 01:09:44 +02:00
feat: closes #12902, allow adding users as post editors
This commit is contained in:
@@ -81,6 +81,7 @@ module.exports = function (Posts) {
|
||||
deleteDiffs(pids),
|
||||
deleteFromUploads(pids),
|
||||
db.sortedSetsRemove(['posts:pid', 'posts:votes', 'posts:flagged'], pids),
|
||||
db.deleteAll(pids.map(pid => `pid:${pid}:editors`)),
|
||||
]);
|
||||
|
||||
await resolveFlags(postData, uid);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
const _ = require('lodash');
|
||||
|
||||
const db = require('../database');
|
||||
const meta = require('../meta');
|
||||
const posts = require('../posts');
|
||||
const topics = require('../topics');
|
||||
@@ -118,7 +119,8 @@ privsPosts.canEdit = async function (pid, uid) {
|
||||
const results = await utils.promiseParallel({
|
||||
isAdmin: user.isAdministrator(uid),
|
||||
isMod: posts.isModerator([pid], uid),
|
||||
owner: posts.isOwner(pid, uid),
|
||||
isOwner: posts.isOwner(pid, uid),
|
||||
isEditor: db.isSetMember(`pid:${pid}:editors`, uid),
|
||||
edit: privsPosts.can('posts:edit', pid, uid),
|
||||
postData: posts.getPostFields(pid, ['tid', 'timestamp', 'deleted', 'deleterUid']),
|
||||
userData: user.getUserFields(uid, ['reputation']),
|
||||
@@ -158,7 +160,10 @@ privsPosts.canEdit = async function (pid, uid) {
|
||||
results.uid = uid;
|
||||
|
||||
const result = await plugins.hooks.fire('filter:privileges.posts.edit', results);
|
||||
return { flag: result.edit && (result.owner || result.isMod), message: '[[error:no-privileges]]' };
|
||||
return {
|
||||
flag: result.edit && (result.isOwner || result.isEditor || result.isMod),
|
||||
message: '[[error:no-privileges]]',
|
||||
};
|
||||
};
|
||||
|
||||
privsPosts.canDelete = async function (pid, uid) {
|
||||
|
||||
@@ -46,6 +46,7 @@ module.exports = function (SocketPosts) {
|
||||
postData.display_moderator_tools = postData.display_edit_tools || postData.display_delete_tools;
|
||||
postData.display_move_tools = results.isAdmin || results.isModerator;
|
||||
postData.display_change_owner_tools = results.isAdmin || results.isModerator;
|
||||
postData.display_manage_editors_tools = results.isAdmin || results.isModerator || postData.selfPost;
|
||||
postData.display_ip_ban = (results.isAdmin || results.isGlobalMod) && !postData.selfPost;
|
||||
postData.display_history = results.history && results.canViewHistory;
|
||||
postData.flags = {
|
||||
@@ -92,4 +93,35 @@ module.exports = function (SocketPosts) {
|
||||
|
||||
await Promise.all(logs);
|
||||
};
|
||||
|
||||
SocketPosts.getEditors = async function (socket, data) {
|
||||
if (!data || !data.pid) {
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
await checkEditorPrivilege(socket.uid, data.pid);
|
||||
const editorUids = await db.getSetMembers(`pid:${data.pid}:editors`);
|
||||
const userData = await user.getUsersFields(editorUids, ['username', 'userslug', 'picture']);
|
||||
return userData;
|
||||
};
|
||||
|
||||
SocketPosts.saveEditors = async function (socket, data) {
|
||||
if (!data || !data.pid || !Array.isArray(data.uids)) {
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
await checkEditorPrivilege(socket.uid, data.pid);
|
||||
await db.delete(`pid:${data.pid}:editors`);
|
||||
await db.setAdd(`pid:${data.pid}:editors`, data.uids);
|
||||
};
|
||||
|
||||
async function checkEditorPrivilege(uid, pid) {
|
||||
const cid = await posts.getCidByPid(pid);
|
||||
const [isAdminOrMod, owner] = await Promise.all([
|
||||
privileges.categories.isAdminOrMod(cid, uid),
|
||||
posts.getPostField(pid, 'uid'),
|
||||
]);
|
||||
const isSelfPost = String(uid) === String(owner);
|
||||
if (!isAdminOrMod && !isSelfPost) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
32
src/views/modals/manage-editors.tpl
Normal file
32
src/views/modals/manage-editors.tpl
Normal file
@@ -0,0 +1,32 @@
|
||||
<div class="card tool-modal shadow">
|
||||
<h5 class="card-header">[[topic:thread-tools.manage-editors]]</h5>
|
||||
<div class="card-body">
|
||||
<p>
|
||||
[[topic:manage-editors-instruction]]
|
||||
</p>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="username"><strong>[[user:username]]</strong></label>
|
||||
<div class="input-group">
|
||||
<input id="username" type="text" class="form-control" name="username">
|
||||
<span class="input-group-text" type="button">
|
||||
<i class="fa fa-search"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap" component="topic/editors">
|
||||
{{{ each editors }}}
|
||||
<div class="badge text-bg-light m-1 p-1 border d-inline-flex gap-1 align-items-center" data-uid="{./uid}">
|
||||
{buildAvatar(@value, "24px", true)}
|
||||
<a href="{config.relative_path}/user/{./userslug}">{./username}</a>
|
||||
<button class="btn btn-ghost btn-sm p-0 remove-user-icon">
|
||||
<i class="fa fa-fw fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
{{{ end }}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer text-end">
|
||||
<button class="btn btn-link btn-sm" id="manage_editors_cancel">[[global:buttons.close]]</button>
|
||||
<button class="btn btn-primary btn-sm" id="manage_editors_commit">[[global:save]]</button>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user