discourse/app/models/email_log.rb
Martin Brennan 5222247746
FEATURE: Add more columns to outbound EmailLog (#13449)
This adds the following columns to EmailLog:

* cc_addresses
* cc_user_ids
* topic_id
* raw

This is to bring the EmailLog table closer in parity to
IncomingEmail so it can be better utilized for Group SMTP
and IMAP mailing.

The raw column contains the full content of the outbound email,
but _only_ if the new hidden site setting
enable_raw_outbound_email_logging is enabled. Most sites do not
need it, and it's mostly required for IMAP and SMTP sending.

In the next pull request, there will be a migration to backfill
topic_id on the EmailLog table, at which point we can remove the
topic fallback method on EmailLog.
2021-06-22 08:32:01 +10:00

130 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
)
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)
#