mirror of
https://github.com/wassname/talk.git
synced 2026-06-30 07:38:35 +08:00
added emails for status changes
This commit is contained in:
+2
-37
@@ -1,5 +1,4 @@
|
||||
const errors = require('../../errors');
|
||||
const UserModel = require('../../models/user');
|
||||
const UsersService = require('../../services/users');
|
||||
const {
|
||||
CHANGE_USERNAME,
|
||||
@@ -19,48 +18,14 @@ const setUserUsernameStatus = async (ctx, id, status) => {
|
||||
};
|
||||
|
||||
const setUserBanStatus = async (ctx, id, status) => {
|
||||
const user = await UserModel.findOneAndUpdate({id}, {
|
||||
$set: {
|
||||
'status.banned.status': status
|
||||
},
|
||||
$push: {
|
||||
'status.banned.history': {
|
||||
status,
|
||||
assigned_by: ctx.user.id,
|
||||
created_at: Date.now()
|
||||
}
|
||||
}
|
||||
}, {
|
||||
new: true
|
||||
});
|
||||
if (user === null) {
|
||||
throw errors.ErrNotFound;
|
||||
}
|
||||
|
||||
const user = await UsersService.setBanStatus(id, status, ctx.user.id);
|
||||
if (user.banned) {
|
||||
ctx.pubsub.publish('userBanned', user);
|
||||
}
|
||||
};
|
||||
|
||||
const setUserSuspensionStatus = async (ctx, id, until) => {
|
||||
const user = await UserModel.findOneAndUpdate({id}, {
|
||||
$set: {
|
||||
'status.suspension.until': until
|
||||
},
|
||||
$push: {
|
||||
'status.suspension.history': {
|
||||
until,
|
||||
assigned_by: ctx.user.id,
|
||||
created_at: Date.now()
|
||||
}
|
||||
}
|
||||
}, {
|
||||
new: true
|
||||
});
|
||||
if (user === null) {
|
||||
throw errors.ErrNotFound;
|
||||
}
|
||||
|
||||
const user = await UsersService.setSuspensionStatus(id, until, ctx.user.id);
|
||||
if (user.suspended) {
|
||||
ctx.pubsub.publish('userSuspended', user);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
module.exports.ACTIONS_DELETE = 'actions.delete';
|
||||
module.exports.ACTIONS_NEW = 'actions.new';
|
||||
module.exports.COMMENTS_NEW = 'comments.new';
|
||||
module.exports.COMMENTS_EDIT = 'comments.edit';
|
||||
module.exports = {
|
||||
ACTIONS_DELETE: 'ACTIONS_DELETE',
|
||||
ACTIONS_NEW: 'ACTIONS_NEW',
|
||||
COMMENTS_NEW: 'COMMENTS_NEW',
|
||||
COMMENTS_EDIT: 'COMMENTS_EDIT',
|
||||
USERS_SUSPENSION_CHANGE: 'USERS_SUSPENSION_CHANGE',
|
||||
USERS_BAN_CHANGE: 'USERS_BAN_CHANGE',
|
||||
USERS_USERNAME_STATUS_CHANGE: 'USERS_USERNAME_STATUS_CHANGE'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
const ta = require('timeago.js');
|
||||
|
||||
ta.register('es', require('timeago.js/locales/es'));
|
||||
ta.register('da', require('timeago.js/locales/da'));
|
||||
ta.register('fr', require('timeago.js/locales/fr'));
|
||||
ta.register('pt_BR', require('timeago.js/locales/pt_BR'));
|
||||
|
||||
const timeago = ta();
|
||||
|
||||
module.exports = (time) => {
|
||||
return timeago.format(new Date(time), 'en');
|
||||
};
|
||||
+181
-4
@@ -2,6 +2,15 @@ const uuid = require('uuid');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const errors = require('../errors');
|
||||
const some = require('lodash/some');
|
||||
const merge = require('lodash/merge');
|
||||
const events = require('./events');
|
||||
const timeago = require('./timeago');
|
||||
|
||||
const {
|
||||
USERS_SUSPENSION_CHANGE,
|
||||
USERS_BAN_CHANGE,
|
||||
USERS_USERNAME_STATUS_CHANGE,
|
||||
} = require('./events/constants');
|
||||
|
||||
const {
|
||||
ROOT_URL
|
||||
@@ -24,6 +33,7 @@ const MailerService = require('./mailer');
|
||||
const i18n = require('./i18n');
|
||||
const Wordlist = require('./wordlist');
|
||||
const DomainList = require('./domain_list');
|
||||
const SettingsService = require('./settings');
|
||||
const {escapeRegExp} = require('./regex');
|
||||
|
||||
const EMAIL_CONFIRM_JWT_SUBJECT = 'email_confirm';
|
||||
@@ -39,7 +49,7 @@ const loginRateLimiter = new Limit('loginAttempts', RECAPTCHA_INCORRECT_TRIGGER,
|
||||
|
||||
// UsersService is the interface for the application to interact with the
|
||||
// UserModel through.
|
||||
module.exports = class UsersService {
|
||||
class UsersService {
|
||||
|
||||
/**
|
||||
* Returns a user (if found) for the given email address.
|
||||
@@ -80,8 +90,92 @@ module.exports = class UsersService {
|
||||
}
|
||||
}
|
||||
|
||||
static async setSuspensionStatus(id, until, assignedBy = null) {
|
||||
let user = await UserModel.findOneAndUpdate({id}, {
|
||||
$set: {
|
||||
'status.suspension.until': until
|
||||
},
|
||||
$push: {
|
||||
'status.suspension.history': {
|
||||
until,
|
||||
assigned_by: assignedBy,
|
||||
created_at: Date.now()
|
||||
}
|
||||
}
|
||||
}, {
|
||||
new: true
|
||||
});
|
||||
if (user === null) {
|
||||
user = await UserModel.findOne({id});
|
||||
if (user === null) {
|
||||
throw errors.ErrNotFound;
|
||||
}
|
||||
|
||||
if (
|
||||
user.status.suspension.until === until ||
|
||||
(
|
||||
user.status.suspension.until.getTime() > until.getTime() - 1000 &&
|
||||
user.status.suspension.until.getTime() < until.getTime() + 1000
|
||||
)
|
||||
) {
|
||||
return user;
|
||||
}
|
||||
|
||||
throw new Error('suspension status change edit failed for an unknown reason');
|
||||
}
|
||||
|
||||
// Emit that the user username status was changed.
|
||||
await events.emitAsync(USERS_SUSPENSION_CHANGE, user, until);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
static async setBanStatus(id, status, assignedBy = null) {
|
||||
let user = await UserModel.findOneAndUpdate({
|
||||
id,
|
||||
status: {
|
||||
$ne: status
|
||||
}
|
||||
}, {
|
||||
$set: {
|
||||
'status.banned.status': status
|
||||
},
|
||||
$push: {
|
||||
'status.banned.history': {
|
||||
status,
|
||||
assigned_by: assignedBy,
|
||||
created_at: Date.now()
|
||||
}
|
||||
}
|
||||
}, {
|
||||
new: true
|
||||
});
|
||||
if (user === null) {
|
||||
user = await UserModel.findOne({id});
|
||||
if (user === null) {
|
||||
throw errors.ErrNotFound;
|
||||
}
|
||||
|
||||
if (user.status.banned.status === status) {
|
||||
return user;
|
||||
}
|
||||
|
||||
throw new Error('ban status change edit failed for an unknown reason');
|
||||
}
|
||||
|
||||
// Emit that the user ban status was changed.
|
||||
await events.emitAsync(USERS_BAN_CHANGE, user, status);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
static async setUsernameStatus(id, status, assignedBy = null) {
|
||||
const user = await UserModel.findOneAndUpdate({id}, {
|
||||
let user = await UserModel.findOneAndUpdate({
|
||||
id,
|
||||
status: {
|
||||
$ne: status
|
||||
}
|
||||
}, {
|
||||
$set: {
|
||||
'status.username.status': status
|
||||
},
|
||||
@@ -96,9 +190,21 @@ module.exports = class UsersService {
|
||||
new: true
|
||||
});
|
||||
if (user === null) {
|
||||
throw errors.ErrNotFound;
|
||||
user = await UserModel.findOne({id});
|
||||
if (user === null) {
|
||||
throw errors.ErrNotFound;
|
||||
}
|
||||
|
||||
if (user.status.username.status === status) {
|
||||
return user;
|
||||
}
|
||||
|
||||
throw new Error('username status change edit failed for an unknown reason');
|
||||
}
|
||||
|
||||
// Emit that the user username status was changed.
|
||||
await events.emitAsync(USERS_USERNAME_STATUS_CHANGE, user, status);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
@@ -145,6 +251,9 @@ module.exports = class UsersService {
|
||||
throw new Error('edit username failed for an unexpected reason');
|
||||
}
|
||||
|
||||
// Emit that the user username status was changed.
|
||||
await events.emitAsync(USERS_USERNAME_STATUS_CHANGE, user, toStatus);
|
||||
|
||||
return user;
|
||||
} catch (err) {
|
||||
if (err.code === 11000) {
|
||||
@@ -297,6 +406,21 @@ module.exports = class UsersService {
|
||||
});
|
||||
}
|
||||
|
||||
static async sendEmail(user, options) {
|
||||
const localProfile = user.profiles.find((profile) => profile.provider === 'local');
|
||||
if (!localProfile) {
|
||||
throw new Error('user does not have an email');
|
||||
}
|
||||
|
||||
const {id: to} = localProfile;
|
||||
|
||||
options = merge(options, {
|
||||
to,
|
||||
});
|
||||
|
||||
return MailerService.sendSimple(options);
|
||||
}
|
||||
|
||||
static async changePassword(id, password) {
|
||||
const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS);
|
||||
|
||||
@@ -789,7 +913,60 @@ module.exports = class UsersService {
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = UsersService;
|
||||
|
||||
events.on(USERS_BAN_CHANGE, async (user, status) => {
|
||||
|
||||
// Check to see if the user was banned now and is currently banned.
|
||||
if (user.banned && status) {
|
||||
await UsersService.sendEmail(user, {
|
||||
template: 'banned',
|
||||
locals: {
|
||||
body: 'In accordance with The Coral Project’s community guidelines, your account has been banned. You are now longer allowed to comment, flag or engage with our community.'
|
||||
},
|
||||
subject: 'Your account has been banned',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
events.on(USERS_SUSPENSION_CHANGE, async (user, until) => {
|
||||
|
||||
// Check to see if the user was suspended now and is currently suspended.
|
||||
if (user.suspended && until !== null && until > Date.now()) {
|
||||
const {organizationName} = await SettingsService.retrieve();
|
||||
|
||||
const message = i18n.t(
|
||||
'suspenduser.email_message_suspend',
|
||||
user.username,
|
||||
organizationName,
|
||||
timeago(until),
|
||||
);
|
||||
|
||||
await UsersService.sendEmail(user, {
|
||||
template: 'suspension',
|
||||
locals: {
|
||||
body: message,
|
||||
},
|
||||
subject: 'Your account has been banned',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
events.on(USERS_USERNAME_STATUS_CHANGE, async (user, status) => {
|
||||
if (status === 'REJECTED') {
|
||||
const message = i18n.t('reject_username.email_message_reject');
|
||||
|
||||
await UsersService.sendEmail(user, {
|
||||
template: 'suspension',
|
||||
locals: {
|
||||
body: message
|
||||
},
|
||||
subject: 'Username Rejected'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Extract all the tokenUserNotFound plugins so we can integrate with other
|
||||
// providers.
|
||||
|
||||
Reference in New Issue
Block a user