Julian Lam 9 years ago
parent d4055ddaef
commit 194716cd68

@ -137,5 +137,7 @@
"info.ban-history": "Recent Ban History",
"info.no-ban-history": "This user has never been banned",
"info.banned-until": "Banned until %1",
"info.banned-permanently": "Banned permanently"
"info.banned-permanently": "Banned permanently",
"info.banned-reason-label": "Reason",
"info.banned-no-reason": "No reason given."
}

@ -112,13 +112,15 @@
}
.ban-modal {
input[type="number"] {
width: 7rem;
text-align: center;
margin-left: 1rem;
}
.form-inline, .form-group {
width: 100%;
}
.units {
line-height: 5rem;
}
}
.admin .ban-modal .units {
line-height: 1.846;
}

@ -60,7 +60,7 @@ define('admin/manage/users', ['admin/modules/selectable', 'translator'], functio
bootbox.confirm('Do you really want to ban ' + (uids.length > 1 ? 'these users' : 'this user') + ' <strong>permanently</strong>?', function(confirm) {
if (confirm) {
socket.emit('user.banUsers', { uids: uids }, done('User(s) banned!', '.ban', true));
socket.emit('user.banUsers', { uids: uids, reason: '' }, done('User(s) banned!', '.ban', true));
}
});
});
@ -91,7 +91,7 @@ define('admin/manage/users', ['admin/modules/selectable', 'translator'], functio
return data;
}, {});
var until = formData.length ? (Date.now() + formData.length * 1000*60*60 * (parseInt(formData.unit, 10) ? 24 : 1)) : 0;
socket.emit('user.banUsers', { uids: uids, until: until }, done('User(s) banned!', '.ban', true));
socket.emit('user.banUsers', { uids: uids, until: until, reason: formData.reason }, done('User(s) banned!', '.ban', true));
}
}
}

@ -126,7 +126,7 @@ define('forum/account/header', [
}, {});
var until = formData.length ? (Date.now() + formData.length * 1000*60*60 * (parseInt(formData.unit, 10) ? 24 : 1)) : 0;
socket.emit('user.banUsers', { uids: [ajaxify.data.theirid], until: until }, function(err) {
socket.emit('user.banUsers', { uids: [ajaxify.data.theirid], until: until, reason: formData.reason || '' }, function(err) {
if (err) {
return app.alertError(err.message);
}

@ -12,12 +12,13 @@ module.exports = function(SocketUser) {
if (Array.isArray(data)) {
data = {
uids: data,
until: 0
until: 0,
reason: ''
};
}
toggleBan(socket.uid, data.uids, function(uid, next) {
banUser(data.until || 0, uid, next);
banUser(uid, data.until || 0, data.reason || '', next);
}, function(err) {
if (err) {
return callback(err);
@ -68,7 +69,7 @@ module.exports = function(SocketUser) {
], callback);
}
function banUser(until, uid, callback) {
function banUser(uid, until, reason, callback) {
async.waterfall([
function (next) {
user.isAdministrator(uid, next);
@ -77,7 +78,7 @@ module.exports = function(SocketUser) {
if (isAdmin) {
return next(new Error('[[error:cant-ban-other-admins]]'));
}
user.ban(uid, until, next);
user.ban(uid, until, reason, next);
},
function (next) {
websockets.in('uid_' + uid).emit('event:banned');

@ -53,13 +53,20 @@ module.exports = function(User) {
], callback);
};
User.ban = function(uid, until, callback) {
User.ban = function(uid, until, reason, callback) {
// "until" (optional) is unix timestamp in milliseconds
// "reason" (optional) is a string
if (!callback && typeof until === 'function') {
callback = until;
until = 0;
reason = '';
} else if (!callback && typeof reason === 'function') {
callback = reason;
reason = '';
}
var now = Date.now();
until = parseInt(until, 10);
if (isNaN(until)) {
return callback(new Error('[[error:ban-expiry-missing]]'));
@ -67,17 +74,21 @@ module.exports = function(User) {
var tasks = [
async.apply(User.setUserField, uid, 'banned', 1),
async.apply(db.sortedSetAdd, 'users:banned', Date.now(), uid),
async.apply(db.sortedSetAdd, 'uid:' + uid + ':bans', Date.now(), until)
async.apply(db.sortedSetAdd, 'users:banned', now, uid),
async.apply(db.sortedSetAdd, 'uid:' + uid + ':bans', now, until)
];
if (until > 0 && Date.now() < until) {
if (until > 0 && now < until) {
tasks.push(async.apply(db.sortedSetAdd, 'users:banned:expire', until, uid));
tasks.push(async.apply(User.setUserField, uid, 'banned:expire', until));
} else {
until = 0;
}
if (reason) {
tasks.push(async.apply(db.sortedSetAdd, 'banned:' + uid + ':reasons', now, reason));
}
async.series(tasks, function (err) {
if (err) {
return callback(err);

@ -13,7 +13,8 @@ module.exports = function(User) {
function(next) {
async.parallel({
flags: async.apply(db.getSortedSetRevRangeWithScores, 'uid:' + uid + ':flag:pids', 0, 19),
bans: async.apply(db.getSortedSetRevRangeWithScores, 'uid:' + uid + ':bans', 0,19)
bans: async.apply(db.getSortedSetRevRangeWithScores, 'uid:' + uid + ':bans', 0, 19),
reasons: async.apply(db.getSortedSetRevRangeWithScores, 'banned:' + uid + ':reasons', 0, 19)
}, next);
},
function(data, next) {
@ -64,15 +65,22 @@ module.exports = function(User) {
}
function formatBanData(data) {
var reasons = data.reasons.reduce(function(memo, cur) {
memo[cur.score] = cur.value;
return memo;
}, {});
data.bans = data.bans.map(function(banObj) {
banObj.until = parseInt(banObj.value, 10);
banObj.untilReadable = new Date(banObj.until).toString();
banObj.timestamp = parseInt(banObj.score, 10);
banObj.timestampReadable = new Date(banObj.score).toString();
banObj.timestampISO = new Date(banObj.score).toISOString();
banObj.reason = reasons[banObj.score] || '[[user:info.banned-no-reason]]';
delete banObj.value;
delete banObj.score;
delete data.reasons;
return banObj;
});

@ -1,13 +1,32 @@
<form class="form-inline">
<div class="form-group text-center">
<label for="days">Ban Length</label>
<input class="form-control" name="length" type="number" min="1" value="1" /><br />
<label>Hours</label>
<input type="radio" name="unit" value="0" checked />
<label>Days</label>
<input type="radio" name="unit" value="1" />
<form class="form">
<div class="row">
<div class="col-xs-4">
<div class="form-group">
<label for="length">Ban Length</label>
<input class="form-control" id="length" name="length" type="number" min="1" value="1" />
</div>
</div>
<div class="col-xs-8">
<div class="form-group">
<label for="reason">Reason <span class="text-muted">(Optional)</span></label>
<input type="text" class="form-control" id="reason" name="reason" />
</div>
</div>
</div>
<div class="row">
<div class="col-sm-4 text-center">
<div class="form-group units">
<label>Hours</label>
<input type="radio" name="unit" value="0" checked />
&nbsp;&nbsp;
<label>Days</label>
<input type="radio" name="unit" value="1" />
</div>
</div>
<div class="col-sm-8">
<p class="help-block">
Enter the length of time for the ban. Note that a time of 0 will be a considered a permanent ban.
</p>
</div>
</div>
<p class="help-block">
Enter the length of time for the ban. Note that a time of 0 will be a considered a permanent ban.
</p>
</form>
Loading…
Cancel
Save