mirror of
https://github.com/discourse/discourse.git
synced 2025-04-09 15:30:48 +08:00
DEV: Remove hash-like access from service contracts
We decided to keep only one way to access values from a contract. This patch thus removes the hash-like access from contracts.
This commit is contained in:
parent
4d0ed2e146
commit
2f334964f2
@ -4,6 +4,11 @@ class AdminNotices::Dismiss
|
|||||||
include Service::Base
|
include Service::Base
|
||||||
|
|
||||||
policy :invalid_access
|
policy :invalid_access
|
||||||
|
params do
|
||||||
|
attribute :id, :integer
|
||||||
|
|
||||||
|
validates :id, presence: true
|
||||||
|
end
|
||||||
model :admin_notice, optional: true
|
model :admin_notice, optional: true
|
||||||
transaction do
|
transaction do
|
||||||
step :destroy
|
step :destroy
|
||||||
@ -17,7 +22,7 @@ class AdminNotices::Dismiss
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_admin_notice(params:)
|
def fetch_admin_notice(params:)
|
||||||
AdminNotice.find_by(id: params[:id])
|
AdminNotice.find_by(id: params.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy(admin_notice:)
|
def destroy(admin_notice:)
|
||||||
|
@ -18,13 +18,13 @@ class Experiments::Toggle
|
|||||||
end
|
end
|
||||||
|
|
||||||
def setting_is_available(params:)
|
def setting_is_available(params:)
|
||||||
SiteSetting.respond_to?(params[:setting_name])
|
SiteSetting.respond_to?(params.setting_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def toggle(params:, guardian:)
|
def toggle(params:, guardian:)
|
||||||
SiteSetting.set_and_log(
|
SiteSetting.set_and_log(
|
||||||
params[:setting_name],
|
params.setting_name,
|
||||||
!SiteSetting.public_send(params[:setting_name]),
|
!SiteSetting.public_send(params.setting_name),
|
||||||
guardian.user,
|
guardian.user,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -32,7 +32,7 @@ class Flags::CreateFlag
|
|||||||
end
|
end
|
||||||
|
|
||||||
def unique_name(params:)
|
def unique_name(params:)
|
||||||
!Flag.custom.where(name: params[:name]).exists?
|
!Flag.custom.where(name: params.name).exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
def instantiate_flag(params:)
|
def instantiate_flag(params:)
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
class Flags::DestroyFlag
|
class Flags::DestroyFlag
|
||||||
include Service::Base
|
include Service::Base
|
||||||
|
|
||||||
|
params do
|
||||||
|
attribute :id, :integer
|
||||||
|
|
||||||
|
validates :id, presence: true
|
||||||
|
end
|
||||||
model :flag
|
model :flag
|
||||||
policy :not_system
|
policy :not_system
|
||||||
policy :not_used
|
policy :not_used
|
||||||
@ -15,7 +20,7 @@ class Flags::DestroyFlag
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_flag(params:)
|
def fetch_flag(params:)
|
||||||
Flag.find_by(id: params[:id])
|
Flag.find_by(id: params.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def not_system(flag:)
|
def not_system(flag:)
|
||||||
|
@ -22,7 +22,7 @@ class Flags::ReorderFlag
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_flag(params:)
|
def fetch_flag(params:)
|
||||||
Flag.find_by(id: params[:flag_id])
|
Flag.find_by(id: params.flag_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def invalid_access(guardian:, flag:)
|
def invalid_access(guardian:, flag:)
|
||||||
@ -34,15 +34,15 @@ class Flags::ReorderFlag
|
|||||||
end
|
end
|
||||||
|
|
||||||
def invalid_move(flag:, params:, all_flags:)
|
def invalid_move(flag:, params:, all_flags:)
|
||||||
return false if all_flags.first == flag && params[:direction] == "up"
|
return false if all_flags.first == flag && params.direction == "up"
|
||||||
return false if all_flags.last == flag && params[:direction] == "down"
|
return false if all_flags.last == flag && params.direction == "down"
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def move(flag:, params:, all_flags:)
|
def move(flag:, params:, all_flags:)
|
||||||
old_position = flag.position
|
old_position = flag.position
|
||||||
index = all_flags.index(flag)
|
index = all_flags.index(flag)
|
||||||
target_flag = all_flags[params[:direction] == "up" ? index - 1 : index + 1]
|
target_flag = all_flags[params.direction == "up" ? index - 1 : index + 1]
|
||||||
|
|
||||||
flag.update!(position: target_flag.position)
|
flag.update!(position: target_flag.position)
|
||||||
target_flag.update!(position: old_position)
|
target_flag.update!(position: old_position)
|
||||||
@ -51,7 +51,7 @@ class Flags::ReorderFlag
|
|||||||
def log(guardian:, flag:, params:)
|
def log(guardian:, flag:, params:)
|
||||||
StaffActionLogger.new(guardian.user).log_custom(
|
StaffActionLogger.new(guardian.user).log_custom(
|
||||||
"move_flag",
|
"move_flag",
|
||||||
{ flag: flag.name, direction: params[:direction] },
|
{ flag: flag.name, direction: params.direction },
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -22,7 +22,7 @@ class Flags::ToggleFlag
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_flag(params:)
|
def fetch_flag(params:)
|
||||||
Flag.find_by(id: params[:flag_id])
|
Flag.find_by(id: params.flag_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def toggle(flag:)
|
def toggle(flag:)
|
||||||
|
@ -32,7 +32,7 @@ class Flags::UpdateFlag
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_flag(params:)
|
def fetch_flag(params:)
|
||||||
Flag.find_by(id: params[:id])
|
Flag.find_by(id: params.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def not_system(flag:)
|
def not_system(flag:)
|
||||||
@ -48,7 +48,7 @@ class Flags::UpdateFlag
|
|||||||
end
|
end
|
||||||
|
|
||||||
def unique_name(params:)
|
def unique_name(params:)
|
||||||
!Flag.custom.where(name: params[:name]).where.not(id: params[:id]).exists?
|
!Flag.custom.where(name: params.name).where.not(id: params.id).exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(flag:, params:)
|
def update(flag:, params:)
|
||||||
|
@ -45,16 +45,16 @@ class SiteSetting::Update
|
|||||||
end
|
end
|
||||||
|
|
||||||
def setting_is_visible(params:, options:)
|
def setting_is_visible(params:, options:)
|
||||||
options.allow_changing_hidden || !SiteSetting.hidden_settings.include?(params[:setting_name])
|
options.allow_changing_hidden || !SiteSetting.hidden_settings.include?(params.setting_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def setting_is_configurable(params:)
|
def setting_is_configurable(params:)
|
||||||
return true if !SiteSetting.plugins[params[:setting_name]]
|
return true if !SiteSetting.plugins[params.setting_name]
|
||||||
|
|
||||||
Discourse.plugins_by_name[SiteSetting.plugins[params[:setting_name]]].configurable?
|
Discourse.plugins_by_name[SiteSetting.plugins[params.setting_name]].configurable?
|
||||||
end
|
end
|
||||||
|
|
||||||
def save(params:, guardian:)
|
def save(params:, guardian:)
|
||||||
SiteSetting.set_and_log(params[:setting_name], params[:new_value], guardian.user)
|
SiteSetting.set_and_log(params.setting_name, params.new_value, guardian.user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -30,11 +30,11 @@ class User::Silence
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_user(params:)
|
def fetch_user(params:)
|
||||||
User.find_by(id: params[:user_id])
|
User.find_by(id: params.user_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_users(user:, params:)
|
def fetch_users(user:, params:)
|
||||||
[user, *User.where(id: params[:other_user_ids].to_a.uniq).to_a]
|
[user, *User.where(id: params.other_user_ids.to_a.uniq).to_a]
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_silence_all_users(guardian:, users:)
|
def can_silence_all_users(guardian:, users:)
|
||||||
@ -46,7 +46,7 @@ class User::Silence
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_post(params:)
|
def fetch_post(params:)
|
||||||
Post.find_by(id: params[:post_id])
|
Post.find_by(id: params.post_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform_post_action(guardian:, post:, params:)
|
def perform_post_action(guardian:, post:, params:)
|
||||||
|
@ -30,11 +30,11 @@ class User::Suspend
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_user(params:)
|
def fetch_user(params:)
|
||||||
User.find_by(id: params[:user_id])
|
User.find_by(id: params.user_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_users(user:, params:)
|
def fetch_users(user:, params:)
|
||||||
[user, *User.where(id: params[:other_user_ids].to_a.uniq).to_a]
|
[user, *User.where(id: params.other_user_ids.to_a.uniq).to_a]
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_suspend_all_users(guardian:, users:)
|
def can_suspend_all_users(guardian:, users:)
|
||||||
@ -46,7 +46,7 @@ class User::Suspend
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_post(params:)
|
def fetch_post(params:)
|
||||||
Post.find_by(id: params[:post_id])
|
Post.find_by(id: params.post_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform_post_action(guardian:, post:, params:)
|
def perform_post_action(guardian:, post:, params:)
|
||||||
|
@ -17,10 +17,6 @@ class Service::ContractBase
|
|||||||
@__options__
|
@__options__
|
||||||
end
|
end
|
||||||
|
|
||||||
def [](key)
|
|
||||||
public_send(key)
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_hash
|
def to_hash
|
||||||
attributes.symbolize_keys
|
attributes.symbolize_keys
|
||||||
end
|
end
|
||||||
|
@ -50,7 +50,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
::Chat::Channel.includes(:chatable).find_by(id: params[:channel_id])
|
::Chat::Channel.includes(:chatable).find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_add_users_to_channel(guardian:, channel:)
|
def can_add_users_to_channel(guardian:, channel:)
|
||||||
@ -60,8 +60,8 @@ module Chat
|
|||||||
|
|
||||||
def fetch_target_users(params:, channel:)
|
def fetch_target_users(params:, channel:)
|
||||||
::Chat::UsersFromUsernamesAndGroupsQuery.call(
|
::Chat::UsersFromUsernamesAndGroupsQuery.call(
|
||||||
usernames: params[:usernames],
|
usernames: params.usernames,
|
||||||
groups: params[:groups],
|
groups: params.groups,
|
||||||
excluded_user_ids: channel.chatable.direct_message_users.pluck(:user_id),
|
excluded_user_ids: channel.chatable.direct_message_users.pluck(:user_id),
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -45,7 +45,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
::Chat::CategoryChannel.find_by(id: params[:channel_id], auto_join_users: true)
|
::Chat::CategoryChannel.find_by(id: params.channel_id, auto_join_users: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_memberships(channel:, params:)
|
def create_memberships(channel:, params:)
|
||||||
|
@ -38,7 +38,7 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_category(params:)
|
def fetch_category(params:)
|
||||||
Category.find_by(id: params[:category_id])
|
Category.find_by(id: params.category_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_category_channel_ids(category:)
|
def fetch_category_channel_ids(category:)
|
||||||
|
@ -33,7 +33,7 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def not_everyone_allowed(params:)
|
def not_everyone_allowed(params:)
|
||||||
params[:new_allowed_groups].exclude?(Group::AUTO_GROUPS[:everyone])
|
params.new_allowed_groups.exclude?(Group::AUTO_GROUPS[:everyone])
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_users(params:)
|
def fetch_users(params:)
|
||||||
@ -46,8 +46,8 @@ module Chat
|
|||||||
.joins(:user_chat_channel_memberships)
|
.joins(:user_chat_channel_memberships)
|
||||||
.distinct
|
.distinct
|
||||||
.then do |users|
|
.then do |users|
|
||||||
break users if params[:new_allowed_groups].blank?
|
break users if params.new_allowed_groups.blank?
|
||||||
users.where(<<~SQL, params[:new_allowed_groups])
|
users.where(<<~SQL, params.new_allowed_groups)
|
||||||
users.id NOT IN (
|
users.id NOT IN (
|
||||||
SELECT DISTINCT group_users.user_id
|
SELECT DISTINCT group_users.user_id
|
||||||
FROM group_users
|
FROM group_users
|
||||||
|
@ -56,7 +56,7 @@ module Chat
|
|||||||
.not_staged
|
.not_staged
|
||||||
.includes(:group_users)
|
.includes(:group_users)
|
||||||
.where("NOT admin AND NOT moderator")
|
.where("NOT admin AND NOT moderator")
|
||||||
.where(id: params[:destroyed_group_user_ids])
|
.where(id: params.destroyed_group_user_ids)
|
||||||
.joins(:user_chat_channel_memberships)
|
.joins(:user_chat_channel_memberships)
|
||||||
.distinct
|
.distinct
|
||||||
end
|
end
|
||||||
|
@ -49,7 +49,7 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_user(params:)
|
def fetch_user(params:)
|
||||||
User.find_by(id: params[:user_id])
|
User.find_by(id: params.user_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def user_not_staff(user:)
|
def user_not_staff(user:)
|
||||||
|
@ -66,11 +66,11 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_category(params:)
|
def fetch_category(params:)
|
||||||
Category.find_by(id: params[:category_id])
|
Category.find_by(id: params.category_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def category_channel_does_not_exist(category:, params:)
|
def category_channel_does_not_exist(category:, params:)
|
||||||
!Chat::Channel.exists?(chatable: category, name: params[:name])
|
!Chat::Channel.exists?(chatable: category, name: params.name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_channel(category:, params:)
|
def create_channel(category:, params:)
|
||||||
|
@ -64,8 +64,8 @@ module Chat
|
|||||||
|
|
||||||
def fetch_target_users(guardian:, params:)
|
def fetch_target_users(guardian:, params:)
|
||||||
::Chat::UsersFromUsernamesAndGroupsQuery.call(
|
::Chat::UsersFromUsernamesAndGroupsQuery.call(
|
||||||
usernames: [*params[:target_usernames], guardian.user.username],
|
usernames: [*params.target_usernames, guardian.user.username],
|
||||||
groups: params[:target_groups],
|
groups: params.target_groups,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -79,9 +79,9 @@ module Chat
|
|||||||
|
|
||||||
def fetch_or_create_direct_message(target_users:, params:)
|
def fetch_or_create_direct_message(target_users:, params:)
|
||||||
ids = target_users.map(&:id)
|
ids = target_users.map(&:id)
|
||||||
is_group = ids.size > 2 || params[:name].present?
|
is_group = ids.size > 2 || params.name.present?
|
||||||
|
|
||||||
if params[:upsert] || !is_group
|
if params.upsert || !is_group
|
||||||
::Chat::DirectMessage.for_user_ids(ids, group: is_group) ||
|
::Chat::DirectMessage.for_user_ids(ids, group: is_group) ||
|
||||||
::Chat::DirectMessage.create(user_ids: ids, group: is_group)
|
::Chat::DirectMessage.create(user_ids: ids, group: is_group)
|
||||||
else
|
else
|
||||||
@ -94,7 +94,7 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_optional_name(channel:, params:)
|
def set_optional_name(channel:, params:)
|
||||||
channel.update!(params.slice(:name)) if params[:name]&.size&.positive?
|
channel.update!(params.slice(:name)) if params.name&.size&.positive?
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_memberships(channel:, target_users:)
|
def update_memberships(channel:, target_users:)
|
||||||
|
@ -90,7 +90,7 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
Chat::Channel.find_by_id_or_slug(params[:chat_channel_id])
|
Chat::Channel.find_by_id_or_slug(params.chat_channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def enforce_membership(guardian:, channel:, options:)
|
def enforce_membership(guardian:, channel:, options:)
|
||||||
@ -108,16 +108,16 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_reply(params:)
|
def fetch_reply(params:)
|
||||||
Chat::Message.find_by(id: params[:in_reply_to_id])
|
Chat::Message.find_by(id: params.in_reply_to_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_reply_consistency(channel:, params:, reply:)
|
def ensure_reply_consistency(channel:, params:, reply:)
|
||||||
return true if params[:in_reply_to_id].blank?
|
return true if params.in_reply_to_id.blank?
|
||||||
reply&.chat_channel == channel
|
reply&.chat_channel == channel
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_thread(params:, reply:, channel:, options:)
|
def fetch_thread(params:, reply:, channel:, options:)
|
||||||
return Chat::Thread.find_by(id: params[:thread_id]) if params[:thread_id].present?
|
return Chat::Thread.find_by(id: params.thread_id) if params.thread_id.present?
|
||||||
return unless reply
|
return unless reply
|
||||||
reply.thread ||
|
reply.thread ||
|
||||||
reply.build_thread(
|
reply.build_thread(
|
||||||
@ -129,7 +129,7 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def ensure_valid_thread_for_channel(thread:, params:, channel:)
|
def ensure_valid_thread_for_channel(thread:, params:, channel:)
|
||||||
return true if params[:thread_id].blank?
|
return true if params.thread_id.blank?
|
||||||
thread&.channel == channel
|
thread&.channel == channel
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ module Chat
|
|||||||
|
|
||||||
def fetch_uploads(params:, guardian:)
|
def fetch_uploads(params:, guardian:)
|
||||||
return [] if !SiteSetting.chat_allow_uploads
|
return [] if !SiteSetting.chat_allow_uploads
|
||||||
guardian.user.uploads.where(id: params[:upload_ids])
|
guardian.user.uploads.where(id: params.upload_ids)
|
||||||
end
|
end
|
||||||
|
|
||||||
def instantiate_message(channel:, guardian:, params:, uploads:, thread:, reply:, options:)
|
def instantiate_message(channel:, guardian:, params:, uploads:, thread:, reply:, options:)
|
||||||
@ -148,10 +148,10 @@ module Chat
|
|||||||
user: guardian.user,
|
user: guardian.user,
|
||||||
last_editor: guardian.user,
|
last_editor: guardian.user,
|
||||||
in_reply_to: reply,
|
in_reply_to: reply,
|
||||||
message: params[:message],
|
message: params.message,
|
||||||
uploads: uploads,
|
uploads: uploads,
|
||||||
thread: thread,
|
thread: thread,
|
||||||
cooked: ::Chat::Message.cook(params[:message], user_id: guardian.user.id),
|
cooked: ::Chat::Message.cook(params.message, user_id: guardian.user.id),
|
||||||
cooked_version: ::Chat::Message::BAKED_VERSION,
|
cooked_version: ::Chat::Message::BAKED_VERSION,
|
||||||
streaming: options.streaming,
|
streaming: options.streaming,
|
||||||
)
|
)
|
||||||
@ -206,7 +206,7 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def process(channel:, message_instance:, params:, thread:, options:)
|
def process(channel:, message_instance:, params:, thread:, options:)
|
||||||
::Chat::Publisher.publish_new!(channel, message_instance, params[:staged_id])
|
::Chat::Publisher.publish_new!(channel, message_instance, params.staged_id)
|
||||||
|
|
||||||
DiscourseEvent.trigger(
|
DiscourseEvent.trigger(
|
||||||
:chat_message_created,
|
:chat_message_created,
|
||||||
@ -217,20 +217,20 @@ module Chat
|
|||||||
thread: thread,
|
thread: thread,
|
||||||
thread_replies_count: thread&.replies_count_cache || 0,
|
thread_replies_count: thread&.replies_count_cache || 0,
|
||||||
context: {
|
context: {
|
||||||
post_ids: params[:context_post_ids],
|
post_ids: params.context_post_ids,
|
||||||
topic_id: params[:context_topic_id],
|
topic_id: params.context_topic_id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if options.process_inline
|
if options.process_inline
|
||||||
Jobs::Chat::ProcessMessage.new.execute(
|
Jobs::Chat::ProcessMessage.new.execute(
|
||||||
{ chat_message_id: message_instance.id, staged_id: params[:staged_id] },
|
{ chat_message_id: message_instance.id, staged_id: params.staged_id },
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
Jobs.enqueue(
|
Jobs.enqueue(
|
||||||
Jobs::Chat::ProcessMessage,
|
Jobs::Chat::ProcessMessage,
|
||||||
{ chat_message_id: message_instance.id, staged_id: params[:staged_id] },
|
{ chat_message_id: message_instance.id, staged_id: params.staged_id },
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -40,14 +40,11 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
::Chat::Channel.find_by(id: params[:channel_id])
|
::Chat::Channel.find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_original_message(channel:, params:)
|
def fetch_original_message(channel:, params:)
|
||||||
::Chat::Message.find_by(
|
::Chat::Message.find_by(id: params.original_message_id, chat_channel_id: params.channel_id)
|
||||||
id: params[:original_message_id],
|
|
||||||
chat_channel_id: params[:channel_id],
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_view_channel(guardian:, channel:)
|
def can_view_channel(guardian:, channel:)
|
||||||
@ -64,7 +61,7 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
context[:thread] = channel.threads.create(
|
context[:thread] = channel.threads.create(
|
||||||
title: params[:title],
|
title: params.title,
|
||||||
original_message: original_message,
|
original_message: original_message,
|
||||||
original_message_user: original_message.user,
|
original_message_user: original_message.user,
|
||||||
)
|
)
|
||||||
|
@ -48,8 +48,8 @@ module Chat
|
|||||||
|
|
||||||
def fetch_message(params:)
|
def fetch_message(params:)
|
||||||
Chat::Message.includes(:chat_channel, :revisions).find_by(
|
Chat::Message.includes(:chat_channel, :revisions).find_by(
|
||||||
id: params[:message_id],
|
id: params.message_id,
|
||||||
chat_channel_id: params[:channel_id],
|
chat_channel_id: params.channel_id,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ module Chat
|
|||||||
guardian.can_flag_chat_message?(message) &&
|
guardian.can_flag_chat_message?(message) &&
|
||||||
guardian.can_flag_message_as?(
|
guardian.can_flag_message_as?(
|
||||||
message,
|
message,
|
||||||
params[:flag_type_id],
|
params.flag_type_id,
|
||||||
params.slice(:queue_for_review, :take_action, :is_warning),
|
params.slice(:queue_for_review, :take_action, :is_warning),
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@ -67,7 +67,7 @@ module Chat
|
|||||||
Chat::ReviewQueue.new.flag_message(
|
Chat::ReviewQueue.new.flag_message(
|
||||||
message,
|
message,
|
||||||
guardian,
|
guardian,
|
||||||
params[:flag_type_id],
|
params.flag_type_id,
|
||||||
**params.slice(:message, :is_warning, :take_action, :queue_for_review),
|
**params.slice(:message, :is_warning, :take_action, :queue_for_review),
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -33,7 +33,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
::Chat::Channel.find_by(id: params[:channel_id])
|
::Chat::Channel.find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_view_channel(guardian:, channel:)
|
def can_view_channel(guardian:, channel:)
|
||||||
@ -45,7 +45,7 @@ module Chat
|
|||||||
.joins(:user_option)
|
.joins(:user_option)
|
||||||
.where(user_options: { chat_enabled: true })
|
.where(user_options: { chat_enabled: true })
|
||||||
.not_suspended
|
.not_suspended
|
||||||
.where(id: params[:user_ids])
|
.where(id: params.user_ids)
|
||||||
.limit(50)
|
.limit(50)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ module Chat
|
|||||||
chat_channel_title: channel.title(invited_user),
|
chat_channel_title: channel.title(invited_user),
|
||||||
chat_channel_slug: channel.slug,
|
chat_channel_slug: channel.slug,
|
||||||
invited_by_username: guardian.user.username,
|
invited_by_username: guardian.user.username,
|
||||||
chat_message_id: params[:message_id],
|
chat_message_id: params.message_id,
|
||||||
}.compact
|
}.compact
|
||||||
|
|
||||||
invited_user.notifications.create(
|
invited_user.notifications.create(
|
||||||
|
@ -32,7 +32,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
Chat::Channel.find_by(id: params[:channel_id])
|
Chat::Channel.find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def leave(channel:, guardian:)
|
def leave(channel:, guardian:)
|
||||||
|
@ -57,7 +57,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
::Chat::Channel.includes(:chatable).find_by(id: params[:channel_id])
|
::Chat::Channel.includes(:chatable).find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_membership(channel:, guardian:)
|
def fetch_membership(channel:, guardian:)
|
||||||
@ -73,10 +73,10 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def determine_target_message_id(params:, membership:)
|
def determine_target_message_id(params:, membership:)
|
||||||
if params[:fetch_from_last_read]
|
if params.fetch_from_last_read
|
||||||
context[:target_message_id] = membership&.last_read_message_id
|
context[:target_message_id] = membership&.last_read_message_id
|
||||||
else
|
else
|
||||||
context[:target_message_id] = params[:target_message_id]
|
context[:target_message_id] = params.target_message_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -103,9 +103,9 @@ module Chat
|
|||||||
guardian:,
|
guardian:,
|
||||||
target_message_id:,
|
target_message_id:,
|
||||||
include_thread_messages: !enabled_threads,
|
include_thread_messages: !enabled_threads,
|
||||||
page_size: params[:page_size] || Chat::MessagesQuery::MAX_PAGE_SIZE,
|
page_size: params.page_size || Chat::MessagesQuery::MAX_PAGE_SIZE,
|
||||||
direction: params[:direction],
|
direction: params.direction,
|
||||||
target_date: params[:target_date],
|
target_date: params.target_date,
|
||||||
)
|
)
|
||||||
|
|
||||||
context[:can_load_more_past] = messages_data[:can_load_more_past]
|
context[:can_load_more_past] = messages_data[:can_load_more_past]
|
||||||
|
@ -51,7 +51,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_thread(params:)
|
def fetch_thread(params:)
|
||||||
::Chat::Thread.strict_loading.includes(channel: :chatable).find_by(id: params[:thread_id])
|
::Chat::Thread.strict_loading.includes(channel: :chatable).find_by(id: params.thread_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_view_thread(guardian:, thread:)
|
def can_view_thread(guardian:, thread:)
|
||||||
@ -63,14 +63,14 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def determine_target_message_id(params:, membership:, guardian:, thread:)
|
def determine_target_message_id(params:, membership:, guardian:, thread:)
|
||||||
if params[:fetch_from_last_message]
|
if params.fetch_from_last_message
|
||||||
context[:target_message_id] = thread.last_message_id
|
context[:target_message_id] = thread.last_message_id
|
||||||
elsif params[:fetch_from_first_message]
|
elsif params.fetch_from_first_message
|
||||||
context[:target_message_id] = thread.original_message_id
|
context[:target_message_id] = thread.original_message_id
|
||||||
elsif params[:fetch_from_last_read] || !params[:target_message_id]
|
elsif params.fetch_from_last_read || !params.target_message_id
|
||||||
context[:target_message_id] = membership&.last_read_message_id
|
context[:target_message_id] = membership&.last_read_message_id
|
||||||
elsif params[:target_message_id]
|
elsif params.target_message_id
|
||||||
context[:target_message_id] = params[:target_message_id]
|
context[:target_message_id] = params.target_message_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ module Chat
|
|||||||
target_message =
|
target_message =
|
||||||
::Chat::Message.with_deleted.find_by(
|
::Chat::Message.with_deleted.find_by(
|
||||||
id: context.target_message_id,
|
id: context.target_message_id,
|
||||||
thread_id: params[:thread_id],
|
thread_id: params.thread_id,
|
||||||
)
|
)
|
||||||
return false if target_message.blank?
|
return false if target_message.blank?
|
||||||
return true if !target_message.trashed?
|
return true if !target_message.trashed?
|
||||||
@ -93,11 +93,11 @@ module Chat
|
|||||||
guardian: guardian,
|
guardian: guardian,
|
||||||
target_message_id: context.target_message_id,
|
target_message_id: context.target_message_id,
|
||||||
thread_id: thread.id,
|
thread_id: thread.id,
|
||||||
page_size: params[:page_size] || Chat::MessagesQuery::MAX_PAGE_SIZE,
|
page_size: params.page_size || Chat::MessagesQuery::MAX_PAGE_SIZE,
|
||||||
direction: params[:direction],
|
direction: params.direction,
|
||||||
target_date: params[:target_date],
|
target_date: params.target_date,
|
||||||
include_target_message_id:
|
include_target_message_id:
|
||||||
params[:fetch_from_first_message] || params[:fetch_from_last_message],
|
params.fetch_from_first_message || params.fetch_from_last_message,
|
||||||
)
|
)
|
||||||
|
|
||||||
context[:can_load_more_past] = messages_data[:can_load_more_past]
|
context[:can_load_more_past] = messages_data[:can_load_more_past]
|
||||||
|
@ -37,9 +37,12 @@ module Chat
|
|||||||
only_integer: true,
|
only_integer: true,
|
||||||
},
|
},
|
||||||
allow_nil: true
|
allow_nil: true
|
||||||
|
|
||||||
|
after_validation do
|
||||||
|
self.limit = (limit || THREADS_LIMIT).to_i.clamp(1, THREADS_LIMIT)
|
||||||
|
self.offset = [offset || 0, 0].max
|
||||||
|
end
|
||||||
end
|
end
|
||||||
step :set_limit
|
|
||||||
step :set_offset
|
|
||||||
model :channel
|
model :channel
|
||||||
policy :threading_enabled_for_channel
|
policy :threading_enabled_for_channel
|
||||||
policy :can_view_channel
|
policy :can_view_channel
|
||||||
@ -51,16 +54,8 @@ module Chat
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_limit(params:)
|
|
||||||
context[:limit] = (params[:limit] || THREADS_LIMIT).to_i.clamp(1, THREADS_LIMIT)
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_offset(params:)
|
|
||||||
context[:offset] = [params[:offset] || 0, 0].max
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
::Chat::Channel.strict_loading.includes(:chatable).find_by(id: params[:channel_id])
|
::Chat::Channel.strict_loading.includes(:chatable).find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def threading_enabled_for_channel(channel:)
|
def threading_enabled_for_channel(channel:)
|
||||||
@ -71,7 +66,7 @@ module Chat
|
|||||||
guardian.can_preview_chat_channel?(channel)
|
guardian.can_preview_chat_channel?(channel)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_threads(guardian:, channel:)
|
def fetch_threads(guardian:, channel:, params:)
|
||||||
::Chat::Thread
|
::Chat::Thread
|
||||||
.includes(
|
.includes(
|
||||||
:channel,
|
:channel,
|
||||||
@ -114,8 +109,8 @@ module Chat
|
|||||||
.order(
|
.order(
|
||||||
"CASE WHEN user_chat_thread_memberships.last_read_message_id IS NULL OR user_chat_thread_memberships.last_read_message_id < chat_threads.last_message_id THEN true ELSE false END DESC, last_message.created_at DESC",
|
"CASE WHEN user_chat_thread_memberships.last_read_message_id IS NULL OR user_chat_thread_memberships.last_read_message_id < chat_threads.last_message_id THEN true ELSE false END DESC, last_message.created_at DESC",
|
||||||
)
|
)
|
||||||
.limit(context.limit)
|
.limit(params.limit)
|
||||||
.offset(context.offset)
|
.offset(params.offset)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_tracking(guardian:, threads:)
|
def fetch_tracking(guardian:, threads:)
|
||||||
@ -137,8 +132,8 @@ module Chat
|
|||||||
context[:participants] = ::Chat::ThreadParticipantQuery.call(thread_ids: threads.map(&:id))
|
context[:participants] = ::Chat::ThreadParticipantQuery.call(thread_ids: threads.map(&:id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_load_more_url(channel:)
|
def build_load_more_url(channel:, params:)
|
||||||
load_more_params = { offset: context.offset + context.limit }.to_query
|
load_more_params = { offset: params.offset + params.limit }.to_query
|
||||||
context[:load_more_url] = ::URI::HTTP.build(
|
context[:load_more_url] = ::URI::HTTP.build(
|
||||||
path: "/chat/api/channels/#{channel.id}/threads",
|
path: "/chat/api/channels/#{channel.id}/threads",
|
||||||
query: load_more_params,
|
query: load_more_params,
|
||||||
|
@ -36,7 +36,7 @@ module Chat
|
|||||||
:channel,
|
:channel,
|
||||||
original_message_user: :user_status,
|
original_message_user: :user_status,
|
||||||
original_message: :chat_webhook_event,
|
original_message: :chat_webhook_event,
|
||||||
).find_by(id: params[:thread_id], channel_id: params[:channel_id])
|
).find_by(id: params.thread_id, channel_id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def invalid_access(guardian:, thread:)
|
def invalid_access(guardian:, thread:)
|
||||||
|
@ -24,9 +24,12 @@ module Chat
|
|||||||
params do
|
params do
|
||||||
attribute :limit, :integer
|
attribute :limit, :integer
|
||||||
attribute :offset, :integer
|
attribute :offset, :integer
|
||||||
|
|
||||||
|
after_validation do
|
||||||
|
self.limit = (limit || THREADS_LIMIT).to_i.clamp(1, THREADS_LIMIT)
|
||||||
|
self.offset = [offset || 0, 0].max
|
||||||
|
end
|
||||||
end
|
end
|
||||||
step :set_limit
|
|
||||||
step :set_offset
|
|
||||||
model :threads
|
model :threads
|
||||||
step :fetch_tracking
|
step :fetch_tracking
|
||||||
step :fetch_memberships
|
step :fetch_memberships
|
||||||
@ -35,15 +38,7 @@ module Chat
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_limit(params:)
|
def fetch_threads(guardian:, params:)
|
||||||
context[:limit] = (params[:limit] || THREADS_LIMIT).to_i.clamp(1, THREADS_LIMIT)
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_offset(params:)
|
|
||||||
context[:offset] = [params[:offset] || 0, 0].max
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_threads(guardian:)
|
|
||||||
::Chat::Thread
|
::Chat::Thread
|
||||||
.includes(
|
.includes(
|
||||||
:channel,
|
:channel,
|
||||||
@ -108,8 +103,8 @@ module Chat
|
|||||||
.order(
|
.order(
|
||||||
"CASE WHEN user_chat_thread_memberships.last_read_message_id IS NULL OR user_chat_thread_memberships.last_read_message_id < chat_threads.last_message_id THEN true ELSE false END DESC, last_message.created_at DESC",
|
"CASE WHEN user_chat_thread_memberships.last_read_message_id IS NULL OR user_chat_thread_memberships.last_read_message_id < chat_threads.last_message_id THEN true ELSE false END DESC, last_message.created_at DESC",
|
||||||
)
|
)
|
||||||
.limit(context.limit)
|
.limit(params.limit)
|
||||||
.offset(context.offset)
|
.offset(params.offset)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_tracking(guardian:, threads:)
|
def fetch_tracking(guardian:, threads:)
|
||||||
@ -131,8 +126,8 @@ module Chat
|
|||||||
context[:participants] = ::Chat::ThreadParticipantQuery.call(thread_ids: threads.map(&:id))
|
context[:participants] = ::Chat::ThreadParticipantQuery.call(thread_ids: threads.map(&:id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_load_more_url
|
def build_load_more_url(params:)
|
||||||
load_more_params = { limit: context.limit, offset: context.offset + context.limit }.to_query
|
load_more_params = { limit: params.limit, offset: params.offset + params.limit }.to_query
|
||||||
|
|
||||||
context[:load_more_url] = ::URI::HTTP.build(
|
context[:load_more_url] = ::URI::HTTP.build(
|
||||||
path: "/chat/api/me/threads",
|
path: "/chat/api/me/threads",
|
||||||
|
@ -38,7 +38,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_thread(params:)
|
def fetch_thread(params:)
|
||||||
Chat::Thread.find_by(id: params[:thread_id], channel_id: params[:channel_id])
|
Chat::Thread.find_by(id: params.thread_id, channel_id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_view_channel(guardian:, thread:)
|
def can_view_channel(guardian:, thread:)
|
||||||
|
@ -40,7 +40,7 @@ module Chat
|
|||||||
Chat::Message
|
Chat::Message
|
||||||
.with_deleted
|
.with_deleted
|
||||||
.includes(chat_channel: :chatable)
|
.includes(chat_channel: :chatable)
|
||||||
.find_by(id: params[:message_id], chat_channel_id: params[:channel_id])
|
.find_by(id: params.message_id, chat_channel_id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def invalid_access(guardian:, message:)
|
def invalid_access(guardian:, message:)
|
||||||
|
@ -40,33 +40,33 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_users(guardian:, params:)
|
def fetch_users(guardian:, params:)
|
||||||
return unless params[:include_users]
|
return unless params.include_users
|
||||||
return unless guardian.can_create_direct_message?
|
return unless guardian.can_create_direct_message?
|
||||||
search_users(params, guardian)
|
search_users(params, guardian)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_groups(guardian:, params:)
|
def fetch_groups(guardian:, params:)
|
||||||
return unless params[:include_groups]
|
return unless params.include_groups
|
||||||
return unless guardian.can_create_direct_message?
|
return unless guardian.can_create_direct_message?
|
||||||
search_groups(params, guardian)
|
search_groups(params, guardian)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_category_channels(guardian:, params:)
|
def fetch_category_channels(guardian:, params:)
|
||||||
return unless params[:include_category_channels]
|
return unless params.include_category_channels
|
||||||
return unless SiteSetting.enable_public_channels
|
return unless SiteSetting.enable_public_channels
|
||||||
search_category_channels(params, guardian)
|
search_category_channels(params, guardian)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_direct_message_channels(guardian:, params:, users:)
|
def fetch_direct_message_channels(guardian:, params:, users:)
|
||||||
return unless params[:include_direct_message_channels]
|
return unless params.include_direct_message_channels
|
||||||
return unless guardian.can_create_direct_message?
|
return unless guardian.can_create_direct_message?
|
||||||
search_direct_message_channels(guardian, params, users)
|
search_direct_message_channels(guardian, params, users)
|
||||||
end
|
end
|
||||||
|
|
||||||
def search_users(params, guardian)
|
def search_users(params, guardian)
|
||||||
user_search = ::UserSearch.new(params[:term], limit: SEARCH_RESULT_LIMIT)
|
user_search = ::UserSearch.new(params.term, limit: SEARCH_RESULT_LIMIT)
|
||||||
|
|
||||||
if params[:term].blank?
|
if params.term.blank?
|
||||||
user_search = user_search.scoped_users
|
user_search = user_search.scoped_users
|
||||||
else
|
else
|
||||||
user_search = user_search.search
|
user_search = user_search.search
|
||||||
@ -78,11 +78,11 @@ module Chat
|
|||||||
user_search = user_search.real(allowed_bot_user_ids: allowed_bot_user_ids)
|
user_search = user_search.real(allowed_bot_user_ids: allowed_bot_user_ids)
|
||||||
user_search = user_search.includes(:user_option)
|
user_search = user_search.includes(:user_option)
|
||||||
|
|
||||||
if params[:excluded_memberships_channel_id]
|
if params.excluded_memberships_channel_id
|
||||||
user_search =
|
user_search =
|
||||||
user_search.where(
|
user_search.where(
|
||||||
"NOT EXISTS (SELECT 1 FROM user_chat_channel_memberships WHERE user_id = users.id AND chat_channel_id = ?)",
|
"NOT EXISTS (SELECT 1 FROM user_chat_channel_memberships WHERE user_id = users.id AND chat_channel_id = ?)",
|
||||||
params[:excluded_memberships_channel_id],
|
params.excluded_memberships_channel_id,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ module Chat
|
|||||||
.includes(users: :user_option)
|
.includes(users: :user_option)
|
||||||
.where(
|
.where(
|
||||||
"groups.name ILIKE :term_like OR groups.full_name ILIKE :term_like",
|
"groups.name ILIKE :term_like OR groups.full_name ILIKE :term_like",
|
||||||
term_like: "%#{params[:term]}%",
|
term_like: "%#{params.term}%",
|
||||||
)
|
)
|
||||||
.limit(SEARCH_RESULT_LIMIT)
|
.limit(SEARCH_RESULT_LIMIT)
|
||||||
end
|
end
|
||||||
@ -104,7 +104,7 @@ module Chat
|
|||||||
::Chat::ChannelFetcher.secured_public_channel_search(
|
::Chat::ChannelFetcher.secured_public_channel_search(
|
||||||
guardian,
|
guardian,
|
||||||
status: :open,
|
status: :open,
|
||||||
filter: params[:term],
|
filter: params.term,
|
||||||
filter_on_category_name: false,
|
filter_on_category_name: false,
|
||||||
match_filter_on_starts_with: false,
|
match_filter_on_starts_with: false,
|
||||||
limit: SEARCH_RESULT_LIMIT,
|
limit: SEARCH_RESULT_LIMIT,
|
||||||
@ -116,13 +116,13 @@ module Chat
|
|||||||
::Chat::ChannelFetcher.secured_direct_message_channels_search(
|
::Chat::ChannelFetcher.secured_direct_message_channels_search(
|
||||||
guardian.user.id,
|
guardian.user.id,
|
||||||
guardian,
|
guardian,
|
||||||
filter: params[:term],
|
filter: params.term,
|
||||||
match_filter_on_starts_with: false,
|
match_filter_on_starts_with: false,
|
||||||
limit: SEARCH_RESULT_LIMIT,
|
limit: SEARCH_RESULT_LIMIT,
|
||||||
) || []
|
) || []
|
||||||
|
|
||||||
# skip 1:1s when search returns users
|
# skip 1:1s when search returns users
|
||||||
if params[:include_users] && users.present?
|
if params.include_users && users.present?
|
||||||
channels.reject! do |channel|
|
channels.reject! do |channel|
|
||||||
other_user_ids = channel.allowed_user_ids - [guardian.user.id]
|
other_user_ids = channel.allowed_user_ids - [guardian.user.id]
|
||||||
other_user_ids.size <= 1
|
other_user_ids.size <= 1
|
||||||
|
@ -29,7 +29,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_message(params:)
|
def fetch_message(params:)
|
||||||
::Chat::Message.find_by(id: params[:message_id])
|
::Chat::Message.find_by(id: params.message_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def enforce_membership(guardian:, message:)
|
def enforce_membership(guardian:, message:)
|
||||||
|
@ -18,7 +18,12 @@ module Chat
|
|||||||
|
|
||||||
DELETE_CHANNEL_LOG_KEY = "chat_channel_delete"
|
DELETE_CHANNEL_LOG_KEY = "chat_channel_delete"
|
||||||
|
|
||||||
model :channel, :fetch_channel
|
params do
|
||||||
|
attribute :channel_id, :integer
|
||||||
|
|
||||||
|
validates :channel_id, presence: true
|
||||||
|
end
|
||||||
|
model :channel
|
||||||
policy :invalid_access
|
policy :invalid_access
|
||||||
transaction do
|
transaction do
|
||||||
step :prevents_slug_collision
|
step :prevents_slug_collision
|
||||||
@ -30,7 +35,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
Chat::Channel.find_by(id: params[:channel_id])
|
Chat::Channel.find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def invalid_access(guardian:, channel:)
|
def invalid_access(guardian:, channel:)
|
||||||
|
@ -40,8 +40,8 @@ module Chat
|
|||||||
|
|
||||||
def fetch_message(params:)
|
def fetch_message(params:)
|
||||||
Chat::Message.includes(chat_channel: :chatable).find_by(
|
Chat::Message.includes(chat_channel: :chatable).find_by(
|
||||||
id: params[:message_id],
|
id: params.message_id,
|
||||||
chat_channel_id: params[:channel_id],
|
chat_channel_id: params.channel_id,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,8 +40,8 @@ module Chat
|
|||||||
|
|
||||||
def fetch_messages(params:)
|
def fetch_messages(params:)
|
||||||
Chat::Message.includes(chat_channel: :chatable).where(
|
Chat::Message.includes(chat_channel: :chatable).where(
|
||||||
id: params[:message_ids],
|
id: params.message_ids,
|
||||||
chat_channel_id: params[:channel_id],
|
chat_channel_id: params.channel_id,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ module Chat
|
|||||||
messages.each do |message|
|
messages.each do |message|
|
||||||
DiscourseEvent.trigger(:chat_message_trashed, message, message.chat_channel, guardian.user)
|
DiscourseEvent.trigger(:chat_message_trashed, message, message.chat_channel, guardian.user)
|
||||||
end
|
end
|
||||||
Chat::Publisher.publish_bulk_delete!(messages.first.chat_channel, params[:message_ids])
|
Chat::Publisher.publish_bulk_delete!(messages.first.chat_channel, params.message_ids)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -31,7 +31,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
Chat::Channel.find_by(id: params[:channel_id])
|
Chat::Channel.find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unfollow(channel:, guardian:)
|
def unfollow(channel:, guardian:)
|
||||||
|
@ -16,28 +16,30 @@ module Chat
|
|||||||
# @option params [String] :status
|
# @option params [String] :status
|
||||||
# @return [Service::Base::Context]
|
# @return [Service::Base::Context]
|
||||||
|
|
||||||
model :channel
|
|
||||||
params do
|
params do
|
||||||
|
attribute :channel_id, :integer
|
||||||
attribute :status, :string
|
attribute :status, :string
|
||||||
|
|
||||||
|
validates :channel_id, presence: true
|
||||||
validates :status, inclusion: { in: Chat::Channel.editable_statuses.keys }
|
validates :status, inclusion: { in: Chat::Channel.editable_statuses.keys }
|
||||||
end
|
end
|
||||||
|
model :channel
|
||||||
policy :check_channel_permission
|
policy :check_channel_permission
|
||||||
step :change_status
|
step :change_status
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
Chat::Channel.find_by(id: params[:channel_id])
|
Chat::Channel.find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_channel_permission(guardian:, channel:, params:)
|
def check_channel_permission(guardian:, channel:, params:)
|
||||||
guardian.can_preview_chat_channel?(channel) &&
|
guardian.can_preview_chat_channel?(channel) &&
|
||||||
guardian.can_change_channel_status?(channel, params[:status].to_sym)
|
guardian.can_change_channel_status?(channel, params.status.to_sym)
|
||||||
end
|
end
|
||||||
|
|
||||||
def change_status(channel:, params:, guardian:)
|
def change_status(channel:, params:, guardian:)
|
||||||
channel.public_send("#{params[:status]}!", guardian.user)
|
channel.public_send("#{params.status}!", guardian.user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -79,7 +79,7 @@ module Chat
|
|||||||
chatable: [:topic_only_relative_url, direct_message_users: [user: :user_option]],
|
chatable: [:topic_only_relative_url, direct_message_users: [user: :user_option]],
|
||||||
],
|
],
|
||||||
user: :user_status,
|
user: :user_status,
|
||||||
).find_by(id: params[:message_id])
|
).find_by(id: params.message_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_membership(guardian:, message:)
|
def fetch_membership(guardian:, message:)
|
||||||
@ -88,7 +88,7 @@ module Chat
|
|||||||
|
|
||||||
def fetch_uploads(params:, guardian:)
|
def fetch_uploads(params:, guardian:)
|
||||||
return if !SiteSetting.chat_allow_uploads
|
return if !SiteSetting.chat_allow_uploads
|
||||||
guardian.user.uploads.where(id: params[:upload_ids])
|
guardian.user.uploads.where(id: params.upload_ids)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_modify_channel_message(guardian:, message:)
|
def can_modify_channel_message(guardian:, message:)
|
||||||
@ -100,11 +100,11 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def modify_message(params:, message:, guardian:, uploads:)
|
def modify_message(params:, message:, guardian:, uploads:)
|
||||||
message.message = params[:message]
|
message.message = params.message
|
||||||
message.last_editor_id = guardian.user.id
|
message.last_editor_id = guardian.user.id
|
||||||
message.cook
|
message.cook
|
||||||
|
|
||||||
return if uploads&.size != params[:upload_ids].to_a.size
|
return if uploads&.size != params.upload_ids.to_a.size
|
||||||
|
|
||||||
new_upload_ids = uploads.map(&:id)
|
new_upload_ids = uploads.map(&:id)
|
||||||
existing_upload_ids = message.upload_ids
|
existing_upload_ids = message.upload_ids
|
||||||
|
@ -36,7 +36,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_thread(params:)
|
def fetch_thread(params:)
|
||||||
Chat::Thread.find_by(id: params[:thread_id])
|
Chat::Thread.find_by(id: params.thread_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_view_channel(guardian:, thread:)
|
def can_view_channel(guardian:, thread:)
|
||||||
|
@ -45,7 +45,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_thread(params:)
|
def fetch_thread(params:)
|
||||||
Chat::Thread.find_by(id: params[:thread_id], channel_id: params[:channel_id])
|
Chat::Thread.find_by(id: params.thread_id, channel_id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_view_channel(guardian:, thread:)
|
def can_view_channel(guardian:, thread:)
|
||||||
@ -62,7 +62,7 @@ module Chat
|
|||||||
membership = thread.add(guardian.user)
|
membership = thread.add(guardian.user)
|
||||||
membership.update!(last_read_message_id: thread.last_message_id)
|
membership.update!(last_read_message_id: thread.last_message_id)
|
||||||
end
|
end
|
||||||
membership.update!(notification_level: params[:notification_level])
|
membership.update!(notification_level: params.notification_level)
|
||||||
context[:membership] = membership
|
context[:membership] = membership
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -36,7 +36,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
::Chat::Channel.find_by(id: params[:channel_id])
|
::Chat::Channel.find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_membership(guardian:, channel:)
|
def fetch_membership(guardian:, channel:)
|
||||||
@ -48,7 +48,7 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_message(channel:, params:)
|
def fetch_message(channel:, params:)
|
||||||
::Chat::Message.with_deleted.find_by(chat_channel_id: channel.id, id: params[:message_id])
|
::Chat::Message.with_deleted.find_by(chat_channel_id: channel.id, id: params.message_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_message_id_recency(message:, membership:)
|
def ensure_message_id_recency(message:, membership:)
|
||||||
|
@ -37,7 +37,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_thread(params:)
|
def fetch_thread(params:)
|
||||||
::Chat::Thread.find_by(id: params[:thread_id], channel_id: params[:channel_id])
|
::Chat::Thread.find_by(id: params.thread_id, channel_id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def invalid_access(guardian:, thread:)
|
def invalid_access(guardian:, thread:)
|
||||||
@ -50,7 +50,7 @@ module Chat
|
|||||||
|
|
||||||
def fetch_message(params:, thread:)
|
def fetch_message(params:, thread:)
|
||||||
::Chat::Message.with_deleted.find_by(
|
::Chat::Message.with_deleted.find_by(
|
||||||
id: params[:message_id] || thread.last_message_id,
|
id: params.message_id || thread.last_message_id,
|
||||||
thread: thread,
|
thread: thread,
|
||||||
chat_channel: thread.channel,
|
chat_channel: thread.channel,
|
||||||
)
|
)
|
||||||
|
@ -39,7 +39,7 @@ module Chat
|
|||||||
private
|
private
|
||||||
|
|
||||||
def fetch_channel(params:)
|
def fetch_channel(params:)
|
||||||
Chat::Channel.find_by(id: params[:channel_id])
|
Chat::Channel.find_by(id: params.channel_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_upsert_draft(guardian:, channel:)
|
def can_upsert_draft(guardian:, channel:)
|
||||||
@ -47,26 +47,26 @@ module Chat
|
|||||||
end
|
end
|
||||||
|
|
||||||
def check_thread_exists(params:, channel:)
|
def check_thread_exists(params:, channel:)
|
||||||
return if params[:thread_id].blank?
|
return if params.thread_id.blank?
|
||||||
fail!("Thread not found") if !channel.threads.exists?(id: params[:thread_id])
|
fail!("Thread not found") if !channel.threads.exists?(id: params.thread_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def upsert_draft(params:, guardian:)
|
def upsert_draft(params:, guardian:)
|
||||||
if params[:data].present?
|
if params.data.present?
|
||||||
draft =
|
draft =
|
||||||
Chat::Draft.find_or_initialize_by(
|
Chat::Draft.find_or_initialize_by(
|
||||||
user_id: guardian.user.id,
|
user_id: guardian.user.id,
|
||||||
chat_channel_id: params[:channel_id],
|
chat_channel_id: params.channel_id,
|
||||||
thread_id: params[:thread_id],
|
thread_id: params.thread_id,
|
||||||
)
|
)
|
||||||
draft.data = params[:data]
|
draft.data = params.data
|
||||||
draft.save!
|
draft.save!
|
||||||
else
|
else
|
||||||
# when data is empty, we destroy the draft
|
# when data is empty, we destroy the draft
|
||||||
Chat::Draft.where(
|
Chat::Draft.where(
|
||||||
user: guardian.user,
|
user: guardian.user,
|
||||||
chat_channel_id: params[:channel_id],
|
chat_channel_id: params.channel_id,
|
||||||
thread_id: params[:thread_id],
|
thread_id: params.thread_id,
|
||||||
).destroy_all
|
).destroy_all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -30,7 +30,7 @@ RSpec.describe ::Chat::LookupChannelThreads do
|
|||||||
let(:limit) { nil }
|
let(:limit) { nil }
|
||||||
|
|
||||||
it "defaults to a max value" do
|
it "defaults to a max value" do
|
||||||
expect(result.limit).to eq(described_class::THREADS_LIMIT)
|
expect(result.params.limit).to eq(described_class::THREADS_LIMIT)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ RSpec.describe ::Chat::LookupChannelThreads do
|
|||||||
let(:limit) { 0 }
|
let(:limit) { 0 }
|
||||||
|
|
||||||
it "defaults to a max value" do
|
it "defaults to a max value" do
|
||||||
expect(result.limit).to eq(1)
|
expect(result.params.limit).to eq(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -57,7 +57,7 @@ RSpec.describe ::Chat::LookupChannelThreads do
|
|||||||
let(:offset) { nil }
|
let(:offset) { nil }
|
||||||
|
|
||||||
it "defaults to zero" do
|
it "defaults to zero" do
|
||||||
expect(result.offset).to eq(0)
|
expect(result.params.offset).to eq(0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ RSpec.describe ::Chat::LookupChannelThreads do
|
|||||||
let(:offset) { -99 }
|
let(:offset) { -99 }
|
||||||
|
|
||||||
it "defaults to a min value" do
|
it "defaults to a min value" do
|
||||||
expect(result.offset).to eq(0)
|
expect(result.params.offset).to eq(0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -47,10 +47,10 @@ RSpec.describe Chat::SearchChatable do
|
|||||||
|
|
||||||
it "cleans the term" do
|
it "cleans the term" do
|
||||||
params[:term] = "#bob"
|
params[:term] = "#bob"
|
||||||
expect(result.params[:term]).to eq("bob")
|
expect(result.params.term).to eq("bob")
|
||||||
|
|
||||||
params[:term] = "@bob"
|
params[:term] = "@bob"
|
||||||
expect(result.params[:term]).to eq("bob")
|
expect(result.params.term).to eq("bob")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fetches user memberships" do
|
it "fetches user memberships" do
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
RSpec.describe Chat::TrashChannel do
|
RSpec.describe Chat::TrashChannel do
|
||||||
|
describe described_class::Contract, type: :model do
|
||||||
|
it { is_expected.to validate_presence_of(:channel_id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".call" do
|
||||||
subject(:result) { described_class.call(params:, **dependencies) }
|
subject(:result) { described_class.call(params:, **dependencies) }
|
||||||
|
|
||||||
fab!(:current_user) { Fabricate(:admin) }
|
fab!(:current_user) { Fabricate(:admin) }
|
||||||
@ -11,20 +16,25 @@ RSpec.describe Chat::TrashChannel do
|
|||||||
let(:guardian) { Guardian.new(current_user) }
|
let(:guardian) { Guardian.new(current_user) }
|
||||||
let(:channel_id) { channel.id }
|
let(:channel_id) { channel.id }
|
||||||
|
|
||||||
context "when channel_id is not provided" do
|
context "when data is invalid" do
|
||||||
let(:channel_id) { nil }
|
let(:channel_id) { nil }
|
||||||
|
|
||||||
|
it { is_expected.to fail_a_contract }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when model is not found" do
|
||||||
|
let(:channel_id) { 0 }
|
||||||
|
|
||||||
it { is_expected.to fail_to_find_a_model(:channel) }
|
it { is_expected.to fail_to_find_a_model(:channel) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when channel_id is provided" do
|
|
||||||
context "when user is not allowed to perform the action" do
|
context "when user is not allowed to perform the action" do
|
||||||
let!(:current_user) { Fabricate(:user) }
|
let!(:current_user) { Fabricate(:user) }
|
||||||
|
|
||||||
it { is_expected.to fail_a_policy(:invalid_access) }
|
it { is_expected.to fail_a_policy(:invalid_access) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when user is allowed to perform the action" do
|
context "when everything’s ok" do
|
||||||
it { is_expected.to run_successfully }
|
it { is_expected.to run_successfully }
|
||||||
|
|
||||||
it "trashes the channel" do
|
it "trashes the channel" do
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
RSpec.describe(Chat::UpdateChannelStatus) do
|
RSpec.describe(Chat::UpdateChannelStatus) do
|
||||||
describe described_class::Contract, type: :model do
|
describe described_class::Contract, type: :model do
|
||||||
|
it { is_expected.to validate_presence_of(:channel_id) }
|
||||||
it do
|
it do
|
||||||
is_expected.to validate_inclusion_of(:status).in_array(Chat::Channel.editable_statuses.keys)
|
is_expected.to validate_inclusion_of(:status).in_array(Chat::Channel.editable_statuses.keys)
|
||||||
end
|
end
|
||||||
@ -19,8 +20,8 @@ RSpec.describe(Chat::UpdateChannelStatus) do
|
|||||||
let(:status) { "open" }
|
let(:status) { "open" }
|
||||||
let(:channel_id) { channel.id }
|
let(:channel_id) { channel.id }
|
||||||
|
|
||||||
context "when no channel_id is given" do
|
context "when model is not found" do
|
||||||
let(:channel_id) { nil }
|
let(:channel_id) { 0 }
|
||||||
|
|
||||||
it { is_expected.to fail_to_find_a_model(:channel) }
|
it { is_expected.to fail_to_find_a_model(:channel) }
|
||||||
end
|
end
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
RSpec.describe(AdminNotices::Dismiss) do
|
RSpec.describe(AdminNotices::Dismiss) do
|
||||||
|
describe described_class::Contract, type: :model do
|
||||||
|
it { is_expected.to validate_presence_of(:id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".call" do
|
||||||
subject(:result) { described_class.call(params:, **dependencies) }
|
subject(:result) { described_class.call(params:, **dependencies) }
|
||||||
|
|
||||||
fab!(:current_user) { Fabricate(:admin) }
|
fab!(:current_user) { Fabricate(:admin) }
|
||||||
fab!(:admin_notice) { Fabricate(:admin_notice, identifier: "problem.test") }
|
fab!(:admin_notice) { Fabricate(:admin_notice, identifier: "problem.test") }
|
||||||
fab!(:problem_check) { Fabricate(:problem_check_tracker, identifier: "problem.test", blips: 3) }
|
fab!(:problem_check) { Fabricate(:problem_check_tracker, identifier: "problem.test", blips: 3) }
|
||||||
|
|
||||||
let(:params) { { id: admin_notice.id } }
|
let(:params) { { id: notice_id } }
|
||||||
|
let(:notice_id) { admin_notice.id }
|
||||||
let(:dependencies) { { guardian: current_user.guardian } }
|
let(:dependencies) { { guardian: current_user.guardian } }
|
||||||
|
|
||||||
context "when user is not allowed to perform the action" do
|
context "when user is not allowed to perform the action" do
|
||||||
@ -16,6 +22,12 @@ RSpec.describe(AdminNotices::Dismiss) do
|
|||||||
it { is_expected.to fail_a_policy(:invalid_access) }
|
it { is_expected.to fail_a_policy(:invalid_access) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when data is invalid" do
|
||||||
|
let(:notice_id) { nil }
|
||||||
|
|
||||||
|
it { is_expected.to fail_a_contract }
|
||||||
|
end
|
||||||
|
|
||||||
context "when the admin notice has already been dismissed" do
|
context "when the admin notice has already been dismissed" do
|
||||||
before { admin_notice.destroy! }
|
before { admin_notice.destroy! }
|
||||||
|
|
||||||
@ -34,3 +46,4 @@ RSpec.describe(AdminNotices::Dismiss) do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
RSpec.describe(Flags::DestroyFlag) do
|
RSpec.describe(Flags::DestroyFlag) do
|
||||||
|
describe described_class::Contract, type: :model do
|
||||||
|
it { is_expected.to validate_presence_of(:id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".call" do
|
||||||
subject(:result) { described_class.call(params:, **dependencies) }
|
subject(:result) { described_class.call(params:, **dependencies) }
|
||||||
|
|
||||||
fab!(:current_user) { Fabricate(:admin) }
|
fab!(:current_user) { Fabricate(:admin) }
|
||||||
@ -14,6 +19,12 @@ RSpec.describe(Flags::DestroyFlag) do
|
|||||||
# other examples otherwise.
|
# other examples otherwise.
|
||||||
after { flag.destroy! }
|
after { flag.destroy! }
|
||||||
|
|
||||||
|
context "when data is invalid" do
|
||||||
|
let(:flag_id) { nil }
|
||||||
|
|
||||||
|
it { is_expected.to fail_a_contract }
|
||||||
|
end
|
||||||
|
|
||||||
context "when model is not found" do
|
context "when model is not found" do
|
||||||
let(:flag_id) { 0 }
|
let(:flag_id) { 0 }
|
||||||
|
|
||||||
@ -55,3 +66,4 @@ RSpec.describe(Flags::DestroyFlag) do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user