PERF: Split skipped email logs into a seperate table.
This commit is contained in:
parent
9b84e78fdf
commit
ae8b0a517f
|
@ -1,9 +1,9 @@
|
||||||
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
import AdminEmailLogsController from 'admin/controllers/admin-email-logs';
|
||||||
import debounce from "discourse/lib/debounce";
|
import debounce from 'discourse/lib/debounce';
|
||||||
import EmailLog from "admin/models/email-log";
|
import EmailLog from 'admin/models/email-log';
|
||||||
|
|
||||||
export default AdminEmailLogsController.extend({
|
export default AdminEmailLogsController.extend({
|
||||||
filterEmailLogs: debounce(function() {
|
filterEmailLogs: debounce(function() {
|
||||||
EmailLog.findAll(this.get("filter")).then(logs => this.set("model", logs));
|
EmailLog.findAll(this.get('filter')).then(logs => this.set('model', logs));
|
||||||
}, 250).observes("filter.{user,address,type,skipped_reason}")
|
}, 250).observes('filter.{user,address,type}')
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,5 +5,5 @@ import EmailLog from "admin/models/email-log";
|
||||||
export default AdminEmailLogsController.extend({
|
export default AdminEmailLogsController.extend({
|
||||||
filterEmailLogs: debounce(function() {
|
filterEmailLogs: debounce(function() {
|
||||||
EmailLog.findAll(this.get("filter")).then(logs => this.set("model", logs));
|
EmailLog.findAll(this.get("filter")).then(logs => this.set("model", logs));
|
||||||
}, 250).observes("filter.{user,address,type,skipped_reason}")
|
}, 250).observes("filter.{user,address,type}")
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<td>{{text-field value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
|
<td>{{text-field value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
|
||||||
<td>{{text-field value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
|
<td>{{text-field value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
|
||||||
<td>{{text-field value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
|
<td>{{text-field value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
|
||||||
<td>{{text-field value=filter.skipped_reason placeholderKey="admin.email.logs.filters.skipped_reason_placeholder"}}</td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{{#each model as |l|}}
|
{{#each model as |l|}}
|
||||||
|
|
|
@ -18,17 +18,17 @@ class Admin::EmailController < Admin::AdminController
|
||||||
end
|
end
|
||||||
|
|
||||||
def sent
|
def sent
|
||||||
email_logs = filter_email_logs(EmailLog.sent, params)
|
email_logs = filter_logs(EmailLog, params)
|
||||||
render_serialized(email_logs, EmailLogSerializer)
|
render_serialized(email_logs, EmailLogSerializer)
|
||||||
end
|
end
|
||||||
|
|
||||||
def skipped
|
def skipped
|
||||||
email_logs = filter_email_logs(EmailLog.skipped, params)
|
skipped_email_logs = filter_logs(SkippedEmailLog, params)
|
||||||
render_serialized(email_logs, EmailLogSerializer)
|
render_serialized(skipped_email_logs, SkippedEmailLogSerializer)
|
||||||
end
|
end
|
||||||
|
|
||||||
def bounced
|
def bounced
|
||||||
email_logs = filter_email_logs(EmailLog.bounced, params)
|
email_logs = filter_logs(EmailLog.bounced, params)
|
||||||
render_serialized(email_logs, EmailLogSerializer)
|
render_serialized(email_logs, EmailLogSerializer)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -137,20 +137,20 @@ class Admin::EmailController < Admin::AdminController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def filter_email_logs(email_logs, params)
|
def filter_logs(logs, params)
|
||||||
email_logs = email_logs.includes(:user, post: :topic)
|
table_name = logs.table_name
|
||||||
|
|
||||||
|
logs = logs.includes(:user, post: :topic)
|
||||||
.references(:user)
|
.references(:user)
|
||||||
.order(created_at: :desc)
|
.order(created_at: :desc)
|
||||||
.offset(params[:offset] || 0)
|
.offset(params[:offset] || 0)
|
||||||
.limit(50)
|
.limit(50)
|
||||||
|
|
||||||
email_logs = email_logs.where("users.username ILIKE ?", "%#{params[:user]}%") if params[:user].present?
|
logs = logs.where("users.username ILIKE ?", "%#{params[:user]}%") if params[:user].present?
|
||||||
email_logs = email_logs.where("email_logs.to_address ILIKE ?", "%#{params[:address]}%") if params[:address].present?
|
logs = logs.where("#{table_name}.to_address ILIKE ?", "%#{params[:address]}%") if params[:address].present?
|
||||||
email_logs = email_logs.where("email_logs.email_type ILIKE ?", "%#{params[:type]}%") if params[:type].present?
|
logs = logs.where("#{table_name}.email_type ILIKE ?", "%#{params[:type]}%") if params[:type].present?
|
||||||
email_logs = email_logs.where("email_logs.reply_key ILIKE ?", "%#{params[:reply_key]}%") if params[:reply_key].present?
|
logs = logs.where("#{table_name}.reply_key ILIKE ?", "%#{params[:reply_key]}%") if params[:reply_key].present?
|
||||||
email_logs = email_logs.where("email_logs.skipped_reason ILIKE ?", "%#{params[:skipped_reason]}%") if params[:skipped_reason].present?
|
logs
|
||||||
|
|
||||||
email_logs
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_incoming_emails(incoming_emails, params)
|
def filter_incoming_emails(incoming_emails, params)
|
||||||
|
|
|
@ -42,17 +42,26 @@ module Jobs
|
||||||
users.find_each do |user|
|
users.find_each do |user|
|
||||||
if Guardian.new(user).can_see?(post)
|
if Guardian.new(user).can_see?(post)
|
||||||
if EmailLog.reached_max_emails?(user)
|
if EmailLog.reached_max_emails?(user)
|
||||||
skip(user.email, user.id, post.id, I18n.t('email_log.exceeded_emails_limit'))
|
skip(user.email, user.id, post.id,
|
||||||
|
SkippedEmailLog.reason_types[:exceeded_emails_limit]
|
||||||
|
)
|
||||||
|
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
if user.user_stat.bounce_score >= SiteSetting.bounce_score_threshold
|
if user.user_stat.bounce_score >= SiteSetting.bounce_score_threshold
|
||||||
skip(user.email, user.id, post.id, I18n.t('email_log.exceeded_bounces_limit'))
|
skip(user.email, user.id, post.id,
|
||||||
|
SkippedEmailLog.reason_types[:exceeded_bounces_limit]
|
||||||
|
)
|
||||||
|
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
if (user.id == post.user_id) && (user.user_option.mailing_list_mode_frequency == 2)
|
if (user.id == post.user_id) && (user.user_option.mailing_list_mode_frequency == 2)
|
||||||
skip(user.email, user.id, post.id, I18n.t('email_log.no_echo_mailing_list_mode'))
|
skip(user.email, user.id, post.id,
|
||||||
|
SkippedEmailLog.reason_types[:mailing_list_no_echo_mode]
|
||||||
|
)
|
||||||
|
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -70,14 +79,13 @@ module Jobs
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def skip(to_address, user_id, post_id, reason)
|
def skip(to_address, user_id, post_id, reason_type)
|
||||||
EmailLog.create!(
|
SkippedEmailLog.create!(
|
||||||
email_type: 'mailing_list',
|
email_type: 'mailing_list',
|
||||||
to_address: to_address,
|
to_address: to_address,
|
||||||
user_id: user_id,
|
user_id: user_id,
|
||||||
post_id: post_id,
|
post_id: post_id,
|
||||||
skipped: true,
|
reason_type: reason_type
|
||||||
skipped_reason: "[MailingList] #{reason}"
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,18 +20,21 @@ module Jobs
|
||||||
|
|
||||||
set_skip_context(type, args[:user_id], to_address, args[:post_id])
|
set_skip_context(type, args[:user_id], to_address, args[:post_id])
|
||||||
|
|
||||||
return skip(I18n.t("email_log.no_user", user_id: args[:user_id])) unless user
|
return skip(SkippedEmailLog.reason_types[:user_email_no_user]) unless user
|
||||||
|
|
||||||
if args[:post_id].present?
|
if args[:post_id].present?
|
||||||
post = Post.find_by(id: args[:post_id])
|
post = Post.find_by(id: args[:post_id])
|
||||||
return skip(I18n.t('email_log.post_not_found', post_id: args[:post_id])) unless post.present?
|
|
||||||
|
unless post.present?
|
||||||
|
return skip(SkippedEmailLog.reason_types[:user_email_post_not_found])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if args[:notification_id].present?
|
if args[:notification_id].present?
|
||||||
notification = Notification.find_by(id: args[:notification_id])
|
notification = Notification.find_by(id: args[:notification_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
message, skip_reason = message_for_email(
|
message, skip_reason_type = message_for_email(
|
||||||
user,
|
user,
|
||||||
post,
|
post,
|
||||||
type,
|
type,
|
||||||
|
@ -42,7 +45,7 @@ module Jobs
|
||||||
if message
|
if message
|
||||||
Email::Sender.new(message, type, user).send
|
Email::Sender.new(message, type, user).send
|
||||||
else
|
else
|
||||||
skip_reason
|
skip_reason_type
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -68,10 +71,12 @@ module Jobs
|
||||||
|
|
||||||
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?
|
if user.anonymous?
|
||||||
|
return skip_message(SkippedEmailLog.reason_types[:user_email_anonymous_user])
|
||||||
|
end
|
||||||
|
|
||||||
if user.suspended? && !["user_private_message", "account_suspended"].include?(type.to_s)
|
if user.suspended? && !["user_private_message", "account_suspended"].include?(type.to_s)
|
||||||
return skip_message(I18n.t("email_log.suspended_not_pm"))
|
return skip_message(SkippedEmailLog.reason_types[:user_email_user_suspended_not_pm])
|
||||||
end
|
end
|
||||||
|
|
||||||
return if user.staged && type.to_s == "digest"
|
return if user.staged && type.to_s == "digest"
|
||||||
|
@ -81,8 +86,10 @@ module Jobs
|
||||||
|
|
||||||
email_args = {}
|
email_args = {}
|
||||||
|
|
||||||
if post || notification || notification_type
|
if (post || notification || notification_type) &&
|
||||||
return skip_message(I18n.t('email_log.seen_recently')) if seen_recently && !user.suspended?
|
(seen_recently && !user.suspended?)
|
||||||
|
|
||||||
|
return skip_message(SkippedEmailLog.reason_types[:user_email_seen_recently])
|
||||||
end
|
end
|
||||||
|
|
||||||
email_args[:post] = post if post
|
email_args[:post] = post if post
|
||||||
|
@ -108,13 +115,13 @@ module Jobs
|
||||||
|
|
||||||
unless user.user_option.email_always?
|
unless user.user_option.email_always?
|
||||||
if (notification && notification.read?) || (post && post.seen?(user))
|
if (notification && notification.read?) || (post && post.seen?(user))
|
||||||
return skip_message(I18n.t('email_log.notification_already_read'))
|
return skip_message(SkippedEmailLog.reason_types[:user_email_notification_already_read])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
skip_reason = skip_email_for_post(post, user)
|
skip_reason_type = skip_email_for_post(post, user)
|
||||||
return skip_message(skip_reason) if skip_reason.present?
|
return skip_message(skip_reason_type) if skip_reason_type.present?
|
||||||
|
|
||||||
# Make sure that mailer exists
|
# Make sure that mailer exists
|
||||||
raise Discourse::InvalidParameters.new("type=#{type}") unless UserNotifications.respond_to?(type)
|
raise Discourse::InvalidParameters.new("type=#{type}") unless UserNotifications.respond_to?(type)
|
||||||
|
@ -123,11 +130,11 @@ module Jobs
|
||||||
email_args[:new_email] = user.email if type.to_s == "notify_old_email"
|
email_args[:new_email] = user.email if type.to_s == "notify_old_email"
|
||||||
|
|
||||||
if EmailLog.reached_max_emails?(user, type.to_s)
|
if EmailLog.reached_max_emails?(user, type.to_s)
|
||||||
return skip_message(I18n.t('email_log.exceeded_emails_limit'))
|
return skip_message(SkippedEmailLog.reason_types[:exceeded_emails_limit])
|
||||||
end
|
end
|
||||||
|
|
||||||
if !EmailLog::CRITICAL_EMAIL_TYPES.include?(type.to_s) && user.user_stat.bounce_score >= SiteSetting.bounce_score_threshold
|
if !EmailLog::CRITICAL_EMAIL_TYPES.include?(type.to_s) && user.user_stat.bounce_score >= SiteSetting.bounce_score_threshold
|
||||||
return skip_message(I18n.t('email_log.exceeded_bounces_limit'))
|
return skip_message(SkippedEmailLog.reason_types[:exceeded_bounces_limit])
|
||||||
end
|
end
|
||||||
|
|
||||||
if args[:user_history_id]
|
if args[:user_history_id]
|
||||||
|
@ -169,26 +176,38 @@ module Jobs
|
||||||
# If this email has a related post, don't send an email if it's been deleted or seen recently.
|
# If this email has a related post, don't send an email if it's been deleted or seen recently.
|
||||||
def skip_email_for_post(post, user)
|
def skip_email_for_post(post, user)
|
||||||
if post
|
if post
|
||||||
return I18n.t('email_log.topic_nil') if post.topic.blank?
|
if post.topic.blank?
|
||||||
return I18n.t('email_log.post_user_deleted') if post.user.blank?
|
return SkippedEmailLog.reason_types[:user_email_topic_nil]
|
||||||
return I18n.t('email_log.post_deleted') if post.user_deleted?
|
end
|
||||||
return I18n.t('email_log.user_suspended') if user.suspended? && !post.user&.staff?
|
|
||||||
|
if post.user.blank?
|
||||||
|
return SkippedEmailLog.reason_types[:user_email_post_user_deleted]
|
||||||
|
end
|
||||||
|
|
||||||
|
if post.user_deleted?
|
||||||
|
return SkippedEmailLog.reason_types[:user_email_post_deleted]
|
||||||
|
end
|
||||||
|
|
||||||
|
if user.suspended? && !post.user&.staff?
|
||||||
|
return SkippedEmailLog.reason_types[:user_email_user_suspended]
|
||||||
|
end
|
||||||
|
|
||||||
already_read = !user.user_option.email_always? && PostTiming.exists?(topic_id: post.topic_id, post_number: post.post_number, user_id: user.id)
|
already_read = !user.user_option.email_always? && PostTiming.exists?(topic_id: post.topic_id, post_number: post.post_number, user_id: user.id)
|
||||||
return I18n.t('email_log.already_read') if already_read
|
if already_read
|
||||||
|
return SkippedEmailLog.reason_types[:user_email_already_read]
|
||||||
|
end
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def skip(reason)
|
def skip(reason_type)
|
||||||
EmailLog.create!(
|
SkippedEmailLog.create!(
|
||||||
email_type: @skip_context[:type],
|
email_type: @skip_context[:type],
|
||||||
to_address: @skip_context[:to_address],
|
to_address: @skip_context[:to_address],
|
||||||
user_id: @skip_context[:user_id],
|
user_id: @skip_context[:user_id],
|
||||||
post_id: @skip_context[:post_id],
|
post_id: @skip_context[:post_id],
|
||||||
skipped: true,
|
reason_type: reason_type
|
||||||
skipped_reason: "[UserEmail] #{reason}",
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@ module Jobs
|
||||||
EmailLog.where(reply_key: nil)
|
EmailLog.where(reply_key: nil)
|
||||||
.where("created_at < ?", threshold)
|
.where("created_at < ?", threshold)
|
||||||
.delete_all
|
.delete_all
|
||||||
|
|
||||||
|
SkippedEmailLog.where("created_at < ?", threshold).delete_all
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
class SkippedEmailLog < ActiveRecord::Base
|
||||||
|
belongs_to :email_log
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :post
|
||||||
|
has_one :topic, through: :post
|
||||||
|
|
||||||
|
validates :email_type, :to_address, :reason_type, presence: true
|
||||||
|
|
||||||
|
validates :custom_reason, presence: true, if: -> { is_custom? }
|
||||||
|
validates :custom_reason, absence: true, if: -> { !is_custom? }
|
||||||
|
validate :ensure_valid_reason_type
|
||||||
|
|
||||||
|
def self.reason_types
|
||||||
|
Enum.new(
|
||||||
|
custom: 1,
|
||||||
|
exceeded_emails_limit: 2,
|
||||||
|
exceeded_bounces_limit: 3,
|
||||||
|
mailing_list_no_echo_mode: 4,
|
||||||
|
user_email_no_user: 5,
|
||||||
|
user_email_post_not_found: 6,
|
||||||
|
user_email_anonymous_user: 7,
|
||||||
|
user_email_user_suspended_not_pm: 8,
|
||||||
|
user_email_seen_recently: 9,
|
||||||
|
user_email_notification_already_read: 10,
|
||||||
|
user_email_topic_nil: 11,
|
||||||
|
user_email_post_user_deleted: 12,
|
||||||
|
user_email_post_deleted: 13,
|
||||||
|
user_email_user_suspended: 14,
|
||||||
|
user_email_already_read: 15,
|
||||||
|
sender_message_blank: 16,
|
||||||
|
sender_message_to_blank: 17,
|
||||||
|
sender_text_part_body_blank: 18,
|
||||||
|
sender_body_blank: 19
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def reason
|
||||||
|
if is_custom?
|
||||||
|
self.custom_reason
|
||||||
|
else
|
||||||
|
type = self.reason_type
|
||||||
|
|
||||||
|
I18n.t(
|
||||||
|
"skipped_email_log.#{SkippedEmailLog.reason_types[type]}",
|
||||||
|
user_id: self.user_id,
|
||||||
|
post_id: self.post_id
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def is_custom?
|
||||||
|
self.reason_type == self.class.reason_types[:custom]
|
||||||
|
end
|
||||||
|
|
||||||
|
def ensure_valid_reason_type
|
||||||
|
unless self.class.reason_types[self.reason_type]
|
||||||
|
self.errors.add(:reason_type, :invalid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: skipped_email_logs
|
||||||
|
#
|
||||||
|
# id :bigint(8) not null, primary key
|
||||||
|
# email_type :string not null
|
||||||
|
# to_address :string not null
|
||||||
|
# user_id :integer
|
||||||
|
# post_id :integer
|
||||||
|
# reason_type :integer not null
|
||||||
|
# custom_reason :text
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_skipped_email_logs_on_created_at (created_at)
|
||||||
|
# index_skipped_email_logs_on_post_id (post_id)
|
||||||
|
# index_skipped_email_logs_on_reason_type (reason_type)
|
||||||
|
# index_skipped_email_logs_on_user_id (user_id)
|
||||||
|
#
|
|
@ -0,0 +1,29 @@
|
||||||
|
module EmailLogsMixin
|
||||||
|
def self.included(klass)
|
||||||
|
klass.attributes :id,
|
||||||
|
:to_address,
|
||||||
|
:email_type,
|
||||||
|
:user_id,
|
||||||
|
:created_at,
|
||||||
|
:post_url,
|
||||||
|
:post_description
|
||||||
|
|
||||||
|
klass.has_one :user, serializer: BasicUserSerializer, embed: :objects
|
||||||
|
end
|
||||||
|
|
||||||
|
def post_url
|
||||||
|
object.post.url
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_post_url?
|
||||||
|
object.post.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_post_description?
|
||||||
|
object.post.present? && object.post.topic.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def post_description
|
||||||
|
"#{object.post.topic.title} ##{object.post.post_number}"
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,37 +1,8 @@
|
||||||
class EmailLogSerializer < ApplicationSerializer
|
class EmailLogSerializer < ApplicationSerializer
|
||||||
|
include EmailLogsMixin
|
||||||
|
|
||||||
attributes :id,
|
attributes :reply_key,
|
||||||
:reply_key,
|
|
||||||
:to_address,
|
|
||||||
:email_type,
|
|
||||||
:user_id,
|
|
||||||
:created_at,
|
|
||||||
:skipped,
|
|
||||||
:skipped_reason,
|
|
||||||
:post_url,
|
|
||||||
:post_description,
|
|
||||||
:bounced
|
:bounced
|
||||||
|
|
||||||
has_one :user, serializer: BasicUserSerializer, embed: :objects
|
has_one :user, serializer: BasicUserSerializer, embed: :objects
|
||||||
|
|
||||||
def include_skipped_reason?
|
|
||||||
object.skipped
|
|
||||||
end
|
|
||||||
|
|
||||||
def post_url
|
|
||||||
object.post.url
|
|
||||||
end
|
|
||||||
|
|
||||||
def include_post_url?
|
|
||||||
object.post.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def include_post_description?
|
|
||||||
object.post.present? && object.post.topic.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def post_description
|
|
||||||
"#{object.post.topic.title} ##{object.post.post_number}"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
class SkippedEmailLogSerializer < ApplicationSerializer
|
||||||
|
include EmailLogsMixin
|
||||||
|
|
||||||
|
attributes :skipped_reason
|
||||||
|
|
||||||
|
def skipped_reason
|
||||||
|
object.reason
|
||||||
|
end
|
||||||
|
end
|
|
@ -3352,7 +3352,6 @@ en:
|
||||||
address_placeholder: "name@example.com"
|
address_placeholder: "name@example.com"
|
||||||
type_placeholder: "digest, signup..."
|
type_placeholder: "digest, signup..."
|
||||||
reply_key_placeholder: "reply key"
|
reply_key_placeholder: "reply key"
|
||||||
skipped_reason_placeholder: "reason"
|
|
||||||
|
|
||||||
moderation_history:
|
moderation_history:
|
||||||
performed_by: "Performed By"
|
performed_by: "Performed By"
|
||||||
|
|
|
@ -3163,25 +3163,25 @@ en:
|
||||||
sockpuppet: "A new user created a topic, and another new user at the same IP address (%{ip_address}) replied. See the <a href='/admin/site_settings/category/spam'>`flag_sockpuppets`</a> site setting."
|
sockpuppet: "A new user created a topic, and another new user at the same IP address (%{ip_address}) replied. See the <a href='/admin/site_settings/category/spam'>`flag_sockpuppets`</a> site setting."
|
||||||
spam_hosts: "This new user tried to create multiple posts with links to the same domain (%{domain}). See the <a href='/admin/site_settings/category/spam'>`newuser_spam_host_threshold`</a> site setting."
|
spam_hosts: "This new user tried to create multiple posts with links to the same domain (%{domain}). See the <a href='/admin/site_settings/category/spam'>`newuser_spam_host_threshold`</a> site setting."
|
||||||
|
|
||||||
email_log:
|
skipped_email_log:
|
||||||
post_user_deleted: "User of the post has been deleted."
|
|
||||||
no_user: "Can't find user with id %{user_id}"
|
|
||||||
anonymous_user: "User is anonymous"
|
|
||||||
suspended_not_pm: "User is suspended, not a message"
|
|
||||||
seen_recently: "User was seen recently"
|
|
||||||
post_not_found: "Can't find a post with id %{post_id}"
|
|
||||||
notification_already_read: "The notification this email is about has already been read"
|
|
||||||
topic_nil: "post.topic is nil"
|
|
||||||
post_deleted: "post was deleted by the author"
|
|
||||||
user_suspended: "user was suspended"
|
|
||||||
already_read: "user has already read this post"
|
|
||||||
exceeded_emails_limit: "Exceeded max_emails_per_day_per_user"
|
exceeded_emails_limit: "Exceeded max_emails_per_day_per_user"
|
||||||
exceeded_bounces_limit: "Exceeded bounce_score_threshold"
|
exceeded_bounces_limit: "Exceeded bounce_score_threshold"
|
||||||
message_blank: "message is blank"
|
mailing_list_no_echo_mode: "Mailing list notifications disabled for user's own posts"
|
||||||
message_to_blank: "message.to is blank"
|
user_email_no_user: "Can't find user with id %{user_id}"
|
||||||
text_part_body_blank: "text_part.body is blank"
|
user_email_post_not_found: "Can't find a post with id %{post_id}"
|
||||||
body_blank: "body is blank"
|
user_email_anonymous_user: "User is anonymous"
|
||||||
no_echo_mailing_list_mode: "Mailing list notifications disabled for user's own posts"
|
user_email_user_suspended_not_pm: "User is suspended, not a message"
|
||||||
|
user_email_seen_recently: "User was seen recently"
|
||||||
|
user_email_notification_already_read: "The notification this email is about has already been read"
|
||||||
|
user_email_notification_topic_nil: "post.topic is nil"
|
||||||
|
user_email_post_user_deleted: "User of the post has been deleted."
|
||||||
|
user_email_post_deleted: "post was deleted by the author"
|
||||||
|
user_email_user_suspended: "user was suspended"
|
||||||
|
user_email_already_read: "user has already read this post"
|
||||||
|
sender_message_blank: "message is blank"
|
||||||
|
sender_message_to_blank: "message.to is blank"
|
||||||
|
sender_text_part_body_blank: "text_part.body is blank"
|
||||||
|
sender_text_body_blank: "body is blank"
|
||||||
|
|
||||||
color_schemes:
|
color_schemes:
|
||||||
base_theme_name: "Base"
|
base_theme_name: "Base"
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
require 'migration/column_dropper'
|
||||||
|
|
||||||
|
class CreateSkippedEmailLogs < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_table :skipped_email_logs do |t|
|
||||||
|
t.string :email_type, null: false
|
||||||
|
t.string :to_address, null: false
|
||||||
|
t.integer :user_id
|
||||||
|
t.integer :post_id
|
||||||
|
t.integer :reason_type, null: false
|
||||||
|
t.text :custom_reason
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :skipped_email_logs, :created_at
|
||||||
|
add_index :skipped_email_logs, :user_id
|
||||||
|
add_index :skipped_email_logs, :post_id
|
||||||
|
add_index :skipped_email_logs, :reason_type
|
||||||
|
|
||||||
|
sql = <<~SQL
|
||||||
|
INSERT INTO skipped_email_logs (
|
||||||
|
email_type,
|
||||||
|
to_address,
|
||||||
|
user_id,
|
||||||
|
post_id,
|
||||||
|
reason_type,
|
||||||
|
custom_reason,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
) SELECT
|
||||||
|
email_type,
|
||||||
|
to_address,
|
||||||
|
user_id,
|
||||||
|
post_id,
|
||||||
|
1,
|
||||||
|
skipped_reason,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
FROM email_logs
|
||||||
|
WHERE skipped IS TRUE
|
||||||
|
SQL
|
||||||
|
|
||||||
|
execute(sql)
|
||||||
|
|
||||||
|
Migration::ColumnDropper.mark_readonly('email_logs', 'skipped_reason')
|
||||||
|
end
|
||||||
|
end
|
|
@ -27,8 +27,8 @@ module Email
|
||||||
return if ActionMailer::Base::NullMail === @message
|
return if ActionMailer::Base::NullMail === @message
|
||||||
return if ActionMailer::Base::NullMail === (@message.message rescue nil)
|
return if ActionMailer::Base::NullMail === (@message.message rescue nil)
|
||||||
|
|
||||||
return skip(I18n.t('email_log.message_blank')) if @message.blank?
|
return skip(SkippedEmailLog.reason_types[:sender_message_blank]) if @message.blank?
|
||||||
return skip(I18n.t('email_log.message_to_blank')) if @message.to.blank?
|
return skip(SkippedEmailLog.reason_types[:sender_message_to_blank]) if @message.to.blank?
|
||||||
|
|
||||||
if SiteSetting.disable_emails == "non-staff"
|
if SiteSetting.disable_emails == "non-staff"
|
||||||
user = User.find_by_email(to_address)
|
user = User.find_by_email(to_address)
|
||||||
|
@ -36,9 +36,13 @@ module Email
|
||||||
end
|
end
|
||||||
|
|
||||||
if @message.text_part
|
if @message.text_part
|
||||||
return skip(I18n.t('email_log.text_part_body_blank')) if @message.text_part.body.to_s.blank?
|
if @message.text_part.body.to_s.blank?
|
||||||
|
return skip(SkippedEmailLog.reason_types[:sender_text_part_body_blank])
|
||||||
|
end
|
||||||
else
|
else
|
||||||
return skip(I18n.t('email_log.body_blank')) if @message.body.to_s.blank?
|
if @message.body.to_s.blank?
|
||||||
|
return skip(SkippedEmailLog.reason_types[:sender_body_blank])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@message.charset = 'UTF-8'
|
@message.charset = 'UTF-8'
|
||||||
|
@ -186,7 +190,7 @@ module Email
|
||||||
begin
|
begin
|
||||||
@message.deliver_now
|
@message.deliver_now
|
||||||
rescue *SMTP_CLIENT_ERRORS => e
|
rescue *SMTP_CLIENT_ERRORS => e
|
||||||
return skip(e.message)
|
return skip(SkippedEmailLog.reason_types[:custom], custom_reason: e.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Save and return the email log
|
# Save and return the email log
|
||||||
|
@ -222,14 +226,16 @@ module Email
|
||||||
header.value
|
header.value
|
||||||
end
|
end
|
||||||
|
|
||||||
def skip(reason)
|
def skip(reason_type, custom_reason: nil)
|
||||||
EmailLog.create!(
|
attributes = {
|
||||||
email_type: @email_type,
|
email_type: @email_type,
|
||||||
to_address: to_address,
|
to_address: to_address,
|
||||||
user_id: @user.try(:id),
|
user_id: @user&.id,
|
||||||
skipped: true,
|
reason_type: reason_type
|
||||||
skipped_reason: "[Sender] #{reason}"
|
}
|
||||||
)
|
|
||||||
|
attributes[:custom_reason] = custom_reason if custom_reason
|
||||||
|
SkippedEmailLog.create!(attributes)
|
||||||
end
|
end
|
||||||
|
|
||||||
def merge_json_x_header(name, value)
|
def merge_json_x_header(name, value)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
Fabricator(:skipped_email_log) do
|
||||||
|
to_address { sequence(:address) { |i| "blah#{i}@example.com" } }
|
||||||
|
email_type :invite
|
||||||
|
reason_type SkippedEmailLog.reason_types[:exceeded_emails_limit]
|
||||||
|
end
|
|
@ -7,17 +7,22 @@ describe Jobs::CleanUpEmailLogs do
|
||||||
Fabricate(:email_log, created_at: 2.years.ago)
|
Fabricate(:email_log, created_at: 2.years.ago)
|
||||||
Fabricate(:email_log, created_at: 2.weeks.ago)
|
Fabricate(:email_log, created_at: 2.weeks.ago)
|
||||||
Fabricate(:email_log, created_at: 2.days.ago)
|
Fabricate(:email_log, created_at: 2.days.ago)
|
||||||
|
|
||||||
|
Fabricate(:skipped_email_log, created_at: 2.years.ago)
|
||||||
|
Fabricate(:skipped_email_log)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "removes old email logs without a reply_key" do
|
it "removes old email logs without a reply_key" do
|
||||||
Jobs::CleanUpEmailLogs.new.execute({})
|
Jobs::CleanUpEmailLogs.new.execute({})
|
||||||
expect(EmailLog.count).to eq(3)
|
expect(EmailLog.count).to eq(3)
|
||||||
|
expect(SkippedEmailLog.count).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not remove old email logs when delete_email_logs_after_days is 0" do
|
it "does not remove old email logs when delete_email_logs_after_days is 0" do
|
||||||
SiteSetting.delete_email_logs_after_days = 0
|
SiteSetting.delete_email_logs_after_days = 0
|
||||||
Jobs::CleanUpEmailLogs.new.execute({})
|
Jobs::CleanUpEmailLogs.new.execute({})
|
||||||
expect(EmailLog.count).to eq(4)
|
expect(EmailLog.count).to eq(4)
|
||||||
|
expect(SkippedEmailLog.count).to eq(2)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -129,7 +129,13 @@ describe Jobs::NotifyMailingListSubscribers do
|
||||||
Jobs::NotifyMailingListSubscribers.new.execute(post_id: post.id)
|
Jobs::NotifyMailingListSubscribers.new.execute(post_id: post.id)
|
||||||
UserNotifications.expects(:mailing_list_notify).with(mailing_list_user, post).never
|
UserNotifications.expects(:mailing_list_notify).with(mailing_list_user, post).never
|
||||||
|
|
||||||
expect(EmailLog.where(user: mailing_list_user, skipped: true).count).to eq(1)
|
expect(SkippedEmailLog.exists?(
|
||||||
|
email_type: "mailing_list",
|
||||||
|
user: mailing_list_user,
|
||||||
|
post: post,
|
||||||
|
to_address: mailing_list_user.email,
|
||||||
|
reason_type: SkippedEmailLog.reason_types[:exceeded_emails_limit]
|
||||||
|
)).to eq(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -141,7 +147,13 @@ describe Jobs::NotifyMailingListSubscribers do
|
||||||
Jobs::NotifyMailingListSubscribers.new.execute(post_id: post.id)
|
Jobs::NotifyMailingListSubscribers.new.execute(post_id: post.id)
|
||||||
UserNotifications.expects(:mailing_list_notify).with(mailing_list_user, post).never
|
UserNotifications.expects(:mailing_list_notify).with(mailing_list_user, post).never
|
||||||
|
|
||||||
expect(EmailLog.where(user: mailing_list_user, skipped: true).count).to eq(1)
|
expect(SkippedEmailLog.exists?(
|
||||||
|
email_type: "mailing_list",
|
||||||
|
user: mailing_list_user,
|
||||||
|
post: post,
|
||||||
|
to_address: mailing_list_user.email,
|
||||||
|
reason_type: SkippedEmailLog.reason_types[:exceeded_bounces_limit]
|
||||||
|
)).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,38 +79,46 @@ describe Jobs::UserEmail do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "email_log" do
|
context "email_log" do
|
||||||
|
let(:post) { Fabricate(:post) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
SiteSetting.editing_grace_period = 0
|
SiteSetting.editing_grace_period = 0
|
||||||
Fabricate(:post)
|
post
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates an email log when the mail is sent (via Email::Sender)" do
|
it "creates an email log when the mail is sent (via Email::Sender)" do
|
||||||
last_emailed_at = user.last_emailed_at
|
last_emailed_at = user.last_emailed_at
|
||||||
|
|
||||||
expect { Jobs::UserEmail.new.execute(type: :digest, user_id: user.id) }.to change { EmailLog.count }.by(1)
|
expect do
|
||||||
|
Jobs::UserEmail.new.execute(type: :digest, user_id: user.id,)
|
||||||
|
end.to change { EmailLog.count }.by(1)
|
||||||
|
|
||||||
email_log = EmailLog.last
|
email_log = EmailLog.last
|
||||||
expect(email_log.skipped).to eq(false)
|
|
||||||
expect(email_log.user_id).to eq(user.id)
|
|
||||||
|
|
||||||
|
expect(email_log.user).to eq(user)
|
||||||
|
expect(email_log.post).to eq(nil)
|
||||||
# last_emailed_at should have changed
|
# last_emailed_at should have changed
|
||||||
expect(email_log.user.last_emailed_at).to_not eq(last_emailed_at)
|
expect(email_log.user.last_emailed_at).to_not eq(last_emailed_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates an email log when the mail is skipped" do
|
it "creates a skipped email log when the mail is skipped" do
|
||||||
last_emailed_at = user.last_emailed_at
|
last_emailed_at = user.last_emailed_at
|
||||||
user.update_columns(suspended_till: 1.year.from_now)
|
user.update_columns(suspended_till: 1.year.from_now)
|
||||||
|
|
||||||
expect { Jobs::UserEmail.new.execute(type: :digest, user_id: user.id) }.to change { EmailLog.count }.by(1)
|
expect do
|
||||||
|
Jobs::UserEmail.new.execute(type: :digest, user_id: user.id)
|
||||||
|
end.to change { SkippedEmailLog.count }.by(1)
|
||||||
|
|
||||||
email_log = EmailLog.last
|
expect(SkippedEmailLog.exists?(
|
||||||
expect(email_log.skipped).to eq(true)
|
email_type: "digest",
|
||||||
expect(email_log.skipped_reason).to be_present
|
user: user,
|
||||||
expect(email_log.user_id).to eq(user.id)
|
post: nil,
|
||||||
|
to_address: user.email,
|
||||||
|
reason_type: SkippedEmailLog.reason_types[:user_email_user_suspended_not_pm]
|
||||||
|
)).to eq(true)
|
||||||
|
|
||||||
# last_emailed_at doesn't change
|
# last_emailed_at doesn't change
|
||||||
expect(email_log.user.last_emailed_at).to eq(last_emailed_at)
|
expect(user.last_emailed_at).to eq(last_emailed_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -205,8 +213,15 @@ describe Jobs::UserEmail do
|
||||||
notification_data_hash: notification.data_hash
|
notification_data_hash: notification.data_hash
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(message).to eq nil
|
expect(message).to eq(nil)
|
||||||
expect(err.skipped_reason).to match(/notification.*already/)
|
|
||||||
|
expect(SkippedEmailLog.exists?(
|
||||||
|
email_type: "user_mentioned",
|
||||||
|
user: user,
|
||||||
|
post: post,
|
||||||
|
to_address: user.email,
|
||||||
|
reason_type: SkippedEmailLog.reason_types[:user_email_notification_already_read]
|
||||||
|
)).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does send the email if the notification has been seen but the user is set for email_always" do
|
it "does send the email if the notification has been seen but the user is set for email_always" do
|
||||||
|
@ -230,20 +245,59 @@ describe Jobs::UserEmail do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not send notification if limit is reached" do
|
it "does not send notification if limit is reached" do
|
||||||
Jobs::UserEmail.new.execute(type: :user_mentioned, user_id: user.id, notification_id: notification.id, post_id: post.id)
|
expect do
|
||||||
expect(EmailLog.where(user_id: user.id, skipped: true).count).to eq(1)
|
Jobs::UserEmail.new.execute(
|
||||||
|
type: :user_mentioned,
|
||||||
|
user_id: user.id,
|
||||||
|
notification_id: notification.id,
|
||||||
|
post_id: post.id
|
||||||
|
)
|
||||||
|
end.to change { SkippedEmailLog.count }.by(1)
|
||||||
|
|
||||||
|
expect(SkippedEmailLog.exists?(
|
||||||
|
email_type: "user_mentioned",
|
||||||
|
user: user,
|
||||||
|
post: post,
|
||||||
|
to_address: user.email,
|
||||||
|
reason_type: SkippedEmailLog.reason_types[:exceeded_emails_limit]
|
||||||
|
)).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sends critical email" do
|
it "sends critical email" do
|
||||||
Jobs::UserEmail.new.execute(type: :forgot_password, user_id: user.id, notification_id: notification.id, post_id: post.id)
|
expect do
|
||||||
expect(EmailLog.where(user_id: user.id, skipped: true).count).to eq(0)
|
Jobs::UserEmail.new.execute(
|
||||||
|
type: :forgot_password,
|
||||||
|
user_id: user.id,
|
||||||
|
notification_id: notification.id,
|
||||||
|
)
|
||||||
|
end.to change { EmailLog.count }.by(1)
|
||||||
|
|
||||||
|
expect(EmailLog.exists?(
|
||||||
|
email_type: "forgot_password",
|
||||||
|
user: user,
|
||||||
|
)).to eq(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not send notification if bounce threshold is reached" do
|
it "does not send notification if bounce threshold is reached" do
|
||||||
user.user_stat.update(bounce_score: SiteSetting.bounce_score_threshold)
|
user.user_stat.update(bounce_score: SiteSetting.bounce_score_threshold)
|
||||||
Jobs::UserEmail.new.execute(type: :user_mentioned, user_id: user.id, notification_id: notification.id, post_id: post.id)
|
|
||||||
expect(EmailLog.where(user_id: user.id, skipped: true).count).to eq(1)
|
expect do
|
||||||
|
Jobs::UserEmail.new.execute(
|
||||||
|
type: :user_mentioned,
|
||||||
|
user_id: user.id,
|
||||||
|
notification_id: notification.id,
|
||||||
|
post_id: post.id
|
||||||
|
)
|
||||||
|
end.to change { SkippedEmailLog.count }.by(1)
|
||||||
|
|
||||||
|
expect(SkippedEmailLog.exists?(
|
||||||
|
email_type: "user_mentioned",
|
||||||
|
user: user,
|
||||||
|
post: post,
|
||||||
|
to_address: user.email,
|
||||||
|
reason_type: SkippedEmailLog.reason_types[:exceeded_bounces_limit]
|
||||||
|
)).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't send the mail if the user is using individual mailing list mode" do
|
it "doesn't send the mail if the user is using individual mailing list mode" do
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe SkippedEmailLog, type: :model do
|
||||||
|
let(:custom_skipped_email_log) do
|
||||||
|
Fabricate.build(:skipped_email_log,
|
||||||
|
reason_type: SkippedEmailLog.reason_types[:custom]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:skipped_email_log) { Fabricate.build(:skipped_email_log) }
|
||||||
|
|
||||||
|
describe 'validations' do
|
||||||
|
it { is_expected.to validate_presence_of(:email_type) }
|
||||||
|
it { is_expected.to validate_presence_of(:to_address) }
|
||||||
|
it { is_expected.to validate_presence_of(:reason_type) }
|
||||||
|
|
||||||
|
describe '#reason_type' do
|
||||||
|
describe 'when reason_type is not valid' do
|
||||||
|
it 'should not be valid' do
|
||||||
|
skipped_email_log.reason_type = 999999
|
||||||
|
|
||||||
|
expect(skipped_email_log.valid?).to eq(false)
|
||||||
|
expect(skipped_email_log.errors.messages).to include(:reason_type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#custom_reason' do
|
||||||
|
describe 'when log is a custom reason type' do
|
||||||
|
describe 'when custom reason is blank' do
|
||||||
|
it 'should not be valid' do
|
||||||
|
expect(custom_skipped_email_log.valid?).to eq(false)
|
||||||
|
|
||||||
|
expect(custom_skipped_email_log.errors.messages)
|
||||||
|
.to include(:custom_reason)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when custom reason is not blank' do
|
||||||
|
it 'should be valid' do
|
||||||
|
custom_skipped_email_log.custom_reason = 'test'
|
||||||
|
|
||||||
|
expect(custom_skipped_email_log.valid?).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when log is not a custom reason type' do
|
||||||
|
describe 'when custom reason is blank' do
|
||||||
|
it 'should be valid' do
|
||||||
|
expect(skipped_email_log.valid?).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when custom reason is not blank' do
|
||||||
|
it 'should not be valid' do
|
||||||
|
skipped_email_log.custom_reason = 'test'
|
||||||
|
|
||||||
|
expect(skipped_email_log.valid?).to eq(false)
|
||||||
|
expect(skipped_email_log.errors.messages).to include(:custom_reason)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.reason_types' do
|
||||||
|
describe "verify enum sequence" do
|
||||||
|
it 'should return the right sequence' do
|
||||||
|
expect(SkippedEmailLog.reason_types[:custom]).to eq(1)
|
||||||
|
expect(SkippedEmailLog.reason_types[:user_email_already_read]).to eq(15)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#reason' do
|
||||||
|
describe 'for a custom log' do
|
||||||
|
it 'should return the right output' do
|
||||||
|
custom_skipped_email_log.custom_reason = 'test'
|
||||||
|
expect(custom_skipped_email_log.reason).to eq('test')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'for a non custom log' do
|
||||||
|
it 'should return the right output' do
|
||||||
|
expect(skipped_email_log.reason).to eq("
|
||||||
|
#{I18n.t('skipped_email_log.exceeded_emails_limit')}
|
||||||
|
".strip)
|
||||||
|
|
||||||
|
skipped_email_log.reason_type =
|
||||||
|
SkippedEmailLog.reason_types[:user_email_no_user]
|
||||||
|
|
||||||
|
skipped_email_log.user_id = 9999
|
||||||
|
|
||||||
|
expect(skipped_email_log.reason).to eq("
|
||||||
|
#{I18n.t(
|
||||||
|
'skipped_email_log.user_email_no_user', user_id: 9999
|
||||||
|
)}
|
||||||
|
".strip)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -39,9 +39,34 @@ describe Admin::EmailController do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#skipped' do
|
describe '#skipped' do
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
let!(:log1) { Fabricate(:skipped_email_log, user: user) }
|
||||||
|
let!(:log2) { Fabricate(:skipped_email_log) }
|
||||||
|
|
||||||
it "succeeds" do
|
it "succeeds" do
|
||||||
get "/admin/email/skipped.json"
|
get "/admin/email/skipped.json"
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
logs = JSON.parse(response.body)
|
||||||
|
|
||||||
|
expect(logs.first["id"]).to eq(log2.id)
|
||||||
|
expect(logs.last["id"]).to eq(log1.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when filtered by username' do
|
||||||
|
it 'should return the right response' do
|
||||||
|
get "/admin/email/skipped.json", params: {
|
||||||
|
user: user.username
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
logs = JSON.parse(response.body)
|
||||||
|
|
||||||
|
expect(logs.count).to eq(1)
|
||||||
|
expect(logs.first["id"]).to eq(log1.id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -54,6 +79,7 @@ describe Admin::EmailController do
|
||||||
context 'with an email address' do
|
context 'with an email address' do
|
||||||
it 'enqueues a test email job' do
|
it 'enqueues a test email job' do
|
||||||
post "/admin/email/test.json", params: { email_address: 'eviltrout@test.domain' }
|
post "/admin/email/test.json", params: { email_address: 'eviltrout@test.domain' }
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(ActionMailer::Base.deliveries.map(&:to).flatten).to include('eviltrout@test.domain')
|
expect(ActionMailer::Base.deliveries.map(&:to).flatten).to include('eviltrout@test.domain')
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue