mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 19:46:01 +01:00
@@ -38,5 +38,5 @@
|
|||||||
"bookmarkThreshold": 5,
|
"bookmarkThreshold": 5,
|
||||||
"topicsPerList": 20,
|
"topicsPerList": 20,
|
||||||
"autoDetectLang": 1,
|
"autoDetectLang": 1,
|
||||||
"privileges:flag": 0
|
"min:rep:flag": 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,9 +69,9 @@
|
|||||||
"nodebb-plugin-spam-be-gone": "0.5.1",
|
"nodebb-plugin-spam-be-gone": "0.5.1",
|
||||||
"nodebb-rewards-essentials": "0.0.9",
|
"nodebb-rewards-essentials": "0.0.9",
|
||||||
"nodebb-theme-lavender": "5.0.0",
|
"nodebb-theme-lavender": "5.0.0",
|
||||||
"nodebb-theme-persona": "7.2.11",
|
"nodebb-theme-persona": "7.2.12",
|
||||||
"nodebb-theme-slick": "1.1.2",
|
"nodebb-theme-slick": "1.1.2",
|
||||||
"nodebb-theme-vanilla": "8.1.5",
|
"nodebb-theme-vanilla": "8.1.6",
|
||||||
"nodebb-widget-essentials": "4.0.1",
|
"nodebb-widget-essentials": "4.0.1",
|
||||||
"nodemailer": "4.4.1",
|
"nodemailer": "4.4.1",
|
||||||
"passport": "^0.4.0",
|
"passport": "^0.4.0",
|
||||||
|
|||||||
@@ -5,5 +5,8 @@
|
|||||||
"votes-are-public": "All Votes Are Public",
|
"votes-are-public": "All Votes Are Public",
|
||||||
"thresholds": "Activity Thresholds",
|
"thresholds": "Activity Thresholds",
|
||||||
"min-rep-downvote": "Minimum reputation to downvote posts",
|
"min-rep-downvote": "Minimum reputation to downvote posts",
|
||||||
"min-rep-flag": "Minimum reputation to flag posts"
|
"min-rep-flag": "Minimum reputation to flag posts",
|
||||||
|
"min-rep-website": "Minimum reputation to add \"Website\" to user profile",
|
||||||
|
"min-rep-aboutme": "Minimum reputation to add \"About me\" to user profile",
|
||||||
|
"min-rep-signature": "Minimum reputation to add \"Signature\" to user profile"
|
||||||
}
|
}
|
||||||
@@ -146,6 +146,9 @@
|
|||||||
"downvoting-disabled": "Downvoting is disabled",
|
"downvoting-disabled": "Downvoting is disabled",
|
||||||
"not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post",
|
"not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post",
|
||||||
"not-enough-reputation-to-flag": "You do not have enough reputation to flag this post",
|
"not-enough-reputation-to-flag": "You do not have enough reputation to flag this post",
|
||||||
|
"not-enough-reputation-min-rep-website": "You do not have enough reputation to add a website",
|
||||||
|
"not-enough-reputation-min-rep-aboutme": "You do not have enough reputation to add an about me",
|
||||||
|
"not-enough-reputation-min-rep-signature": "You do not have enough reputation to add a signature",
|
||||||
"already-flagged": "You have already flagged this post",
|
"already-flagged": "You have already flagged this post",
|
||||||
"self-vote": "You cannot vote on your own post",
|
"self-vote": "You cannot vote on your own post",
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ editController.get = function (req, res, callback) {
|
|||||||
userData.maximumProfileImageSize = parseInt(meta.config.maximumProfileImageSize, 10);
|
userData.maximumProfileImageSize = parseInt(meta.config.maximumProfileImageSize, 10);
|
||||||
userData.allowProfileImageUploads = parseInt(meta.config.allowProfileImageUploads, 10) === 1;
|
userData.allowProfileImageUploads = parseInt(meta.config.allowProfileImageUploads, 10) === 1;
|
||||||
userData.allowAccountDelete = parseInt(meta.config.allowAccountDelete, 10) === 1;
|
userData.allowAccountDelete = parseInt(meta.config.allowAccountDelete, 10) === 1;
|
||||||
|
userData.allowWebsite = !userData.isSelf || parseInt(userData.reputation, 10) >= (parseInt(meta.config['min:rep:website'], 10) || 0);
|
||||||
|
userData.allowAboutMe = !userData.isSelf || parseInt(userData.reputation, 10) >= (parseInt(meta.config['min:rep:aboutme'], 10) || 0);
|
||||||
|
userData.allowSignature = !userData.isSelf || parseInt(userData.reputation, 10) >= (parseInt(meta.config['min:rep:signature'], 10) || 0);
|
||||||
userData.profileImageDimension = parseInt(meta.config.profileImageDimension, 10) || 200;
|
userData.profileImageDimension = parseInt(meta.config.profileImageDimension, 10) || 200;
|
||||||
userData.defaultAvatar = user.getDefaultAvatar();
|
userData.defaultAvatar = user.getDefaultAvatar();
|
||||||
|
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ Flags.validate = function (payload, callback) {
|
|||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
var minimumReputation = utils.isNumber(meta.config['privileges:flag']) ? parseInt(meta.config['privileges:flag'], 10) : 0;
|
var minimumReputation = utils.isNumber(meta.config['min:rep:flag']) ? parseInt(meta.config['min:rep:flag'], 10) : 0;
|
||||||
// Check if reporter meets rep threshold (or can edit the target post, in which case threshold does not apply)
|
// Check if reporter meets rep threshold (or can edit the target post, in which case threshold does not apply)
|
||||||
if (!editable.flag && parseInt(data.reporter.reputation, 10) < minimumReputation) {
|
if (!editable.flag && parseInt(data.reporter.reputation, 10) < minimumReputation) {
|
||||||
return callback(new Error('[[error:not-enough-reputation-to-flag]]'));
|
return callback(new Error('[[error:not-enough-reputation-to-flag]]'));
|
||||||
@@ -257,7 +257,7 @@ Flags.validate = function (payload, callback) {
|
|||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
var minimumReputation = utils.isNumber(meta.config['privileges:flag']) ? parseInt(meta.config['privileges:flag'], 10) : 0;
|
var minimumReputation = utils.isNumber(meta.config['min:rep:flag']) ? parseInt(meta.config['min:rep:flag'], 10) : 0;
|
||||||
// Check if reporter meets rep threshold (or can edit the target user, in which case threshold does not apply)
|
// Check if reporter meets rep threshold (or can edit the target user, in which case threshold does not apply)
|
||||||
if (!editable && parseInt(data.reporter.reputation, 10) < minimumReputation) {
|
if (!editable && parseInt(data.reporter.reputation, 10) < minimumReputation) {
|
||||||
return callback(new Error('[[error:not-enough-reputation-to-flag]]'));
|
return callback(new Error('[[error:not-enough-reputation-to-flag]]'));
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ module.exports = function (Posts) {
|
|||||||
return callback(new Error('[[error:self-vote]]'));
|
return callback(new Error('[[error:self-vote]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command === 'downvote' && parseInt(results.reputation, 10) < parseInt(meta.config['privileges:downvote'], 10)) {
|
if (command === 'downvote' && parseInt(results.reputation, 10) < parseInt(meta.config['min:rep:downvote'], 10)) {
|
||||||
return callback(new Error('[[error:not-enough-reputation-to-downvote]]'));
|
return callback(new Error('[[error:not-enough-reputation-to-downvote]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ module.exports = function (privileges) {
|
|||||||
}, next);
|
}, next);
|
||||||
},
|
},
|
||||||
function (results, next) {
|
function (results, next) {
|
||||||
var minimumReputation = utils.isNumber(meta.config['privileges:flag']) ? parseInt(meta.config['privileges:flag'], 10) : 0;
|
var minimumReputation = utils.isNumber(meta.config['min:rep:flag']) ? parseInt(meta.config['min:rep:flag'], 10) : 0;
|
||||||
var canFlag = results.isAdminOrMod || parseInt(results.userReputation, 10) >= minimumReputation;
|
var canFlag = results.isAdminOrMod || parseInt(results.userReputation, 10) >= minimumReputation;
|
||||||
next(null, { flag: canFlag });
|
next(null, { flag: canFlag });
|
||||||
},
|
},
|
||||||
|
|||||||
25
src/upgrades/1.8.0/rename_min_reputation_settings.js
Normal file
25
src/upgrades/1.8.0/rename_min_reputation_settings.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var db = require('../../database');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'Rename privileges:downvote and privileges:flag to min:rep:downvote, min:rep:flag respectively',
|
||||||
|
timestamp: Date.UTC(2018, 0, 12),
|
||||||
|
method: function (callback) {
|
||||||
|
db.getObjectFields('config', ['privileges:downvote', 'privileges:flag'], function (err, config) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.setObject('config', {
|
||||||
|
'min:rep:downvote': parseInt(config['privileges:downvote'], 10) || 0,
|
||||||
|
'min:rep:flag': parseInt(config['privileges:downvote'], 10) || 0,
|
||||||
|
}, function (err) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
db.deleteObjectFields('config', ['privileges:downvote', 'privileges:flag'], callback);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -17,14 +17,6 @@ module.exports = function (User) {
|
|||||||
var updateUid = data.uid;
|
var updateUid = data.uid;
|
||||||
var oldData;
|
var oldData;
|
||||||
|
|
||||||
if (data.aboutme !== undefined && data.aboutme.length > meta.config.maximumAboutMeLength) {
|
|
||||||
return callback(new Error('[[error:about-me-too-long, ' + meta.config.maximumAboutMeLength + ']]'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.signature !== undefined && data.signature.length > meta.config.maximumSignatureLength) {
|
|
||||||
return callback(new Error('[[error:signature-too-long, ' + meta.config.maximumSignatureLength + ']]'));
|
|
||||||
}
|
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
plugins.fireHook('filter:user.updateProfile', { uid: uid, data: data, fields: fields }, next);
|
plugins.fireHook('filter:user.updateProfile', { uid: uid, data: data, fields: fields }, next);
|
||||||
@@ -33,13 +25,7 @@ module.exports = function (User) {
|
|||||||
fields = data.fields;
|
fields = data.fields;
|
||||||
data = data.data;
|
data = data.data;
|
||||||
|
|
||||||
async.series([
|
validateData(uid, data, next);
|
||||||
async.apply(isEmailAvailable, data, updateUid),
|
|
||||||
async.apply(isUsernameAvailable, data, updateUid),
|
|
||||||
async.apply(isGroupTitleValid, data),
|
|
||||||
], function (err) {
|
|
||||||
next(err);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
function (next) {
|
function (next) {
|
||||||
User.getUserFields(updateUid, fields, next);
|
User.getUserFields(updateUid, fields, next);
|
||||||
@@ -73,6 +59,19 @@ module.exports = function (User) {
|
|||||||
], callback);
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function validateData(callerUid, data, callback) {
|
||||||
|
async.series([
|
||||||
|
async.apply(isEmailAvailable, data, data.uid),
|
||||||
|
async.apply(isUsernameAvailable, data, data.uid),
|
||||||
|
async.apply(isGroupTitleValid, data),
|
||||||
|
async.apply(isWebsiteValid, callerUid, data),
|
||||||
|
async.apply(isAboutMeValid, callerUid, data),
|
||||||
|
async.apply(isSignatureValid, callerUid, data),
|
||||||
|
], function (err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function isEmailAvailable(data, uid, callback) {
|
function isEmailAvailable(data, uid, callback) {
|
||||||
if (!data.email) {
|
if (!data.email) {
|
||||||
return callback();
|
return callback();
|
||||||
@@ -141,6 +140,52 @@ module.exports = function (User) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isWebsiteValid(callerUid, data, callback) {
|
||||||
|
if (!data.website) {
|
||||||
|
return setImmediate(callback);
|
||||||
|
}
|
||||||
|
checkMinReputation(callerUid, data.uid, 'min:rep:website', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAboutMeValid(callerUid, data, callback) {
|
||||||
|
if (!data.aboutme) {
|
||||||
|
return setImmediate(callback);
|
||||||
|
}
|
||||||
|
if (data.aboutme !== undefined && data.aboutme.length > meta.config.maximumAboutMeLength) {
|
||||||
|
return callback(new Error('[[error:about-me-too-long, ' + meta.config.maximumAboutMeLength + ']]'));
|
||||||
|
}
|
||||||
|
|
||||||
|
checkMinReputation(callerUid, data.uid, 'min:rep:aboutme', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSignatureValid(callerUid, data, callback) {
|
||||||
|
if (!data.signature) {
|
||||||
|
return setImmediate(callback);
|
||||||
|
}
|
||||||
|
if (data.signature !== undefined && data.signature.length > meta.config.maximumSignatureLength) {
|
||||||
|
return callback(new Error('[[error:signature-too-long, ' + meta.config.maximumSignatureLength + ']]'));
|
||||||
|
}
|
||||||
|
checkMinReputation(callerUid, data.uid, 'min:rep:signature', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkMinReputation(callerUid, uid, setting, callback) {
|
||||||
|
var isSelf = parseInt(callerUid, 10) === parseInt(uid, 10);
|
||||||
|
if (!isSelf) {
|
||||||
|
return setImmediate(callback);
|
||||||
|
}
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
User.getUserField(uid, 'reputation', next);
|
||||||
|
},
|
||||||
|
function (reputation, next) {
|
||||||
|
if (parseInt(reputation, 10) < (parseInt(meta.config[setting], 10) || 0)) {
|
||||||
|
return next(new Error('[[error:not-enough-reputation-' + setting.replace(/:/g, '-') + ']]'));
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
|
}
|
||||||
|
|
||||||
function updateEmail(uid, newEmail, callback) {
|
function updateEmail(uid, newEmail, callback) {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
|
|||||||
@@ -32,8 +32,11 @@
|
|||||||
<div class="col-sm-2 col-xs-12 settings-header">[[admin/settings/reputation:thresholds]]</div>
|
<div class="col-sm-2 col-xs-12 settings-header">[[admin/settings/reputation:thresholds]]</div>
|
||||||
<div class="col-sm-10 col-xs-12">
|
<div class="col-sm-10 col-xs-12">
|
||||||
<form>
|
<form>
|
||||||
<strong>[[admin/settings/reputation:min-rep-downvote]]</strong><br /> <input type="text" class="form-control" placeholder="0" data-field="privileges:downvote"><br />
|
<strong>[[admin/settings/reputation:min-rep-downvote]]</strong><br /> <input type="text" class="form-control" placeholder="0" data-field="min:rep:downvote"><br />
|
||||||
<strong>[[admin/settings/reputation:min-rep-flag]]</strong><br /> <input type="text" class="form-control" placeholder="0" data-field="privileges:flag"><br />
|
<strong>[[admin/settings/reputation:min-rep-flag]]</strong><br /> <input type="text" class="form-control" placeholder="0" data-field="min:rep:flag"><br />
|
||||||
|
<strong>[[admin/settings/reputation:min-rep-website]]</strong><br /> <input type="text" class="form-control" placeholder="0" data-field="min:rep:website"><br />
|
||||||
|
<strong>[[admin/settings/reputation:min-rep-aboutme]]</strong><br /> <input type="text" class="form-control" placeholder="0" data-field="min:rep:aboutme"><br />
|
||||||
|
<strong>[[admin/settings/reputation:min-rep-signature]]</strong><br /> <input type="text" class="form-control" placeholder="0" data-field="min:rep:signature"><br />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -591,21 +591,21 @@ describe('Admin Controllers', function () {
|
|||||||
|
|
||||||
it('should error with not enough reputation to flag', function (done) {
|
it('should error with not enough reputation to flag', function (done) {
|
||||||
var socketFlags = require('../src/socket.io/flags');
|
var socketFlags = require('../src/socket.io/flags');
|
||||||
var oldValue = meta.config['privileges:flag'];
|
var oldValue = meta.config['min:rep:flag'];
|
||||||
meta.config['privileges:flag'] = 1000;
|
meta.config['min:rep:flag'] = 1000;
|
||||||
socketFlags.create({ uid: regularUid }, { id: pid, type: 'post', reason: 'spam' }, function (err) {
|
socketFlags.create({ uid: regularUid }, { id: pid, type: 'post', reason: 'spam' }, function (err) {
|
||||||
assert.equal(err.message, '[[error:not-enough-reputation-to-flag]]');
|
assert.equal(err.message, '[[error:not-enough-reputation-to-flag]]');
|
||||||
meta.config['privileges:flag'] = oldValue;
|
meta.config['min:rep:flag'] = oldValue;
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return flag details', function (done) {
|
it('should return flag details', function (done) {
|
||||||
var socketFlags = require('../src/socket.io/flags');
|
var socketFlags = require('../src/socket.io/flags');
|
||||||
var oldValue = meta.config['privileges:flag'];
|
var oldValue = meta.config['min:rep:flag'];
|
||||||
meta.config['privileges:flag'] = 0;
|
meta.config['min:rep:flag'] = 0;
|
||||||
socketFlags.create({ uid: regularUid }, { id: pid, type: 'post', reason: 'spam' }, function (err, data) {
|
socketFlags.create({ uid: regularUid }, { id: pid, type: 'post', reason: 'spam' }, function (err, data) {
|
||||||
meta.config['privileges:flag'] = oldValue;
|
meta.config['min:rep:flag'] = oldValue;
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
request(nconf.get('url') + '/api/flags/' + data.flagId, { jar: moderatorJar, json: true }, function (err, res, body) {
|
request(nconf.get('url') + '/api/flags/' + data.flagId, { jar: moderatorJar, json: true }, function (err, res, body) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
|
|||||||
@@ -364,7 +364,7 @@ describe('Flags', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not pass validation if flag threshold is set and user rep does not meet it', function (done) {
|
it('should not pass validation if flag threshold is set and user rep does not meet it', function (done) {
|
||||||
Meta.configs.set('privileges:flag', '50', function (err) {
|
Meta.configs.set('min:rep:flag', '50', function (err) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
|
|
||||||
Flags.validate({
|
Flags.validate({
|
||||||
@@ -374,7 +374,7 @@ describe('Flags', function () {
|
|||||||
}, function (err) {
|
}, function (err) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual('[[error:not-enough-reputation-to-flag]]', err.message);
|
assert.strictEqual('[[error:not-enough-reputation-to-flag]]', err.message);
|
||||||
Meta.configs.set('privileges:flag', 0, done);
|
Meta.configs.set('min:rep:flag', 0, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user