discourse/app/mailers/user_notifications.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

873 lines
26 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
2013-02-06 03:16:51 +08:00
class UserNotifications < ActionMailer::Base
include UserNotificationsHelper
include ApplicationHelper
helper :application, :email
2013-04-26 14:56:28 +08:00
default charset: "UTF-8"
layout "email_template"
2013-04-26 14:56:28 +08:00
include Email::BuildEmailHelper
2013-02-06 03:16:51 +08:00
def signup(user, opts = {})
build_user_email_token_by_template("user_notifications.signup", user, opts[:email_token])
2013-02-06 03:16:51 +08:00
end
def activation_reminder(user, opts = {})
build_user_email_token_by_template(
"user_notifications.activation_reminder",
user,
opts[:email_token],
)
end
def signup_after_approval(user, opts = {})
locale = user_locale(user)
tips =
I18n.t(
"system_messages.usage_tips.text_body_template",
base_url: Discourse.base_url,
locale: locale,
)
build_email(
user.email,
template: "user_notifications.signup_after_approval",
locale: locale,
new_user_tips: tips,
)
end
def post_approved(user, opts = {})
post_url = opts.dig(:notification_data_hash, :post_url)
return if post_url.nil?
locale = user_locale(user)
build_email(
user.email,
template: "user_notifications.post_approved",
locale: locale,
base_url: Discourse.base_url,
post_url: post_url,
)
end
def signup_after_reject(user, opts = {})
locale = user_locale(user)
build_email(
user.email,
template: "user_notifications.signup_after_reject",
locale: locale,
reject_reason: opts[:reject_reason],
)
end
def suspicious_login(user, opts = {})
ipinfo = DiscourseIpInfo.get(opts[:client_ip])
location = ipinfo[:location]
browser = BrowserDetection.browser(opts[:user_agent])
device = BrowserDetection.device(opts[:user_agent])
os = BrowserDetection.os(opts[:user_agent])
build_email(
user.email,
template: "user_notifications.suspicious_login",
locale: user_locale(user),
client_ip: opts[:client_ip],
location: location.present? ? location : I18n.t("staff_action_logs.unknown"),
browser: I18n.t("user_auth_tokens.browser.#{browser}"),
device: I18n.t("user_auth_tokens.device.#{device}"),
os: I18n.t("user_auth_tokens.os.#{os}"),
)
end
def notify_old_email(user, opts = {})
build_email(
user.email,
template: "user_notifications.notify_old_email",
locale: user_locale(user),
new_email: opts[:new_email],
)
end
def notify_old_email_add(user, opts = {})
build_email(
user.email,
template: "user_notifications.notify_old_email_add",
locale: user_locale(user),
new_email: opts[:new_email],
)
end
def confirm_old_email(user, opts = {})
build_user_email_token_by_template(
"user_notifications.confirm_old_email",
user,
opts[:email_token],
)
end
def confirm_old_email_add(user, opts = {})
build_user_email_token_by_template(
"user_notifications.confirm_old_email_add",
user,
opts[:email_token],
)
end
def confirm_new_email(user, opts = {})
build_user_email_token_by_template(
(
if opts[:requested_by_admin]
"user_notifications.confirm_new_email_via_admin"
else
"user_notifications.confirm_new_email"
end
),
user,
opts[:email_token],
)
2013-02-06 03:16:51 +08:00
end
def forgot_password(user, opts = {})
build_user_email_token_by_template(
user.has_password? ? "user_notifications.forgot_password" : "user_notifications.set_password",
user,
opts[:email_token],
)
end
def email_login(user, opts = {})
build_user_email_token_by_template("user_notifications.email_login", user, opts[:email_token])
2013-02-06 03:16:51 +08:00
end
def admin_login(user, opts = {})
build_user_email_token_by_template("user_notifications.admin_login", user, opts[:email_token])
end
2013-02-06 03:16:51 +08:00
def account_created(user, opts = {})
build_user_email_token_by_template(
"user_notifications.account_created",
user,
opts[:email_token],
)
end
def account_silenced(user, opts = nil)
opts ||= {}
return unless user_history = opts[:user_history]
if user.silenced_forever?
build_email(
user.email,
template: "user_notifications.account_silenced_forever",
locale: user_locale(user),
reason: user_history.details,
)
else
silenced_till = user.silenced_till.in_time_zone(user.user_option.timezone)
build_email(
user.email,
template: "user_notifications.account_silenced",
locale: user_locale(user),
reason: user_history.details,
silenced_till: I18n.l(silenced_till, format: :long),
)
end
end
def account_suspended(user, opts = nil)
opts ||= {}
return unless user_history = opts[:user_history]
if user.suspended_forever?
build_email(
user.email,
template: "user_notifications.account_suspended_forever",
locale: user_locale(user),
reason: user_history.details,
)
else
suspended_till = user.suspended_till.in_time_zone(user.user_option.timezone)
build_email(
user.email,
template: "user_notifications.account_suspended",
locale: user_locale(user),
reason: user_history.details,
suspended_till: I18n.l(suspended_till, format: :long),
)
end
end
def account_exists(user, opts = {})
build_email(
user.email,
template: "user_notifications.account_exists",
locale: user_locale(user),
email: user.email,
)
end
def account_second_factor_disabled(user, opts = {})
build_email(
user.email,
template: "user_notifications.account_second_factor_disabled",
locale: user_locale(user),
email: user.email,
)
end
def digest(user, opts = {})
build_summary_for(user)
@unsubscribe_key = UnsubscribeKey.create_key_for(@user, UnsubscribeKey::DIGEST_TYPE)
min_date = opts[:since] || user.last_emailed_at || user.last_seen_at || 1.month.ago
2013-02-06 03:16:51 +08:00
# Fetch some topics and posts to show
digest_opts = {
limit: SiteSetting.digest_topics + SiteSetting.digest_other_topics,
top_order: true,
}
topics_for_digest = Topic.for_digest(user, min_date, digest_opts).to_a
if topics_for_digest.empty? && !user.user_option.try(:include_tl0_in_digests)
# Find some topics from new users that are at least 24 hours old
topics_for_digest =
Topic
.for_digest(user, min_date, digest_opts.merge(include_tl0: true))
.where("topics.created_at < ?", 24.hours.ago)
.to_a
end
@popular_topics = topics_for_digest[0, SiteSetting.digest_topics]
if @popular_topics.present?
@other_new_for_you =
(
if topics_for_digest.size > SiteSetting.digest_topics
topics_for_digest[SiteSetting.digest_topics..-1]
else
[]
end
)
@popular_posts =
if SiteSetting.digest_posts > 0
Post
.order("posts.score DESC")
.for_mailing_list(user, min_date)
.where("posts.post_type = ?", Post.types[:regular])
.where(
"posts.deleted_at IS NULL AND posts.hidden = false AND posts.user_deleted = false",
)
.where(
"posts.post_number > ? AND posts.score > ?",
1,
ScoreCalculator.default_score_weights[:like_score] * 5.0,
)
.where("posts.created_at < ?", (SiteSetting.editing_grace_period || 0).seconds.ago)
.limit(SiteSetting.digest_posts)
else
[]
end
@excerpts = {}
@popular_topics.map do |t|
@excerpts[t.first_post.id] = email_excerpt(
t.first_post.cooked,
t.first_post,
) if t.first_post.present?
end
# Try to find 3 interesting stats for the top of the digest
2019-04-04 14:19:39 +08:00
new_topics_count = Topic.for_digest(user, min_date).count
if new_topics_count == 0
# We used topics from new users instead, so count should match
new_topics_count = topics_for_digest.size
end
@counts = [
{
id: "new_topics",
label_key: "user_notifications.digest.new_topics",
value: new_topics_count,
href: "#{Discourse.base_url}/new",
},
]
# totalling unread notifications (which are low-priority only) and unread
# PMs and bookmark reminder notifications, so the total is both unread low
# and high priority PMs
value = user.unread_notifications + user.unread_high_priority_notifications
if value > 0
@counts << {
id: "unread_notifications",
label_key: "user_notifications.digest.unread_notifications",
value: value,
href: "#{Discourse.base_url}/my/notifications",
}
end
if @counts.size < 3
value = user.unread_notifications_of_type(Notification.types[:liked], since: min_date)
if value > 0
@counts << {
id: "likes_received",
label_key: "user_notifications.digest.liked_received",
value: value,
href: "#{Discourse.base_url}/my/notifications",
}
end
end
if @counts.size < 3 && user.user_option.digest_after_minutes.to_i >= 1440
value = summary_new_users_count(min_date)
if value > 0
@counts << {
id: "new_users",
label_key: "user_notifications.digest.new_users",
value: value,
href: "#{Discourse.base_url}/about",
}
end
end
@last_seen_at = short_date(user.last_seen_at || user.created_at)
@preheader_text = I18n.t("user_notifications.digest.preheader", last_seen_at: @last_seen_at)
opts = {
from_alias: I18n.t("user_notifications.digest.from", site_name: Email.site_title),
2017-03-21 21:11:15 +08:00
subject:
I18n.t(
"user_notifications.digest.subject_template",
email_prefix: @email_prefix,
date: short_date(Time.now),
),
add_unsubscribe_link: true,
unsubscribe_url: "#{Discourse.base_url}/email/unsubscribe/#{@unsubscribe_key}",
}
build_email(user.email, opts)
2013-02-06 03:16:51 +08:00
end
end
2013-02-07 23:45:24 +08:00
def user_replied(user, opts)
opts[:allow_reply_by_email] = true
opts[:use_site_subject] = true
opts[:show_category_in_subject] = true
opts[:show_tags_in_subject] = true
notification_email(user, opts)
end
def user_quoted(user, opts)
opts[:allow_reply_by_email] = true
opts[:use_site_subject] = true
opts[:show_category_in_subject] = true
opts[:show_tags_in_subject] = true
notification_email(user, opts)
end
def user_linked(user, opts)
opts[:allow_reply_by_email] = true
opts[:use_site_subject] = true
opts[:show_category_in_subject] = true
opts[:show_tags_in_subject] = true
notification_email(user, opts)
end
def user_mentioned(user, opts)
opts[:allow_reply_by_email] = true
opts[:use_site_subject] = true
opts[:show_category_in_subject] = true
opts[:show_tags_in_subject] = true
notification_email(user, opts)
end
def group_mentioned(user, opts)
opts[:allow_reply_by_email] = true
opts[:use_site_subject] = true
opts[:show_category_in_subject] = true
opts[:show_tags_in_subject] = true
notification_email(user, opts)
end
def user_posted(user, opts)
opts[:allow_reply_by_email] = true
opts[:use_site_subject] = true
opts[:add_re_to_subject] = true
opts[:show_category_in_subject] = true
opts[:show_tags_in_subject] = true
notification_email(user, opts)
end
def user_private_message(user, opts)
opts[:allow_reply_by_email] = true
opts[:use_site_subject] = true
opts[:add_re_to_subject] = true
opts[:show_category_in_subject] = false
opts[:show_tags_in_subject] = false
opts[:show_group_in_subject] = true if SiteSetting.group_in_subject
# We use the 'user_posted' event when you are emailed a post in a PM.
opts[:notification_type] = "posted"
notification_email(user, opts)
end
def user_invited_to_private_message(user, opts)
opts[:allow_reply_by_email] = false
opts[:use_invite_template] = true
notification_email(user, opts)
end
def user_invited_to_topic(user, opts)
opts[:allow_reply_by_email] = false
opts[:use_invite_template] = true
opts[:show_category_in_subject] = true
opts[:show_tags_in_subject] = true
notification_email(user, opts)
end
2016-07-08 00:23:19 +08:00
def user_watching_first_post(user, opts)
user_posted(user, opts)
end
def mailing_list_notify(user, post)
opts = {
post: post,
allow_reply_by_email: true,
use_site_subject: true,
add_re_to_subject: true,
show_category_in_subject: true,
show_tags_in_subject: true,
notification_type: "posted",
notification_data_hash: {
original_username: post.user.username,
topic_title: post.topic.title,
},
}
notification_email(user, opts)
end
protected
2016-02-10 07:54:13 +08:00
def user_locale(user)
user.effective_locale
2016-02-10 07:54:13 +08:00
end
def email_post_markdown(post, add_posted_by = false)
FEATURE: Allow email image embed with secure media (#10563) This PR introduces a few important changes to secure media redaction in emails. First of all, two new site settings have been introduced: * `secure_media_allow_embed_images_in_emails`: If enabled we will embed secure images in emails instead of redacting them. * `secure_media_max_email_embed_image_size_kb`: The cap to the size of the secure image we will embed, defaulting to 1mb, so the email does not become too big. Max is 10mb. Works in tandem with `email_total_attachment_size_limit_kb`. `Email::Sender` will now attach images to the email based on these settings. The sender will also call `inline_secure_images` in `Email::Styles` after secure media is redacted and attachments are added to replace redaction messages with attached images. I went with attachment and `cid` URLs because base64 image support is _still_ flaky in email clients. All redaction of secure media is now handled in `Email::Styles` and calls out to `PrettyText.strip_secure_media` to do the actual stripping and replacing with placeholders. `app/mailers/group_smtp_mailer.rb` and `app/mailers/user_notifications.rb` no longer do any stripping because they are earlier in the pipeline than `Email::Styles`. Finally the redaction notice has been restyled and includes a link to the media that the user can click, which will show it to them if they have the necessary permissions. ![image](https://user-images.githubusercontent.com/920448/92341012-b9a2c380-f0ff-11ea-860e-b376b4528357.png)
2020-09-10 07:50:16 +08:00
result = +"#{post.raw}\n\n"
if add_posted_by
result << "#{I18n.t("user_notifications.posted_by", username: post.username, post_date: post.created_at.strftime("%m/%d/%Y"))}\n\n"
end
result
end
def self.get_context_posts(post, topic_user, user)
if (user.user_option.email_previous_replies == UserOption.previous_replies_type[:never]) ||
SiteSetting.private_email?
return []
end
allowed_post_types = [Post.types[:regular]]
allowed_post_types << Post.types[:whisper] if topic_user.try(:user).try(:staff?)
context_posts =
Post
.where(topic_id: post.topic_id)
.where("post_number < ?", post.post_number)
.where(user_deleted: false)
.where(hidden: false)
.where(post_type: allowed_post_types)
.order("created_at desc")
.limit(SiteSetting.email_posts_context)
if topic_user && topic_user.last_emailed_post_number &&
user.user_option.email_previous_replies ==
UserOption.previous_replies_type[:unless_emailed]
context_posts = context_posts.where("post_number > ?", topic_user.last_emailed_post_number)
end
context_posts
end
def notification_email(user, opts)
notification_type = opts[:notification_type]
notification_data = opts[:notification_data_hash]
post = opts[:post]
2013-02-06 03:16:51 +08:00
unless String === notification_type
notification_type = Notification.types[notification_type] if Numeric === notification_type
notification_type = notification_type.to_s
end
user_name = notification_data[:original_username]
if post && SiteSetting.enable_names && SiteSetting.display_name_on_email_from
name = User.where(id: notification_data[:original_user_id] || post.user_id).pick(:name)
user_name = name unless name.blank?
2014-10-21 22:06:55 +08:00
end
allow_reply_by_email = opts[:allow_reply_by_email] unless user.suspended?
original_username =
notification_data[:original_username] || notification_data[:display_username]
if user.staged && post
original_subject =
IncomingEmail
.joins(:post)
.where("posts.topic_id = ? AND posts.post_number = 1", post.topic_id)
.pluck(:subject)
.first
end
if original_subject
topic_title = original_subject
opts[:use_site_subject] = false
opts[:add_re_to_subject] = true
use_topic_title_subject = true
else
topic_title = notification_data[:topic_title]
use_topic_title_subject = false
end
email_options = {
title: topic_title,
post: post,
username: original_username,
from_alias: I18n.t("email_from", user_name: user_name, site_name: Email.site_title),
allow_reply_by_email: allow_reply_by_email,
use_site_subject: opts[:use_site_subject],
add_re_to_subject: opts[:add_re_to_subject],
show_category_in_subject: opts[:show_category_in_subject],
show_tags_in_subject: opts[:show_tags_in_subject],
show_group_in_subject: opts[:show_group_in_subject],
notification_type: notification_type,
use_invite_template: opts[:use_invite_template],
use_topic_title_subject: use_topic_title_subject,
user: user,
}
if group_id = notification_data[:group_id]
email_options[:group_name] = Group.find_by(id: group_id)&.name
end
send_notification_email(email_options)
end
def send_notification_email(opts)
post = opts[:post]
title = opts[:title]
allow_reply_by_email = opts[:allow_reply_by_email]
use_site_subject = opts[:use_site_subject]
add_re_to_subject = opts[:add_re_to_subject] && post.post_number > 1
use_topic_title_subject = opts[:use_topic_title_subject]
2014-10-21 22:06:55 +08:00
username = opts[:username]
from_alias = opts[:from_alias]
notification_type = opts[:notification_type]
user = opts[:user]
group_name = opts[:group_name]
2016-02-10 07:54:13 +08:00
locale = user_locale(user)
template = +"user_notifications.user_#{notification_type}"
if post.topic.private_message?
template << "_pm"
if group_name
template << "_group"
elsif user.staged
template << "_staged"
end
end
# category name
category = Topic.find_by(id: post.topic_id)&.category
if opts[:show_category_in_subject] && post.topic_id && category && !category.uncategorized?
show_category_in_subject = category.name
# subcategory case
if !category.parent_category_id.nil?
show_category_in_subject =
"#{Category.where(id: category.parent_category_id).pick(:name)}/#{show_category_in_subject}"
end
else
show_category_in_subject = nil
end
# tag names
if opts[:show_tags_in_subject] && post.topic_id
max_tags =
if SiteSetting.enable_max_tags_per_email_subject
SiteSetting.max_tags_per_email_subject
else
SiteSetting.max_tags_per_topic
end
tags =
DiscourseTagging
.visible_tags(Guardian.new(user))
.joins(:topic_tags)
.where("topic_tags.topic_id = ?", post.topic_id)
.order("tags.public_topic_count DESC", "tags.name ASC")
.limit(max_tags)
.pluck(:name)
show_tags_in_subject = tags.any? ? tags.join(" ") : nil
end
FEATURE: Use group SMTP settings for sending user notification emails (initial) (#13220) This PR changes the `UserNotification` class to send outbound `user_private_message` using the group's SMTP settings, but only if: * The first allowed_group on the topic has SMTP configured and enabled * SiteSetting.enable_smtp is true * The group does not have IMAP enabled, if this is enabled the `GroupSMTPMailer` handles things The email is sent using the group's `email_username` as both the `from` and `reply-to` address, so when the user replies from their email it will go through the group's SMTP inbox, which needs to have email forwarding set up to send the message on to a location (such as a hosted site email address like meta@discoursemail.com) where it can be POSTed into discourse's handle_mail route. Also includes a fix to `EmailReceiver#group_incoming_emails_regex` to include the `group.email_username` so the group does not get a staged user created and invited to the topic (which was a problem for IMAP), as well as updating `Group.find_by_email` to find using the `email_username` as well for inbound emails with that as the TO address. #### Note This is safe to merge without impacting anyone seriously. If people had SMTP enabled for a group they would have IMAP enabled too currently, and that is a very small amount of users because IMAP is an alpha product, and also because the UserNotification change has a guard to make sure it is not used if IMAP is enabled for the group. The existing IMAP tests work, and I tested this functionality by manually POSTing replies to the SMTP address into my local discourse. There will probably be more work needed on this, but it needs to be tested further in a real hosted environment to continue.
2021-06-03 12:47:32 +08:00
group = post.topic.allowed_groups&.first
if post.topic.private_message?
subject_pm =
FEATURE: Use group SMTP settings for sending user notification emails (initial) (#13220) This PR changes the `UserNotification` class to send outbound `user_private_message` using the group's SMTP settings, but only if: * The first allowed_group on the topic has SMTP configured and enabled * SiteSetting.enable_smtp is true * The group does not have IMAP enabled, if this is enabled the `GroupSMTPMailer` handles things The email is sent using the group's `email_username` as both the `from` and `reply-to` address, so when the user replies from their email it will go through the group's SMTP inbox, which needs to have email forwarding set up to send the message on to a location (such as a hosted site email address like meta@discoursemail.com) where it can be POSTed into discourse's handle_mail route. Also includes a fix to `EmailReceiver#group_incoming_emails_regex` to include the `group.email_username` so the group does not get a staged user created and invited to the topic (which was a problem for IMAP), as well as updating `Group.find_by_email` to find using the `email_username` as well for inbound emails with that as the TO address. #### Note This is safe to merge without impacting anyone seriously. If people had SMTP enabled for a group they would have IMAP enabled too currently, and that is a very small amount of users because IMAP is an alpha product, and also because the UserNotification change has a guard to make sure it is not used if IMAP is enabled for the group. The existing IMAP tests work, and I tested this functionality by manually POSTing replies to the SMTP address into my local discourse. There will probably be more work needed on this, but it needs to be tested further in a real hosted environment to continue.
2021-06-03 12:47:32 +08:00
if opts[:show_group_in_subject] && group.present?
if group.full_name
"[#{group.full_name}] "
else
"[#{group.name}] "
end
else
I18n.t("subject_pm")
end
participants = self.class.participants(post, user)
end
if SiteSetting.private_email?
title = I18n.t("system_messages.private_topic_title", id: post.topic_id)
end
2019-05-13 14:31:20 +08:00
context = +""
tu = TopicUser.get(post.topic_id, user)
context_posts = self.class.get_context_posts(post, tu, user)
# make .present? cheaper
context_posts = context_posts.to_a
if context_posts.present?
context << +"-- \n*#{I18n.t("user_notifications.previous_discussion")}*\n"
context_posts.each { |cp| context << email_post_markdown(cp, true) }
end
translation_override_exists =
TranslationOverride.where(
locale: SiteSetting.default_locale,
translation_key: "#{template}.text_body_template",
).exists?
if opts[:use_invite_template]
invite_template = +"user_notifications.invited"
invite_template << "_group" if group_name
invite_template << if post.topic.private_message?
"_to_private_message_body"
else
"_to_topic_body"
end
topic_excerpt = post.excerpt.tr("\n", " ") if post.is_first_post? && post.excerpt
topic_url = post.topic&.url
if SiteSetting.private_email?
topic_excerpt = ""
topic_url = ""
end
message =
I18n.t(
invite_template,
username: username,
group_name: group_name,
topic_title: gsub_emoji_to_unicode(title),
topic_excerpt: topic_excerpt,
site_title: SiteSetting.title,
site_description: SiteSetting.site_description,
topic_url: topic_url,
)
html = PrettyText.cook(message, sanitize: false).html_safe
else
reached_limit = SiteSetting.max_emails_per_day_per_user > 0
reached_limit &&=
(EmailLog.where(user_id: user.id).where("created_at > ?", 1.day.ago).count) >=
(SiteSetting.max_emails_per_day_per_user - 1)
in_reply_to_post = post.reply_to_post if user.user_option.email_in_reply_to
if SiteSetting.private_email?
message = I18n.t("system_messages.contents_hidden")
else
message =
email_post_markdown(post) +
(
if reached_limit
"\n\n#{I18n.t "user_notifications.reached_limit", count: SiteSetting.max_emails_per_day_per_user}"
else
""
end
)
end
first_footer_classes = "highlight"
2018-06-12 06:54:39 +08:00
if (allow_reply_by_email && user.staged) || (user.suspended? || user.staged?)
first_footer_classes = ""
end
unless translation_override_exists
html =
UserNotificationRenderer.render(
template: "email/notification",
format: :html,
locals: {
context_posts: context_posts,
reached_limit: reached_limit,
post: post,
in_reply_to_post: in_reply_to_post,
2018-06-12 06:54:39 +08:00
classes: Rtl.new(user).css_class,
first_footer_classes: first_footer_classes,
reply_above_line: false,
},
)
end
end
2013-02-28 07:30:14 +08:00
email_opts = {
2017-07-22 02:24:28 +08:00
topic_title: Emoji.gsub_emoji_to_unicode(title),
topic_title_url_encoded: title ? UrlHelper.encode_component(title) : title,
message: message,
url: post.url(without_slug: SiteSetting.private_email?),
post_id: post.id,
topic_id: post.topic_id,
context: context,
2014-10-21 22:06:55 +08:00
username: username,
group_name: group_name,
add_unsubscribe_link: !user.staged,
mailing_list_mode: user.user_option.mailing_list_mode,
unsubscribe_url: post.unsubscribe_url(user),
allow_reply_by_email: allow_reply_by_email,
only_reply_by_email: allow_reply_by_email && user.staged,
use_site_subject: use_site_subject,
add_re_to_subject: add_re_to_subject,
show_category_in_subject: show_category_in_subject,
show_tags_in_subject: show_tags_in_subject,
private_reply: post.topic.private_message?,
subject_pm: subject_pm,
participants: participants,
include_respond_instructions: !(user.suspended? || user.staged?),
template: template,
use_topic_title_subject: use_topic_title_subject,
site_description: SiteSetting.site_description,
site_title: SiteSetting.title,
site_title_url_encoded: UrlHelper.encode_component(SiteSetting.title),
locale: locale,
2013-02-28 07:30:14 +08:00
}
email_opts[:html_override] = html unless translation_override_exists
2013-02-28 07:30:14 +08:00
# If we have a display name, change the from address
email_opts[:from_alias] = from_alias if from_alias.present?
2013-02-28 07:30:14 +08:00
TopicUser.change(user.id, post.topic_id, last_emailed_post_number: post.post_number)
build_email(user.email, email_opts)
2013-02-07 23:45:24 +08:00
end
def self.participants(post, recipient_user, reveal_staged_email: false)
list = []
allowed_groups = post.topic.allowed_groups.order("user_count DESC")
allowed_groups.each do |g|
list.push("[#{g.name_full_preferred} (#{g.user_count})](#{g.full_url})")
break if list.size >= SiteSetting.max_participant_names
end
recent_posts_query =
post
.topic
.posts
.select("user_id, MAX(post_number) AS post_number")
.where(post_type: Post.types[:regular], post_number: ..post.post_number)
.where.not(user_id: recipient_user.id)
.group(:user_id)
.order("post_number DESC")
.limit(SiteSetting.max_participant_names)
.to_sql
allowed_users =
post
.topic
.allowed_users
.joins("LEFT JOIN (#{recent_posts_query}) pu ON topic_allowed_users.user_id = pu.user_id")
.order("post_number DESC NULLS LAST", :id)
.where.not(id: recipient_user.id)
.human_users
allowed_users.each do |u|
break if list.size >= SiteSetting.max_participant_names
if reveal_staged_email && u.staged?
list.push("#{u.email}")
else
list.push("[#{u.display_name}](#{u.full_url})")
end
end
participants = list.join(I18n.t("word_connector.comma"))
others_count = allowed_groups.size + allowed_users.size - list.size
if others_count > 0
I18n.t(
"user_notifications.more_pm_participants",
participants: participants,
count: others_count,
)
else
participants
end
end
private
def build_user_email_token_by_template(template, user, email_token)
build_email(user.email, template: template, locale: user_locale(user), email_token: email_token)
end
def build_summary_for(user)
@site_name = SiteSetting.email_prefix.presence || SiteSetting.title # used by I18n
@user = user
@date = short_date(Time.now)
@base_url = Discourse.base_url
2017-03-21 21:11:15 +08:00
@email_prefix = SiteSetting.email_prefix.presence || SiteSetting.title
@header_color = ColorScheme.hex_for_name("header_primary")
@header_bgcolor = ColorScheme.hex_for_name("header_background")
@anchor_color = ColorScheme.hex_for_name("tertiary")
@markdown_linker = MarkdownLinker.new(@base_url)
@disable_email_custom_styles = !SiteSetting.apply_custom_styles_to_digest
end
def self.summary_new_users_count_key(min_date_str)
"summary-new-users:#{min_date_str}"
end
def summary_new_users_count(min_date)
min_date_str = min_date.is_a?(String) ? min_date : min_date.strftime("%Y-%m-%d")
key = self.class.summary_new_users_count_key(min_date_str)
((count = Discourse.redis.get(key)) && count.to_i) ||
begin
count =
User
.real
.where(active: true, staged: false)
.not_suspended
.where("created_at > ?", min_date_str)
.count
Discourse.redis.setex(key, 1.day, count)
count
end
end
2013-02-06 03:16:51 +08:00
end