mirror of
https://github.com/discourse/discourse.git
synced 2025-02-16 18:24:52 -06:00
This PR backtracks a fair bit on this one https://github.com/discourse/discourse/pull/13220/files. Instead of sending the group SMTP email for each user via `UserNotifications`, we are changing to send only one email with the existing `Jobs::GroupSmtpEmail` job and `GroupSmtpMailer`. We are changing this job and mailer along with `PostAlerter` to make the first topic allowed user the `to_address` for the email and any other `topic_allowed_users` to be the CC address on the email. This is to cut down on emails sent via SMTP, which is subject to daily limits from providers such as Gmail. We log these details in the `EmailLog` table now. In addition to this, we have changed `PostAlerter` to no longer rely on incoming email email addresses for sending the `GroupSmtpEmail` job. This was unreliable as a user's email could have changed in the meantime. Also it was a little overcomplicated to use the incoming email records -- it is far simpler to reason about to just use topic allowed users. This also adds a fix to include cc_addresses in the EmailLog.addressed_to_user scope.
131 lines
3.3 KiB
Ruby
131 lines
3.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class EmailLog < ActiveRecord::Base
|
|
CRITICAL_EMAIL_TYPES ||= Set.new %w{
|
|
account_created
|
|
admin_login
|
|
confirm_new_email
|
|
confirm_old_email
|
|
confirm_old_email_add
|
|
forgot_password
|
|
notify_old_email
|
|
notify_old_email_add
|
|
signup
|
|
signup_after_approval
|
|
}
|
|
|
|
belongs_to :user
|
|
belongs_to :post
|
|
belongs_to :smtp_group, class_name: 'Group'
|
|
|
|
validates :email_type, :to_address, presence: true
|
|
|
|
scope :bounced, -> { where(bounced: true) }
|
|
|
|
scope :addressed_to_user, ->(user) do
|
|
where(<<~SQL, user_id: user.id)
|
|
EXISTS(
|
|
SELECT 1
|
|
FROM user_emails
|
|
WHERE user_emails.user_id = :user_id AND
|
|
(email_logs.to_address = user_emails.email OR
|
|
email_logs.cc_addresses ILIKE '%' || user_emails.email || '%')
|
|
)
|
|
SQL
|
|
end
|
|
|
|
after_create do
|
|
# Update last_emailed_at if the user_id is present and email was sent
|
|
User.where(id: user_id).update_all("last_emailed_at = CURRENT_TIMESTAMP") if user_id.present?
|
|
end
|
|
|
|
def topic
|
|
@topic ||= self.topic_id.present? ? Topic.find_by(id: self.topic_id) : self.post&.topic
|
|
end
|
|
|
|
def self.unique_email_per_post(post, user)
|
|
return yield unless post && user
|
|
|
|
DistributedMutex.synchronize("email_log_#{post.id}_#{user.id}") do
|
|
if where(post_id: post.id, user_id: user.id).exists?
|
|
nil
|
|
else
|
|
yield
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.reached_max_emails?(user, email_type = nil)
|
|
return false if SiteSetting.max_emails_per_day_per_user == 0 || CRITICAL_EMAIL_TYPES.include?(email_type)
|
|
|
|
count = where('created_at > ?', 1.day.ago)
|
|
.where(user_id: user.id)
|
|
.count
|
|
|
|
count >= SiteSetting.max_emails_per_day_per_user
|
|
end
|
|
|
|
def self.count_per_day(start_date, end_date)
|
|
where("created_at BETWEEN ? AND ?", start_date, end_date)
|
|
.group("DATE(created_at)")
|
|
.order("DATE(created_at)")
|
|
.count
|
|
end
|
|
|
|
def self.for(reply_key)
|
|
self.find_by(reply_key: reply_key)
|
|
end
|
|
|
|
def self.last_sent_email_address
|
|
self.where(email_type: "signup")
|
|
.order(created_at: :desc)
|
|
.limit(1)
|
|
.pluck(:to_address)
|
|
.first
|
|
end
|
|
|
|
def bounce_key
|
|
super&.delete('-')
|
|
end
|
|
|
|
def cc_users
|
|
return [] if !self.cc_user_ids
|
|
@cc_users ||= User.where(id: self.cc_user_ids)
|
|
end
|
|
|
|
def cc_addresses_split
|
|
@cc_addresses_split ||= self.cc_addresses&.split(";") || []
|
|
end
|
|
end
|
|
|
|
# == Schema Information
|
|
#
|
|
# Table name: email_logs
|
|
#
|
|
# id :integer not null, primary key
|
|
# to_address :string not null
|
|
# email_type :string not null
|
|
# user_id :integer
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# post_id :integer
|
|
# bounce_key :uuid
|
|
# bounced :boolean default(FALSE), not null
|
|
# message_id :string
|
|
# smtp_group_id :integer
|
|
# cc_addresses :text
|
|
# cc_user_ids :integer is an Array
|
|
# raw :text
|
|
# topic_id :integer
|
|
#
|
|
# Indexes
|
|
#
|
|
# index_email_logs_on_bounce_key (bounce_key) UNIQUE WHERE (bounce_key IS NOT NULL)
|
|
# index_email_logs_on_bounced (bounced)
|
|
# index_email_logs_on_created_at (created_at)
|
|
# index_email_logs_on_message_id (message_id)
|
|
# index_email_logs_on_post_id (post_id)
|
|
# index_email_logs_on_topic_id (topic_id) WHERE (topic_id IS NOT NULL)
|
|
# index_email_logs_on_user_id (user_id)
|
|
#
|