discourse/app/services/group_message.rb
Régis Hanol 0e9451e93f
FIX: crawler view with unicode usernames (#27051)
When "unicode_usernames" is enabled, calling the "user_path" helper with a username containing some non ASCII character will break due to the route constraint we have on username.

This fixes the issue by always encoding the username before passing it to the "user_path" helper.

Internal ref - t/127547
2024-05-16 17:11:24 +02:00

106 lines
3.1 KiB
Ruby

# frozen_string_literal: true
# GroupMessage sends a private message to a group.
# It will also avoid sending the same message repeatedly, which can happen with
# notifications to moderators when spam is detected.
#
# Options:
#
# user: (User) If the message is about a user, pass the user object.
# limit_once_per: (seconds) Limit sending the given type of message once every X seconds.
# The default is 24 hours. Set to false to always send the message.
class GroupMessage
include Rails.application.routes.url_helpers
RECENT_MESSAGE_PERIOD = 3.months
def self.create(group_name, message_type, opts = {})
GroupMessage.new(group_name, message_type, opts).create
end
def initialize(group_name, message_type, opts = {})
@group_name = group_name
@message_type = message_type
@opts = opts
end
def create
return false if sent_recently?
post =
PostCreator.create(
Discourse.system_user,
target_group_names: [@group_name],
archetype: Archetype.private_message,
subtype: TopicSubtype.system_message,
title: I18n.t("system_messages.#{@message_type}.subject_template", message_params),
raw: I18n.t("system_messages.#{@message_type}.text_body_template", message_params),
)
remember_message_sent
post
end
def delete_previous!(respect_sent_recently: true, match_raw: true)
return false if respect_sent_recently && sent_recently?
posts =
Post
.joins(topic: { topic_allowed_groups: :group })
.where(
topic: {
posts_count: 1,
user_id: Discourse.system_user,
archetype: Archetype.private_message,
subtype: TopicSubtype.system_message,
title: I18n.t("system_messages.#{@message_type}.subject_template", message_params),
topic_allowed_groups: {
groups: {
name: @group_name,
},
},
},
)
.where("posts.created_at > ?", RECENT_MESSAGE_PERIOD.ago)
if match_raw
posts =
posts.where(
raw: I18n.t("system_messages.#{@message_type}.text_body_template", message_params).rstrip,
)
end
posts.find_each { |post| PostDestroyer.new(Discourse.system_user, post).destroy }
end
def message_params
@message_params ||=
begin
h = { base_url: Discourse.base_url }.merge(@opts[:message_params] || {})
if @opts[:user]
h.merge!(
username: @opts[:user].username,
user_url: user_path(@opts[:user].encoded_username(lower: true)),
)
end
h
end
end
def sent_recently?
return false if @opts[:limit_once_per] == false
Discourse.redis.get(sent_recently_key).present?
end
# default is to send no more than once every 24 hours (24 * 60 * 60 = 86,400 seconds)
def remember_message_sent
unless @opts[:limit_once_per] == false
Discourse.redis.setex(sent_recently_key, @opts[:limit_once_per].try(:to_i) || 86_400, 1)
end
end
def sent_recently_key
"grpmsg:#{@group_name}:#{@message_type}:#{@opts[:user] ? @opts[:user].username : ""}"
end
end