v1.18.x
Barış Soner Uşaklı 7 years ago
parent d64b814acb
commit 8446a733e5

@ -0,0 +1,10 @@
{
"administrators": "Administrators",
"global-moderators": "Global Moderators",
"no-global-moderators": "No Global Moderators",
"moderators-of-category": "%1 Moderators",
"no-moderators": "No Moderators",
"add-administrator": "Add Administrator",
"add-global-moderator": "Add Global Moderator",
"add-moderator": "Add Moderator"
}

@ -71,9 +71,15 @@
"alerts.lockout-reset-success": "Lockout(s) reset!",
"alerts.flag-reset-success": "Flags(s) reset!",
"alerts.no-remove-yourself-admin": "You can't remove yourself as Administrator!",
"alerts.make-admin-success": "User(s) are now administrators.",
"alerts.confirm-remove-admin": "Do you really want to remove admins?",
"alerts.remove-admin-success": "User(s) are no longer administrators.",
"alerts.make-admin-success": "User is now administrator.",
"alerts.confirm-remove-admin": "Do you really want to remove this administrator?",
"alerts.remove-admin-success": "User is no longer administrator.",
"alerts.make-global-mod-success": "User is now global moderator.",
"alerts.confirm-remove-global-mod": "Do you really want to remove this global moderator?",
"alerts.remove-global-mod-success": "User is no longer global noderator",
"alerts.make-moderator-success": "User is now moderator.",
"alerts.confirm-remove-moderator": "Do you really want to remove this moderator?",
"alerts.remove-moderator-success": "User is no longer moderator.",
"alerts.confirm-validate-email": "Do you want to validate email(s) of these user(s)?",
"alerts.validate-email-success": "Emails validated",
"alerts.password-reset-confirm": "Do you want to send password reset email(s) to these user(s)?",

@ -12,6 +12,7 @@
"manage/privileges": "Privileges",
"manage/tags": "Tags",
"manage/users": "Users",
"manage/admins-mods": "Admins & Mods",
"manage/registration": "Registration Queue",
"manage/post-queue": "Post Queue",
"manage/groups": "Groups",

@ -14,6 +14,7 @@
@import "./manage/groups";
@import "./manage/registration";
@import "./manage/users";
@import "./manage/admins-mods";
@import "./appearance/customise";
@import "./appearance/themes";
@import "./extend/plugins";

@ -0,0 +1,27 @@
.admins-mods {
.user-card {
margin-right: 10px;
padding: 2px;
}
.remove-user-icon {
margin-right: 5px;
margin-left: 5px;
}
.category-depth-1 {
margin-left: 30px;
}
.category-depth-2 {
margin-left: 60px;
}
.category-depth-3 {
margin-left: 90px;
}
.category-depth-4 {
margin-left: 120px;
}
.category-depth-5 {
margin-left: 150px;
}
}

@ -0,0 +1,142 @@
'use strict';
define('admin/manage/admins-mods', ['translator', 'benchpress', 'autocomplete'], function (translator, Benchpress, autocomplete) {
var AdminsMods = {};
AdminsMods.init = function () {
autocomplete.user($('#admin-search'), function (ev, ui) {
socket.emit('admin.user.makeAdmins', [ui.item.user.uid], function (err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[admin/manage/users:alerts.make-admin-success]]');
$('#admin-search').val('');
if ($('.administrator-area [data-uid="' + ui.item.user.uid + '"]').length) {
return;
}
app.parseAndTranslate('admin/manage/admins-mods', 'admins.members', { admins: { members: [ui.item.user] } }, function (html) {
$('.administrator-area').prepend(html);
});
});
});
$('.administrator-area').on('click', '.remove-user-icon', function () {
var userCard = $(this).parents('[data-uid]');
var uid = userCard.attr('data-uid');
if (parseInt(uid, 10) === parseInt(app.user.uid, 10)) {
return app.alertError('[[admin/manage/users:alerts.no-remove-yourself-admin]]');
}
bootbox.confirm('[[admin/manage/users:alerts.confirm-remove-admin]]', function (confirm) {
if (confirm) {
socket.emit('admin.user.removeAdmins', [uid], function (err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[admin/manage/users:alerts.remove-admin-success]]');
userCard.remove();
});
}
});
});
autocomplete.user($('#global-mod-search'), function (ev, ui) {
socket.emit('admin.groups.join', {
groupName: 'Global Moderators',
uid: ui.item.user.uid,
}, function (err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[admin/manage/users:alerts.make-global-mod-success]]');
$('#global-mod-search').val('');
if ($('.global-moderator-area [data-uid="' + ui.item.user.uid + '"]').length) {
return;
}
app.parseAndTranslate('admin/manage/admins-mods', 'globalMods.members', { globalMods: { members: [ui.item.user] } }, function (html) {
$('.global-moderator-area').prepend(html);
$('#no-global-mods-warning').addClass('hidden');
});
});
});
$('.global-moderator-area').on('click', '.remove-user-icon', function () {
var userCard = $(this).parents('[data-uid]');
var uid = userCard.attr('data-uid');
bootbox.confirm('[[admin/manage/users:alerts.confirm-remove-global-mod]]', function (confirm) {
if (confirm) {
socket.emit('admin.groups.leave', { uid: uid, groupName: 'Global Moderators' }, function (err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[admin/manage/users:alerts.remove-global-mod-success]]');
userCard.remove();
if (!$('.global-moderator-area').children().length) {
$('#no-global-mods-warning').removeClass('hidden');
}
});
}
});
});
autocomplete.user($('.moderator-search'), function (ev, ui) {
var input = $(ev.target);
var cid = $(ev.target).attr('data-cid');
socket.emit('admin.categories.setPrivilege', {
cid: cid,
privilege: ['moderate'],
set: true,
member: ui.item.user.uid,
}, function (err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[admin/manage/users:alerts.make-moderator-success]]');
input.val('');
if ($('.moderator-area[data-cid="' + cid + '"] [data-uid="' + ui.item.user.uid + '"]').length) {
return;
}
app.parseAndTranslate('admin/manage/admins-mods', 'globalMods', { globalMods: [ui.item.user] }, function (html) {
$('.moderator-area[data-cid="' + cid + '"]').prepend(html);
$('.no-moderator-warning[data-cid="' + cid + '"]').addClass('hidden');
});
});
});
$('.moderator-area').on('click', '.remove-user-icon', function () {
var moderatorArea = $(this).parents('[data-cid]');
var cid = moderatorArea.attr('data-cid');
var userCard = $(this).parents('[data-uid]');
var uid = userCard.attr('data-uid');
bootbox.confirm('[[admin/manage/users:alerts.confirm-remove-moderator]]', function (confirm) {
if (confirm) {
socket.emit('admin.categories.setPrivilege', {
cid: cid,
privilege: ['moderate'],
set: false,
member: uid,
}, function (err) {
if (err) {
return app.alertError(err.message);
}
app.alertSuccess('[[admin/manage/users:alerts.remove-moderator-success]]');
userCard.remove();
if (!moderatorArea.children().length) {
$('.no-moderator-warning[data-cid="' + cid + '"]').removeClass('hidden');
}
});
}
});
});
};
return AdminsMods;
});

@ -127,36 +127,6 @@ define('admin/manage/users', ['translator', 'benchpress'], function (translator,
socket.emit('admin.user.resetLockouts', uids, done('[[admin/manage/users:alerts.lockout-reset-success]]'));
});
$('.admin-user').on('click', function () {
var uids = getSelectedUids();
if (!uids.length) {
return;
}
if (uids.indexOf(app.user.uid.toString()) !== -1) {
app.alertError('[[admin/manage/users:alerts.no-remove-yourself-admin]]');
} else {
socket.emit('admin.user.makeAdmins', uids, done('[[admin/manage/users:alerts.make-admin-success]]', '.administrator', true));
}
});
$('.remove-admin-user').on('click', function () {
var uids = getSelectedUids();
if (!uids.length) {
return;
}
if (uids.indexOf(app.user.uid.toString()) !== -1) {
app.alertError('[[admin/manage/users:alerts.no-remove-yourself-admin]]');
} else {
bootbox.confirm('[[admin/manage/users:alerts.confirm-remove-admin]]', function (confirm) {
if (confirm) {
socket.emit('admin.user.removeAdmins', uids, done('[[admin/manage/users:alerts.remove-admin-success]]', '.administrator', false));
}
});
}
});
$('.validate-email').on('click', function () {
var uids = getSelectedUids();
if (!uids.length) {

@ -29,6 +29,11 @@ define('autocomplete', function () {
uid: user.uid,
name: user.username,
slug: user.userslug,
username: user.username,
userslug: user.userslug,
picture: user.picture,
'icon:text': user['icon:text'],
'icon:bgColor': user['icon:bgColor'],
},
};
});

@ -338,7 +338,7 @@ Categories.buildForSelect = function (uid, privilege, callback) {
};
Categories.buildForSelectCategories = function (categories, callback) {
function recursive(category, categoriesData, level) {
function recursive(category, categoriesData, level, depth) {
if (category.link) {
return;
}
@ -347,10 +347,11 @@ Categories.buildForSelectCategories = function (categories, callback) {
category.value = category.cid;
category.level = level;
category.text = level + bullet + category.name;
category.depth = depth;
categoriesData.push(category);
category.children.forEach(function (child) {
recursive(child, categoriesData, '    ' + level);
recursive(child, categoriesData, '    ' + level, depth + 1);
});
}
@ -361,7 +362,7 @@ Categories.buildForSelectCategories = function (categories, callback) {
});
categories.forEach(function (category) {
recursive(category, categoriesData, '');
recursive(category, categoriesData, '', 0);
});
callback(null, categoriesData);
};

@ -31,7 +31,11 @@ module.exports = function (Categories) {
category.name = validator.escape(String(category.name || ''));
category.disabled = category.hasOwnProperty('disabled') ? parseInt(category.disabled, 10) === 1 : undefined;
category.isSection = category.hasOwnProperty('isSection') ? parseInt(category.isSection, 10) === 1 : undefined;
category.icon = category.icon || 'hidden';
if (category.hasOwnProperty('icon')) {
category.icon = category.icon || 'hidden';
}
if (category.hasOwnProperty('post_count')) {
category.post_count = category.post_count || 0;
category.totalPostCount = category.post_count;

@ -4,6 +4,7 @@ var adminController = {
dashboard: require('./admin/dashboard'),
categories: require('./admin/categories'),
privileges: require('./admin/privileges'),
adminsMods: require('./admin/admins-mods'),
tags: require('./admin/tags'),
postQueue: require('./admin/postqueue'),
blacklist: require('./admin/blacklist'),

@ -0,0 +1,50 @@
'use strict';
var async = require('async');
var groups = require('../../groups');
var categories = require('../../categories');
var AdminsMods = module.exports;
AdminsMods.get = function (req, res, next) {
async.waterfall([
function (next) {
async.parallel({
admins: function (next) {
groups.get('administrators', { uid: req.uid }, next);
},
globalMods: function (next) {
groups.get('Global Moderators', { uid: req.uid }, next);
},
categories: function (next) {
getModeratorsOfCategories(req.uid, next);
},
}, next);
},
function (results) {
res.render('admin/manage/admins-mods', results);
},
], next);
};
function getModeratorsOfCategories(uid, callback) {
async.waterfall([
function (next) {
categories.buildForSelect(uid, 'find', next);
},
function (categoryData, next) {
async.map(categoryData, function (category, next) {
async.waterfall([
function (next) {
categories.getModerators(category.cid, next);
},
function (moderators, next) {
category.moderators = moderators;
next(null, category);
},
], next);
}, next);
},
], callback);
}

@ -72,6 +72,8 @@ function addRoutes(router, middleware, controllers) {
router.get('/manage/users/banned', middlewares, controllers.admin.users.banned);
router.get('/manage/registration', middlewares, controllers.admin.users.registrationQueue);
router.get('/manage/admins-mods', middlewares, controllers.admin.adminsMods.get);
router.get('/manage/groups', middlewares, controllers.admin.groups.list);
router.get('/manage/groups/:name', middlewares, controllers.admin.groups.get);

@ -0,0 +1,64 @@
<div class="admins-mods">
<h4><!-- IF admins.icon --><i class="fa {admins.icon}"></i> <!-- ENDIF admins.icon -->[[admin/manage/admins-mods:administrators]]</h4>
<div class="administrator-area">
<!-- BEGIN admins.members -->
<div class="user-card pull-left" data-uid="{admins.members.uid}">
<!-- IF admins.members.picture -->
<img class="avatar avatar-sm" src="{admins.members.picture}" />
<!-- ELSE -->
<div class="avatar avatar-sm" style="background-color: {admins.members.icon:bgColor};">{admins.members.icon:text}</div>
<!-- ENDIF admins.members.picture -->
<a href="{config.relative_path}/user/{admins.members.userslug}">{admins.members.username}</a>
<i class="remove-user-icon fa fa-times" role="button"></i>
</div>
<!-- END admins.members -->
</div>
<input id="admin-search" class="form-control" placeholder="[[admin/manage/admins-mods:add-administrator]]" />
<br/>
<h4><!-- IF globalMods.icon --><i class="fa {globalMods.icon}"></i> <!-- ENDIF globalMods.icon -->[[admin/manage/admins-mods:global-moderators]]</h4>
<div class="global-moderator-area">
<!-- BEGIN globalMods.members -->
<div class="user-card pull-left" data-uid="{globalMods.members.uid}">
<!-- IF globalMods.members.picture -->
<img class="avatar avatar-sm" src="{globalMods.members.picture}" />
<!-- ELSE -->
<div class="avatar avatar-sm" style="background-color: {globalMods.members.icon:bgColor};">{globalMods.members.icon:text}</div>
<!-- ENDIF globalMods.members.picture -->
<a href="{config.relative_path}/user/{globalMods.members.userslug}">{globalMods.members.username}</a>
<i class="remove-user-icon fa fa-times" role="button"></i>
</div>
<!-- END globalMods.members -->
</div>
<div id="no-global-mods-warning" class="<!-- IF globalMods.members.length -->hidden<!-- ENDIF globalMods.members.length -->">[[admin/manage/admins-mods:no-global-moderators]]</div>
<input id="global-mod-search" class="form-control" placeholder="[[admin/manage/admins-mods:add-global-moderator]]" />
<br/>
<!-- BEGIN categories -->
<div class="categories category-wrapper category-depth-{categories.depth}">
<h4><!-- IF categories.icon --><i class="fa {categories.icon}"></i> <!-- ENDIF categories.icon -->[[admin/manage/admins-mods:moderators-of-category, {categories.name}]]</h4>
<div class="moderator-area" data-cid="{categories.cid}">
<!-- BEGIN categories.moderators -->
<div class="user-card pull-left" data-uid="{categories.moderators.uid}">
<!-- IF categories.moderators.picture -->
<img class="avatar avatar-sm" src="{categories.moderators.picture}" />
<!-- ELSE -->
<div class="avatar avatar-sm" style="background-color: {categories.moderators.icon:bgColor};">{categories.moderators.icon:text}</div>
<!-- ENDIF categories.moderators.picture -->
<a href="{config.relative_path}/user/{categories.moderators.userslug}">{categories.moderators.username}</a>
<i class="remove-user-icon fa fa-times" role="button"></i>
</div>
<!-- END categories.moderators -->
</div>
<div data-cid="{categories.cid}" class="no-moderator-warning <!-- IF categories.moderators.length -->hidden<!-- ENDIF categories.moderators.length -->">[[admin/manage/admins-mods:no-moderators]]</div>
<input data-cid="{categories.cid}" class="form-control moderator-search" placeholder="[[admin/manage/admins-mods:add-moderator]]" />
</div>
<br/>
<!-- END categories -->
</div>

@ -18,9 +18,6 @@
<p>
[[admin/manage/categories:privileges.description]]
</p>
<p class="text-warning">
[[admin/manage/categories:privileges.warning]]
</p>
<hr />
<div class="privilege-table-container">
<!-- IF cid -->
@ -32,7 +29,3 @@
</div>
</form>
</div>
<button id="save" class="floating-button mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored">
<i class="material-icons">save</i>
</button>

@ -8,9 +8,6 @@
<div class="btn-group pull-right">
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" type="button">[[admin/manage/users:edit]] <span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="#" class="admin-user"><i class="fa fa-fw fa-shield"></i> [[admin/manage/users:make-admin]]</a></li>
<li><a href="#" class="remove-admin-user"><i class="fa fa-fw fa-ban"></i> [[admin/manage/users:remove-admin]]</a></li>
<li class="divider"></li>
<li><a href="#" class="validate-email"><i class="fa fa-fw fa-check"></i> [[admin/manage/users:validate-email]]</a></li>
<li><a href="#" class="send-validation-email"><i class="fa fa-fw fa-mail-forward"></i> [[admin/manage/users:send-validation-email]]</a></li>
<li><a href="#" class="password-reset-email"><i class="fa fa-fw fa-key"></i> [[admin/manage/users:password-reset-email]]</a></li>

@ -17,6 +17,7 @@
<li><a href="{relative_path}/admin/manage/categories">[[admin/menu:manage/categories]]</a></li>
<li><a href="{relative_path}/admin/manage/privileges">[[admin/menu:manage/privileges]]</a></li>
<li><a href="{relative_path}/admin/manage/users">[[admin/menu:manage/users]]</a></li>
<li><a href="{relative_path}/admin/manage/admins-mods">[[admin/menu:manage/admins-mods]]</a></li>
<li><a href="{relative_path}/admin/manage/groups">[[admin/menu:manage/groups]]</a></li>
<li><a href="{relative_path}/admin/manage/tags">[[admin/menu:manage/tags]]</a></li>
<li><a href="{relative_path}/admin/manage/registration">[[admin/menu:manage/registration]]</a></li>
@ -191,6 +192,7 @@
<li><a href="{relative_path}/admin/manage/categories">[[admin/menu:manage/categories]]</a></li>
<li><a href="{relative_path}/admin/manage/privileges">[[admin/menu:manage/privileges]]</a></li>
<li><a href="{relative_path}/admin/manage/users">[[admin/menu:manage/users]]</a></li>
<li><a href="{relative_path}/admin/manage/admins-mods">[[admin/menu:manage/admins-mods]]</a></li>
<li><a href="{relative_path}/admin/manage/groups">[[admin/menu:manage/groups]]</a></li>
<li><a href="{relative_path}/admin/manage/tags">[[admin/menu:manage/tags]]</a></li>
<li><a href="{relative_path}/admin/manage/registration">[[admin/menu:manage/registration]]</a></li>

@ -255,6 +255,14 @@ describe('Admin Controllers', function () {
});
});
it('should load /admin/manage/admins-mods', function (done) {
request(nconf.get('url') + '/api/admin/manage/admins-mods', { jar: jar, json: true }, function (err, res, body) {
assert.ifError(err);
assert(body);
done();
});
});
it('should return 403 if no referer', function (done) {
request(nconf.get('url') + '/api/admin/users/csv', { jar: jar }, function (err, res, body) {
assert.ifError(err);

Loading…
Cancel
Save