mirror of
https://github.com/discourse/discourse.git
synced 2025-05-24 14:12:10 +08:00
Send a suspension message via email to a user
This commit is contained in:
@ -244,17 +244,13 @@ const AdminUser = Discourse.User.extend({
|
|||||||
return ajax(`/admin/users/${this.id}/suspend`, {
|
return ajax(`/admin/users/${this.id}/suspend`, {
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
data
|
data
|
||||||
}).then(result => {
|
}).then(result => this.setProperties(result.suspension));
|
||||||
this.setProperties(result.suspension);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
unsuspend() {
|
unsuspend() {
|
||||||
return ajax(`/admin/users/${this.id}/unsuspend`, {
|
return ajax(`/admin/users/${this.id}/unsuspend`, {
|
||||||
type: 'PUT'
|
type: 'PUT'
|
||||||
}).then(result => {
|
}).then(result => this.setProperties(result.suspension));
|
||||||
this.setProperties(result.suspension);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
logOut() {
|
logOut() {
|
||||||
|
@ -56,11 +56,31 @@ class Admin::UsersController < Admin::AdminController
|
|||||||
@user.suspended_till = params[:duration].to_i.days.from_now
|
@user.suspended_till = params[:duration].to_i.days.from_now
|
||||||
@user.suspended_at = DateTime.now
|
@user.suspended_at = DateTime.now
|
||||||
|
|
||||||
|
message = params[:message]
|
||||||
|
|
||||||
|
user_history = nil
|
||||||
|
|
||||||
|
User.transaction do
|
||||||
@user.save!
|
@user.save!
|
||||||
@user.revoke_api_key
|
@user.revoke_api_key
|
||||||
StaffActionLogger.new(current_user).log_user_suspend(@user, params[:reason])
|
|
||||||
|
user_history = StaffActionLogger.new(current_user).log_user_suspend(
|
||||||
|
@user,
|
||||||
|
params[:reason],
|
||||||
|
context: message
|
||||||
|
)
|
||||||
|
end
|
||||||
@user.logged_out
|
@user.logged_out
|
||||||
|
|
||||||
|
if message.present?
|
||||||
|
Jobs.enqueue(
|
||||||
|
:critical_user_email,
|
||||||
|
type: :account_suspended,
|
||||||
|
user_id: @user.id,
|
||||||
|
user_history_id: user_history.id
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
render_json_dump(
|
render_json_dump(
|
||||||
suspension: {
|
suspension: {
|
||||||
suspended: true,
|
suspended: true,
|
||||||
|
@ -29,14 +29,13 @@ module Jobs
|
|||||||
notification = Notification.find_by(id: args[:notification_id])
|
notification = Notification.find_by(id: args[:notification_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
message, skip_reason = message_for_email(user,
|
message, skip_reason = message_for_email(
|
||||||
|
user,
|
||||||
post,
|
post,
|
||||||
type,
|
type,
|
||||||
notification,
|
notification,
|
||||||
args[:notification_type],
|
args
|
||||||
args[:notification_data_hash],
|
)
|
||||||
args[:email_token],
|
|
||||||
args[:to_address])
|
|
||||||
|
|
||||||
if message
|
if message
|
||||||
Email::Sender.new(message, type, user).send
|
Email::Sender.new(message, type, user).send
|
||||||
@ -57,11 +56,21 @@ module Jobs
|
|||||||
quoted
|
quoted
|
||||||
}
|
}
|
||||||
|
|
||||||
def message_for_email(user, post, type, notification, notification_type = nil, notification_data_hash = nil, email_token = nil, to_address = nil)
|
def message_for_email(user, post, type, notification, args = nil)
|
||||||
|
args ||= {}
|
||||||
|
|
||||||
|
notification_type = args[:notification_type]
|
||||||
|
notification_data_hash = args[:notification_data_hash]
|
||||||
|
email_token = args[:email_token]
|
||||||
|
to_address = args[:to_address]
|
||||||
|
|
||||||
set_skip_context(type, user.id, to_address || user.email, post.try(:id))
|
set_skip_context(type, user.id, to_address || user.email, post.try(:id))
|
||||||
|
|
||||||
return skip_message(I18n.t("email_log.anonymous_user")) if user.anonymous?
|
return skip_message(I18n.t("email_log.anonymous_user")) if user.anonymous?
|
||||||
return skip_message(I18n.t("email_log.suspended_not_pm")) if user.suspended? && type.to_s != "user_private_message"
|
|
||||||
|
if user.suspended? && !["user_private_message", "account_suspended"].include?(type.to_s)
|
||||||
|
return skip_message(I18n.t("email_log.suspended_not_pm"))
|
||||||
|
end
|
||||||
|
|
||||||
return if user.staged && type.to_s == "digest"
|
return if user.staged && type.to_s == "digest"
|
||||||
|
|
||||||
@ -119,6 +128,10 @@ module Jobs
|
|||||||
return skip_message(I18n.t('email_log.exceeded_bounces_limit'))
|
return skip_message(I18n.t('email_log.exceeded_bounces_limit'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if args[:user_history_id]
|
||||||
|
email_args[:user_history] = UserHistory.where(id: args[:user_history_id]).first
|
||||||
|
end
|
||||||
|
|
||||||
message = EmailLog.unique_email_per_post(post, user) do
|
message = EmailLog.unique_email_per_post(post, user) do
|
||||||
UserNotifications.send(type, user, email_args)
|
UserNotifications.send(type, user, email_args)
|
||||||
end
|
end
|
||||||
|
@ -35,7 +35,7 @@ module Jobs
|
|||||||
end
|
end
|
||||||
|
|
||||||
def pending_flag_ids
|
def pending_flag_ids
|
||||||
FlagQuery.flagged_post_actions('active')
|
FlagQuery.flagged_post_actions(filter: 'active')
|
||||||
.where('post_actions.created_at < ?', SiteSetting.notify_about_flags_after.to_i.hours.ago)
|
.where('post_actions.created_at < ?', SiteSetting.notify_about_flags_after.to_i.hours.ago)
|
||||||
.pluck(:id)
|
.pluck(:id)
|
||||||
end
|
end
|
||||||
|
@ -68,6 +68,21 @@ class UserNotifications < ActionMailer::Base
|
|||||||
email_token: opts[:email_token])
|
email_token: opts[:email_token])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def account_suspended(user, opts = nil)
|
||||||
|
opts ||= {}
|
||||||
|
|
||||||
|
return unless user_history = opts[:user_history]
|
||||||
|
|
||||||
|
build_email(
|
||||||
|
user.email,
|
||||||
|
template: "user_notifications.account_suspended",
|
||||||
|
locale: user_locale(user),
|
||||||
|
reason: user_history.details,
|
||||||
|
message: user_history.context,
|
||||||
|
suspended_till: I18n.l(user.suspended_till, format: :long)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def short_date(dt)
|
def short_date(dt)
|
||||||
if dt.year == Time.now.year
|
if dt.year == Time.now.year
|
||||||
I18n.l(dt, format: :short_no_year)
|
I18n.l(dt, format: :short_no_year)
|
||||||
|
@ -2630,6 +2630,17 @@ en:
|
|||||||
|
|
||||||
%{message}
|
%{message}
|
||||||
|
|
||||||
|
account_suspended:
|
||||||
|
title: "Account Suspended"
|
||||||
|
subject_template: "[%{email_prefix}] Your account has been suspended"
|
||||||
|
text_body_template: |
|
||||||
|
You have been suspended from the forum until %{suspended_till}.
|
||||||
|
|
||||||
|
%{reason}
|
||||||
|
|
||||||
|
%{message}
|
||||||
|
|
||||||
|
|
||||||
digest:
|
digest:
|
||||||
why: "A brief summary of %{site_link} since your last visit on %{last_seen_at}"
|
why: "A brief summary of %{site_link} since your last visit on %{last_seen_at}"
|
||||||
since_last_visit: "Since your last visit"
|
since_last_visit: "Since your last visit"
|
||||||
|
@ -121,8 +121,53 @@ describe Admin::UsersController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context '.suspend' do
|
context '.suspend' do
|
||||||
|
let(:user) { Fabricate(:evil_trout) }
|
||||||
|
let!(:api_key) { Fabricate(:api_key, user: user) }
|
||||||
|
|
||||||
let(:evil_trout) { Fabricate(:evil_trout) }
|
it "works properly" do
|
||||||
|
put(
|
||||||
|
:suspend,
|
||||||
|
user_id: user.id,
|
||||||
|
duration: 10,
|
||||||
|
reason: "because I said so",
|
||||||
|
format: :json
|
||||||
|
)
|
||||||
|
expect(response).to be_success
|
||||||
|
|
||||||
|
user.reload
|
||||||
|
expect(user.suspended_at).to be_present
|
||||||
|
expect(user.suspended_till).to be_present
|
||||||
|
expect(ApiKey.where(user_id: user.id).count).to eq(0)
|
||||||
|
|
||||||
|
log = UserHistory.where(target_user_id: user.id).order('id desc').first
|
||||||
|
expect(log).to be_present
|
||||||
|
expect(log.details).to match(/because I said so/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can send a message to the user" do
|
||||||
|
Jobs.expects(:enqueue).with(
|
||||||
|
:critical_user_email,
|
||||||
|
has_entries(
|
||||||
|
type: :account_suspended,
|
||||||
|
user_id: user.id,
|
||||||
|
message: "long reason"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
put(
|
||||||
|
:suspend,
|
||||||
|
user_id: user.id,
|
||||||
|
duration: 10,
|
||||||
|
reason: "short reason",
|
||||||
|
message: "long reason",
|
||||||
|
format: :json
|
||||||
|
)
|
||||||
|
expect(response).to be_success
|
||||||
|
|
||||||
|
log = UserHistory.where(target_user_id: user.id).order('id desc').first
|
||||||
|
expect(log).to be_present
|
||||||
|
expect(log.details).to match(/short reason/)
|
||||||
|
expect(log.details).to match(/long reason/)
|
||||||
|
|
||||||
it "also revoke any api keys" do
|
it "also revoke any api keys" do
|
||||||
User.any_instance.expects(:revoke_api_key)
|
User.any_instance.expects(:revoke_api_key)
|
||||||
|
Reference in New Issue
Block a user