PERF: Move EmailLog#reply_key into new post_reply_keys table.

This commit is contained in:
Guo Xiang Tan
2018-07-18 16:28:44 +08:00
parent ae8b0a517f
commit fad9c2b971
17 changed files with 320 additions and 100 deletions

View File

@@ -17,6 +17,8 @@ module Email
class MessageBuilder
attr_reader :template_args
ALLOW_REPLY_BY_EMAIL_HEADER = 'X-Discourse-Allow-Reply-By-Email'.freeze
def initialize(to, opts = nil)
@to = to
@opts = opts || {}
@@ -147,7 +149,7 @@ module Email
result['X-Auto-Response-Suppress'] = 'All'
if allow_reply_by_email?
result['X-Discourse-Reply-Key'] = reply_key
result[ALLOW_REPLY_BY_EMAIL_HEADER] = true
result['Reply-To'] = reply_by_email_address
else
result['Reply-To'] = from_value
@@ -171,10 +173,6 @@ module Email
protected
def reply_key
@reply_key ||= SecureRandom.hex(16)
end
def allow_reply_by_email?
SiteSetting.reply_by_email_enabled? &&
reply_by_email_address.present? &&
@@ -196,7 +194,6 @@ module Email
return nil unless SiteSetting.reply_by_email_address.present?
@reply_by_email_address = SiteSetting.reply_by_email_address.dup
@reply_by_email_address.gsub!("%{reply_key}", reply_key)
@reply_by_email_address =
if private_reply?

View File

@@ -548,8 +548,8 @@ module Email
if match && match.captures
match.captures.each do |c|
next if c.blank?
email_log = EmailLog.for(c)
return { type: :reply, obj: email_log } if email_log
post_reply_key = PostReplyKey.find_by(reply_key: c)
return { type: :reply, obj: post_reply_key } if post_reply_key
end
end
nil
@@ -580,18 +580,18 @@ module Email
skip_validations: user.staged?)
when :reply
email_log = destination[:obj]
post_reply_key = destination[:obj]
if email_log.user_id != user.id && !forwarded_reply_key?(email_log, user)
raise ReplyUserNotMatchingError, "email_log.user_id => #{email_log.user_id.inspect}, user.id => #{user.id.inspect}"
if post_reply_key.user_id != user.id && !forwarded_reply_key?(post_reply_key, user)
raise ReplyUserNotMatchingError, "post_reply_key.user_id => #{post_reply_key.user_id.inspect}, user.id => #{user.id.inspect}"
end
create_reply(user: user,
raw: body,
elided: elided,
hidden_reason_id: hidden_reason_id,
post: email_log.post,
topic: email_log.post.topic,
post: post_reply_key.post,
topic: post_reply_key.post.topic,
skip_validations: user.staged?)
end
end
@@ -631,11 +631,11 @@ module Email
end
end
def forwarded_reply_key?(email_log, user)
def forwarded_reply_key?(post_reply_key, user)
incoming_emails = IncomingEmail
.joins(:post)
.where('posts.topic_id = ?', email_log.topic.id)
.addressed_to(email_log.reply_key)
.where('posts.topic_id = ?', post_reply_key.post.topic_id)
.addressed_to(post_reply_key.reply_key)
.addressed_to_user(user)
.pluck(:to_addresses, :cc_addresses)
@@ -643,8 +643,8 @@ module Email
next unless contains_email_address_of_user?(to_addresses, user) ||
contains_email_address_of_user?(cc_addresses, user)
return true if contains_reply_by_email_address(to_addresses, email_log.reply_key) ||
contains_reply_by_email_address(cc_addresses, email_log.reply_key)
return true if contains_reply_by_email_address(to_addresses, post_reply_key.reply_key) ||
contains_reply_by_email_address(cc_addresses, post_reply_key.reply_key)
end
false

View File

@@ -31,8 +31,7 @@ module Email
return skip(SkippedEmailLog.reason_types[:sender_message_to_blank]) if @message.to.blank?
if SiteSetting.disable_emails == "non-staff"
user = User.find_by_email(to_address)
return unless user && user.staff?
return unless User.find_by_email(to_address)&.staff?
end
if @message.text_part
@@ -68,15 +67,20 @@ module Email
@message.parts[0].body = @message.parts[0].body.to_s.gsub(/<img src="(\/uploads\/default\/[^"]+)"([^>]*)>/, '![](' + url_prefix + '\1)')
@message.text_part.content_type = 'text/plain; charset=UTF-8'
user_id = @user&.id
# Set up the email log
email_log = EmailLog.new(email_type: @email_type, to_address: to_address, user_id: @user.try(:id))
email_log = EmailLog.new(
email_type: @email_type,
to_address: to_address,
user_id: user_id
)
host = Email::Sender.host_for(Discourse.base_url)
post_id = header_value('X-Discourse-Post-Id')
topic_id = header_value('X-Discourse-Topic-Id')
reply_key = header_value('X-Discourse-Reply-Key')
reply_key = set_reply_key(post_id, user_id)
# always set a default Message ID from the host
@message.header['Message-ID'] = "<#{SecureRandom.uuid}@#{host}>"
@@ -160,12 +164,14 @@ module Email
end
email_log.post_id = post_id if post_id.present?
email_log.reply_key = reply_key if reply_key.present?
# Remove headers we don't need anymore
@message.header['X-Discourse-Topic-Id'] = nil if topic_id.present?
@message.header['X-Discourse-Post-Id'] = nil if post_id.present?
@message.header['X-Discourse-Reply-Key'] = nil if reply_key.present?
if reply_key.present?
@message.header[Email::MessageBuilder::ALLOW_REPLY_BY_EMAIL_HEADER] = nil
end
# pass the original message_id when using mailjet/mandrill/sparkpost
case ActionMailer::Base.smtp_settings[:address]
@@ -251,5 +257,19 @@ module Email
@message.header[name] = data.to_json
end
def set_reply_key(post_id, user_id)
return unless user_id &&
post_id &&
header_value(Email::MessageBuilder::ALLOW_REPLY_BY_EMAIL_HEADER).present?
reply_key = PostReplyKey.find_or_create_by!(
post_id: post_id,
user_id: user_id
).reply_key
@message.header['Reply-To'] =
header_value('Reply-To').gsub!("%{reply_key}", reply_key)
end
end
end