mirror of
https://github.com/wassname/talk.git
synced 2026-08-14 12:50:17 +08:00
merge master
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
const CommentModel = require('../models/comment');
|
||||
const EDIT_WINDOW_MS = CommentModel.EDIT_WINDOW_MS;
|
||||
|
||||
const ActionModel = require('../models/action');
|
||||
const ActionsService = require('./actions');
|
||||
const SettingsService = require('./settings');
|
||||
|
||||
const errors = require('../errors');
|
||||
|
||||
@@ -53,8 +53,10 @@ module.exports = class CommentsService {
|
||||
|
||||
// Establish the edit window (if it exists) and add the condition to the
|
||||
// original query.
|
||||
const lastEditableCommentCreatedAt = new Date((new Date()).getTime() - EDIT_WINDOW_MS);
|
||||
let lastEditableCommentCreatedAt;
|
||||
if (!ignoreEditWindow) {
|
||||
const {editCommentWindowLength: editWindowMs} = await SettingsService.retrieve();
|
||||
lastEditableCommentCreatedAt = new Date((new Date()).getTime() - editWindowMs);
|
||||
query.created_at = {
|
||||
$gt: lastEditableCommentCreatedAt,
|
||||
};
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<%= body %>
|
||||
@@ -1 +1 @@
|
||||
<%= body %>
|
||||
<%= body.replace(/\n/g, '<br />') %>
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
const debug = require('debug')('talk:trust');
|
||||
const UserModel = require('../models/user');
|
||||
|
||||
/**
|
||||
* This will create an object with the property name of the action type as the
|
||||
* key and an object as it's value. This will contain a RELIABLE, and UNRELIABLE
|
||||
* property with the number of karma points associated with their particular
|
||||
* state.
|
||||
*
|
||||
* If only the RELIABLE variable is provided, then it will also be used as the
|
||||
* UNRELIABLE variable.
|
||||
*
|
||||
* The form of the environment variable is:
|
||||
*
|
||||
* <name>:<RELIABLE>,<UNRELIABLE>;<name>:<RELIABLE>,<UNRELIABLE>;...
|
||||
*
|
||||
* The default used is:
|
||||
*
|
||||
* comment:1,1;flag:-1,-1
|
||||
*/
|
||||
const parseThresholds = (thresholds) => thresholds
|
||||
.split(';')
|
||||
.filter((threshold) => threshold && threshold.length > 0)
|
||||
.reduce((acc, threshold) => {
|
||||
const thresholds = threshold.split(':');
|
||||
if (thresholds.length < 2) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
let [name, values] = thresholds;
|
||||
let [RELIABLE, UNRELIABLE] = values.split(',').map((value) => parseInt(value));
|
||||
|
||||
if (!(name in acc)) {
|
||||
acc[name] = {};
|
||||
}
|
||||
|
||||
if (isNaN(UNRELIABLE) && !isNaN(RELIABLE)) {
|
||||
acc[name].RELIABLE = RELIABLE;
|
||||
acc[name].UNRELIABLE = RELIABLE;
|
||||
} else {
|
||||
if (!isNaN(UNRELIABLE)) {
|
||||
acc[name].UNRELIABLE = UNRELIABLE;
|
||||
}
|
||||
|
||||
if (!isNaN(RELIABLE)) {
|
||||
acc[name].RELIABLE = RELIABLE;
|
||||
}
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {
|
||||
comment: {
|
||||
RELIABLE: -1,
|
||||
UNRELIABLE: -1
|
||||
},
|
||||
flag: {
|
||||
RELIABLE: -1,
|
||||
UNRELIABLE: -1
|
||||
}
|
||||
});
|
||||
|
||||
const THRESHOLDS = parseThresholds(process.env.TRUST_THRESHOLDS || '');
|
||||
|
||||
debug('using thresholds: ', THRESHOLDS);
|
||||
|
||||
/**
|
||||
* KarmaModel represents the checkable properties of a user and wrapps the
|
||||
* KarmaService function `isReliable` to work flexibly with the graph.
|
||||
*/
|
||||
class KarmaModel {
|
||||
constructor(model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
get flagger() {
|
||||
return KarmaService.isReliable('flag', this.model);
|
||||
}
|
||||
|
||||
get commenter() {
|
||||
return KarmaService.isReliable('comment', this.model);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* KarmaService provides interfaces for editing a user's karma.
|
||||
*/
|
||||
class KarmaService {
|
||||
|
||||
/**
|
||||
* Model returns a KarmaModel based on the passed in user.
|
||||
*/
|
||||
static model(user) {
|
||||
if (user === null || !user.metadata || !user.metadata.trust) {
|
||||
return new KarmaModel({});
|
||||
}
|
||||
|
||||
return new KarmaModel(user.metadata.trust);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects the reliability of a property and returns it if known.
|
||||
* @param {String} name - name of the property
|
||||
* @param {Object} trust - object possibly containing the propertys
|
||||
*/
|
||||
static isReliable(name, trust) {
|
||||
if (trust && trust[name]) {
|
||||
if (trust[name].karma > THRESHOLDS[name].RELIABLE) {
|
||||
return true;
|
||||
} else if (trust[name].karma < THRESHOLDS[name].UNRELIABLE) {
|
||||
return false;
|
||||
}
|
||||
} else if (THRESHOLDS[name].RELIABLE < 0) {
|
||||
return true;
|
||||
} else if (THRESHOLDS[name].UNRELIABLE > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* modifyUserKarma updates the user to adjust their karma, for either the `type`
|
||||
* of 'comment' or 'flag'. If `multi` is true, then it assumes that `id` is an
|
||||
* array of id's.
|
||||
*/
|
||||
static async modifyUser(id, direction = 1, type = 'comment', multi = false) {
|
||||
const key = `metadata.trust.${type}.karma`;
|
||||
|
||||
let update = {
|
||||
$inc: {
|
||||
[key]: direction
|
||||
}
|
||||
};
|
||||
|
||||
if (multi) {
|
||||
|
||||
// If it was in multi-mode but there was no user's to adjust, bail.
|
||||
if (id.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
return UserModel.update({
|
||||
id: {
|
||||
$in: id
|
||||
}
|
||||
}, update, {
|
||||
multi: true
|
||||
});
|
||||
}
|
||||
|
||||
return UserModel.update({id}, update);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = KarmaService;
|
||||
+2
-1
@@ -4,6 +4,7 @@ const UserModel = require('../models/user');
|
||||
|
||||
const AssetsService = require('./assets');
|
||||
const SettingsService = require('./settings');
|
||||
const {ADD_COMMENT_TAG} = require('../perms/constants');
|
||||
|
||||
const errors = require('../errors');
|
||||
|
||||
@@ -114,7 +115,7 @@ class TagsService {
|
||||
|
||||
// Only admin/moderators can modify unique tags, these are tags that are not
|
||||
// in the global list.
|
||||
if (!(user.hasRoles('ADMIN') || user.hasRoles('MODERATOR'))) {
|
||||
if (!user.can(ADD_COMMENT_TAG)) {
|
||||
throw errors.ErrNotAuthorized;
|
||||
}
|
||||
|
||||
|
||||
+45
-18
@@ -389,13 +389,7 @@ module.exports = class UsersService {
|
||||
return Promise.reject(new Error(`role ${role} is not supported`));
|
||||
}
|
||||
|
||||
return UserModel.update({
|
||||
id: id
|
||||
}, {
|
||||
$addToSet: {
|
||||
roles: role
|
||||
}
|
||||
});
|
||||
return UserModel.update({id}, {$set: {roles: [role]}});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -450,28 +444,64 @@ module.exports = class UsersService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspend a user. It changes the status to BANNED and canEditName to True.
|
||||
* @param {String} id id of a user
|
||||
* @param {Function} done callback after the operation is complete
|
||||
* Suspend a user until specified time.
|
||||
* @param {String} id id of a user
|
||||
* @param {String} message message to be send to the user
|
||||
* @param {Date} until date until the suspension is valid.
|
||||
*/
|
||||
static suspendUser(id, message) {
|
||||
static suspendUser(id, message, until) {
|
||||
return UserModel.findOneAndUpdate(
|
||||
{id}, {
|
||||
$set: {
|
||||
suspension: {
|
||||
until,
|
||||
},
|
||||
}
|
||||
})
|
||||
.then((user) => {
|
||||
if (message) {
|
||||
let localProfile = user.profiles.find((profile) => profile.provider === 'local');
|
||||
if (localProfile) {
|
||||
const options =
|
||||
{
|
||||
template: 'suspension', // needed to know which template to render!
|
||||
locals: { // specifies the template locals.
|
||||
body: message
|
||||
},
|
||||
subject: 'Your account has been suspended',
|
||||
to: localProfile.id // This only works if the user has registered via e-mail.
|
||||
// We may want a standard way to access a user's e-mail address in the future
|
||||
};
|
||||
|
||||
return MailerService.sendSimple(options);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject username. It changes the status to BANNED and canEditName to True.
|
||||
* @param {String} id id of a user
|
||||
* @param {String} message message to be send to the user
|
||||
* @param {Date} until date until the suspension is valid.
|
||||
*/
|
||||
static rejectUsername(id, message) {
|
||||
return UserModel.findOneAndUpdate({
|
||||
id
|
||||
}, {
|
||||
$set: {
|
||||
status: 'BANNED',
|
||||
canEditName: true
|
||||
canEditName: true,
|
||||
}
|
||||
})
|
||||
.then((user) => {
|
||||
if (message) {
|
||||
let localProfile = user.profiles.find((profile) => profile.provider === 'local');
|
||||
|
||||
if (localProfile) {
|
||||
const options =
|
||||
{
|
||||
template: 'suspension', // needed to know which template to render!
|
||||
locals: { // specifies the template locals.
|
||||
locals: { // specifies the template locals.
|
||||
body: message
|
||||
},
|
||||
subject: 'Email Suspension',
|
||||
@@ -480,8 +510,6 @@ module.exports = class UsersService {
|
||||
};
|
||||
|
||||
return MailerService.sendSimple(options);
|
||||
} else {
|
||||
return Promise.reject(errors.ErrMissingEmail);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -813,7 +841,7 @@ module.exports = class UsersService {
|
||||
username: username,
|
||||
lowercaseUsername: username.toLowerCase(),
|
||||
canEditName: false,
|
||||
status: 'PENDING'
|
||||
status: 'PENDING',
|
||||
}
|
||||
})
|
||||
.then((result) => {
|
||||
@@ -867,6 +895,5 @@ module.exports = class UsersService {
|
||||
ignoresUsers: usersToStopIgnoring
|
||||
}
|
||||
});
|
||||
console.log('Mongo wrote stopIgnoringUsers', usersToStopIgnoring);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user