diff --git a/app/assets/stylesheets/common/components/user-status-message.scss b/app/assets/stylesheets/common/components/user-status-message.scss index 3c2b384593d..f3107865f8c 100644 --- a/app/assets/stylesheets/common/components/user-status-message.scss +++ b/app/assets/stylesheets/common/components/user-status-message.scss @@ -1,4 +1,7 @@ [data-content][data-identifier="user-status-message-tooltip"] { + display: flex; + align-items: center; + .emoji { width: 1em; height: 1em; @@ -16,7 +19,7 @@ } .user-status-tooltip-until { - margin-top: 0.1rem; color: var(--primary-medium); + padding-left: 0.25rem; } } diff --git a/plugins/chat/app/controllers/chat/api/channels_memberships_controller.rb b/plugins/chat/app/controllers/chat/api/channels_memberships_controller.rb index d35d63df59c..a60769128e7 100644 --- a/plugins/chat/app/controllers/chat/api/channels_memberships_controller.rb +++ b/plugins/chat/app/controllers/chat/api/channels_memberships_controller.rb @@ -28,4 +28,12 @@ class Chat::Api::ChannelsMembershipsController < Chat::Api::ChannelsController }, ) end + + def create + with_service(Chat::AddUsersToChannel) do + on_failed_policy(:can_add_users_to_channel) do + render_json_error(I18n.t("chat.errors.users_cant_be_added_to_channel")) + end + end + end end diff --git a/plugins/chat/app/models/chat/category_channel.rb b/plugins/chat/app/models/chat/category_channel.rb index bf23f561cde..e23a37f1a7c 100644 --- a/plugins/chat/app/models/chat/category_channel.rb +++ b/plugins/chat/app/models/chat/category_channel.rb @@ -27,21 +27,5 @@ module Chat self.slug = Slug.for(self.title.strip, "") self.slug = "" if duplicate_slug? end - - def ensure_slug_ok - if self.slug.present? - # if we don't unescape it first we strip the % from the encoded version - slug = SiteSetting.slug_generation_method == "encoded" ? CGI.unescape(self.slug) : self.slug - self.slug = Slug.for(slug, "", method: :encoded) - - if self.slug.blank? - errors.add(:slug, :invalid) - elsif SiteSetting.slug_generation_method == "ascii" && !CGI.unescape(self.slug).ascii_only? - errors.add(:slug, I18n.t("chat.category_channel.errors.slug_contains_non_ascii_chars")) - elsif duplicate_slug? - errors.add(:slug, I18n.t("chat.category_channel.errors.is_already_in_use")) - end - end - end end end diff --git a/plugins/chat/app/models/chat/channel.rb b/plugins/chat/app/models/chat/channel.rb index 791be5b7b60..8e585bb0b09 100644 --- a/plugins/chat/app/models/chat/channel.rb +++ b/plugins/chat/app/models/chat/channel.rb @@ -27,6 +27,7 @@ module Chat class_name: "Chat::Message", foreign_key: :last_message_id, optional: true + def last_message super || NullMessage.new end @@ -109,8 +110,28 @@ module Chat %i[allowed_user_ids allowed_group_ids chatable_url].each { |name| define_method(name) { nil } } + def ensure_slug_ok + if self.slug.present? + # if we don't unescape it first we strip the % from the encoded version + slug = SiteSetting.slug_generation_method == "encoded" ? CGI.unescape(self.slug) : self.slug + self.slug = Slug.for(slug, "", method: :encoded) + + if self.slug.blank? + errors.add(:slug, :invalid) + elsif SiteSetting.slug_generation_method == "ascii" && !CGI.unescape(self.slug).ascii_only? + errors.add(:slug, I18n.t("chat.category_channel.errors.slug_contains_non_ascii_chars")) + elsif duplicate_slug? + errors.add(:slug, I18n.t("chat.category_channel.errors.is_already_in_use")) + end + end + end + def membership_for(user) - user_chat_channel_memberships.find_by(user: user) + if user_chat_channel_memberships.loaded? + user_chat_channel_memberships.detect { |m| m.user_id == user.id } + else + user_chat_channel_memberships.find_by(user: user) + end end def add(user) @@ -177,6 +198,7 @@ module Chat AND (users.suspended_till IS NULL OR users.suspended_till <= CURRENT_TIMESTAMP) AND NOT users.staged AND user_chat_channel_memberships.following + and users.id > 0 GROUP BY user_chat_channel_memberships.chat_channel_id ) subquery WHERE channels.id = subquery.chat_channel_id diff --git a/plugins/chat/app/models/chat/direct_message.rb b/plugins/chat/app/models/chat/direct_message.rb index 58fbf39d6b1..c45038e1ff8 100644 --- a/plugins/chat/app/models/chat/direct_message.rb +++ b/plugins/chat/app/models/chat/direct_message.rb @@ -19,6 +19,7 @@ module Chat def for_user_ids(user_ids) joins(:users) + .where(group: false) .group("direct_message_channels.id") .having("ARRAY[?] = ARRAY_AGG(users.id ORDER BY users.id)", user_ids.sort) .first @@ -30,6 +31,8 @@ module Chat end def chat_channel_title_for_user(chat_channel, acting_user) + return chat_channel.name if group && chat_channel.name.present? + users = (direct_message_users.map(&:user) - [acting_user]).map { |user| user || Chat::NullUser.new } @@ -66,6 +69,7 @@ end # Table name: direct_message_channels # # id :bigint not null, primary key +# group :boolean # created_at :datetime not null # updated_at :datetime not null # diff --git a/plugins/chat/app/models/chat/direct_message_channel.rb b/plugins/chat/app/models/chat/direct_message_channel.rb index 44dd3bf3bc4..30077776344 100644 --- a/plugins/chat/app/models/chat/direct_message_channel.rb +++ b/plugins/chat/app/models/chat/direct_message_channel.rb @@ -20,12 +20,8 @@ module Chat direct_message.chat_channel_title_for_user(self, user) end - def ensure_slug_ok - true - end - def generate_auto_slug - self.slug = nil + false if !self.slug.present? end end end diff --git a/plugins/chat/app/models/chat/message.rb b/plugins/chat/app/models/chat/message.rb index 8cbe3ff5d03..c3a5ea2cce8 100644 --- a/plugins/chat/app/models/chat/message.rb +++ b/plugins/chat/app/models/chat/message.rb @@ -114,7 +114,7 @@ module Chat return uploads.first.original_filename if cooked.blank? && uploads.present? # this may return blank for some complex things like quotes, that is acceptable - PrettyText.excerpt(cooked, max_length, strip_links: true) + PrettyText.excerpt(cooked, max_length, strip_links: true, keep_mentions: true) end def censored_excerpt(max_length: 50) diff --git a/plugins/chat/app/queries/chat/channel_memberships_query.rb b/plugins/chat/app/queries/chat/channel_memberships_query.rb index 294ca724c89..d2141c8eb64 100644 --- a/plugins/chat/app/queries/chat/channel_memberships_query.rb +++ b/plugins/chat/app/queries/chat/channel_memberships_query.rb @@ -7,8 +7,10 @@ module Chat Chat::UserChatChannelMembership .joins(:user) .includes(:user) - .where(user: User.activated.not_suspended.not_staged) - .where(chat_channel: channel, following: true) + .where(user: User.human_users.activated.not_suspended.not_staged) + .where(chat_channel: channel) + + query = query.where(following: true) if channel.category_channel? return query.count if count_only diff --git a/plugins/chat/app/serializers/chat/basic_user_serializer.rb b/plugins/chat/app/serializers/chat/basic_user_serializer.rb new file mode 100644 index 00000000000..8daaf74cddf --- /dev/null +++ b/plugins/chat/app/serializers/chat/basic_user_serializer.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Chat + class BasicUserSerializer < BasicUserSerializer + attributes :can_chat, :has_chat_enabled + + def can_chat + SiteSetting.chat_enabled && scope&.can_chat? + end + + def has_chat_enabled + can_chat && object.user_option&.chat_enabled + end + end +end diff --git a/plugins/chat/app/serializers/chat/channel_serializer.rb b/plugins/chat/app/serializers/chat/channel_serializer.rb index 9ed2dcde225..a6c4b87bea7 100644 --- a/plugins/chat/app/serializers/chat/channel_serializer.rb +++ b/plugins/chat/app/serializers/chat/channel_serializer.rb @@ -88,7 +88,7 @@ module Chat end def include_auto_join_users? - scope.can_edit_chat_channel? + object.category_channel? && scope.can_edit_chat_channel?(object) end def include_current_user_membership? diff --git a/plugins/chat/app/serializers/chat/direct_message_serializer.rb b/plugins/chat/app/serializers/chat/direct_message_serializer.rb index b2497c73f73..1c857ae2dd6 100644 --- a/plugins/chat/app/serializers/chat/direct_message_serializer.rb +++ b/plugins/chat/app/serializers/chat/direct_message_serializer.rb @@ -2,9 +2,9 @@ module Chat class DirectMessageSerializer < ApplicationSerializer - attributes :id + attribute :group - has_many :users, serializer: Chat::ChatableUserSerializer, embed: :objects + has_many :users, serializer: ::Chat::ChatableUserSerializer, embed: :objects def users users = object.direct_message_users.map(&:user).map { |u| u || Chat::NullUser.new } diff --git a/plugins/chat/app/serializers/chat/message_serializer.rb b/plugins/chat/app/serializers/chat/message_serializer.rb index 9c0a55a86cb..3a3c10c06be 100644 --- a/plugins/chat/app/serializers/chat/message_serializer.rb +++ b/plugins/chat/app/serializers/chat/message_serializer.rb @@ -37,7 +37,7 @@ module Chat def mentioned_users object .chat_mentions - .includes(:user) + .includes(user: :user_status) .map(&:user) .compact .sort_by(&:id) diff --git a/plugins/chat/app/serializers/chat/thread_preview_serializer.rb b/plugins/chat/app/serializers/chat/thread_preview_serializer.rb index 72f97282678..1ec04c3504f 100644 --- a/plugins/chat/app/serializers/chat/thread_preview_serializer.rb +++ b/plugins/chat/app/serializers/chat/thread_preview_serializer.rb @@ -7,8 +7,8 @@ module Chat :last_reply_id, :participant_count, :reply_count - has_many :participant_users, serializer: BasicUserSerializer, embed: :objects - has_one :last_reply_user, serializer: BasicUserSerializer, embed: :objects + has_many :participant_users, serializer: ::BasicUserSerializer, embed: :objects + has_one :last_reply_user, serializer: ::BasicUserSerializer, embed: :objects def initialize(object, opts) super(object, opts) diff --git a/plugins/chat/app/serializers/chat/user_channel_membership_serializer.rb b/plugins/chat/app/serializers/chat/user_channel_membership_serializer.rb index 8dd02a7ffa1..5abd13c372c 100644 --- a/plugins/chat/app/serializers/chat/user_channel_membership_serializer.rb +++ b/plugins/chat/app/serializers/chat/user_channel_membership_serializer.rb @@ -2,10 +2,10 @@ module Chat class UserChannelMembershipSerializer < BaseChannelMembershipSerializer - has_one :user, serializer: BasicUserSerializer, embed: :objects + has_one :user, serializer: ::Chat::BasicUserSerializer, embed: :objects def user - object.user + object.user || Chat::NullUser.new end end end diff --git a/plugins/chat/app/services/chat/add_users_to_channel.rb b/plugins/chat/app/services/chat/add_users_to_channel.rb new file mode 100644 index 00000000000..6303fbc8bd4 --- /dev/null +++ b/plugins/chat/app/services/chat/add_users_to_channel.rb @@ -0,0 +1,149 @@ +# frozen_string_literal: true + +module Chat + # Service responsible to add users to a channel. + # The guardian passed in is the "acting user" when adding users. + # The service is essentially creating memberships for the users. + # + # @example + # ::Chat::AddUsersToChannel.call( + # guardian: guardian, + # channel_id: 1, + # usernames: ["bob", "alice"] + # ) + # + class AddUsersToChannel + include Service::Base + + # @!method call(guardian:, **params_to_create) + # @param [Guardian] guardian + # @param [Integer] id of the channel + # @param [Hash] params_to_create + # @option params_to_create [Array] usernames + # @return [Service::Base::Context] + contract + model :channel + policy :can_add_users_to_channel + model :users, optional: true + + transaction do + step :upsert_memberships + step :recompute_users_count + step :notice_channel + end + + # @!visibility private + class Contract + attribute :usernames, :array + validates :usernames, presence: true + + attribute :channel_id, :integer + validates :channel_id, presence: true + + validate :usernames_length + + def usernames_length + if usernames && usernames.length > SiteSetting.chat_max_direct_message_users + 1 # 1 for current user + errors.add( + :usernames, + "should have less than #{SiteSetting.chat_max_direct_message_users} elements", + ) + end + end + end + + private + + def can_add_users_to_channel(guardian:, channel:, **) + (guardian.user.admin? || channel.joined_by?(guardian.user)) && + channel.direct_message_channel? && channel.chatable.group + end + + def fetch_users(contract:, channel:, **) + ::User.where( + "username IN (?) AND id NOT IN (?)", + [*contract.usernames], + channel.chatable.direct_message_users.select(:user_id), + ).to_a + end + + def fetch_channel(contract:, **) + ::Chat::Channel.includes(:chatable).find_by(id: contract.channel_id) + end + + def upsert_memberships(channel:, users:, **) + always_level = ::Chat::UserChatChannelMembership::NOTIFICATION_LEVELS[:always] + + memberships = + users.map do |user| + { + user_id: user.id, + chat_channel_id: channel.id, + muted: false, + following: true, + desktop_notification_level: always_level, + mobile_notification_level: always_level, + created_at: Time.zone.now, + updated_at: Time.zone.now, + } + end + + if memberships.blank? + context.added_user_ids = [] + return + end + + context.added_user_ids = + ::Chat::UserChatChannelMembership + .upsert_all( + memberships, + unique_by: %i[user_id chat_channel_id], + returning: Arel.sql("user_id, (xmax = '0') as inserted"), + ) + .select { |row| row["inserted"] } + .map { |row| row["user_id"] } + + ::Chat::DirectMessageUser.upsert_all( + context.added_user_ids.map do |id| + { + user_id: id, + direct_message_channel_id: channel.chatable.id, + created_at: Time.zone.now, + updated_at: Time.zone.now, + } + end, + unique_by: %i[direct_message_channel_id user_id], + ) + end + + def recompute_users_count(channel:, **) + return if context.added_user_ids.blank? + + channel.update!( + user_count: ::Chat::ChannelMembershipsQuery.count(channel), + user_count_stale: false, + ) + end + + def notice_channel(guardian:, channel:, users:, **) + added_users = users.select { |u| context.added_user_ids.include?(u.id) } + + return if added_users.blank? + + result = + ::Chat::CreateMessage.call( + guardian: Discourse.system_user.guardian, + chat_channel_id: channel.id, + message: + I18n.t( + "chat.channel.users_invited_to_channel", + invited_users: added_users.map { |u| "@#{u.username}" }.join(", "), + inviting_user: "@#{guardian.user.username}", + count: added_users.count, + ), + ) + + fail!(failure: "Failed to notice the channel") if result.failure? + end + end +end diff --git a/plugins/chat/app/services/chat/create_direct_message_channel.rb b/plugins/chat/app/services/chat/create_direct_message_channel.rb index 1b5600bcf53..8ce61377ed2 100644 --- a/plugins/chat/app/services/chat/create_direct_message_channel.rb +++ b/plugins/chat/app/services/chat/create_direct_message_channel.rb @@ -7,7 +7,7 @@ module Chat # are passed in. # # @example - # Service::Chat::CreateDirectMessageChannel.call( + # ::Chat::CreateDirectMessageChannel.call( # guardian: guardian, # target_usernames: ["bob", "alice"] # ) @@ -32,10 +32,13 @@ module Chat class_name: Chat::DirectMessageChannel::CanCommunicateAllPartiesPolicy model :direct_message, :fetch_or_create_direct_message model :channel, :fetch_or_create_channel + step :set_optional_name step :update_memberships + step :recompute_users_count # @!visibility private class Contract + attribute :name, :string attribute :target_usernames, :array validates :target_usernames, presence: true end @@ -58,17 +61,26 @@ module Chat !user_comm_screener.actor_disallowing_all_pms? end - def fetch_or_create_direct_message(target_users:, **) - Chat::DirectMessage.for_user_ids(target_users.map(&:id)) || - Chat::DirectMessage.create(user_ids: target_users.map(&:id)) + def fetch_or_create_direct_message(target_users:, contract:, **) + ids = target_users.map(&:id) + + if ids.size > 2 || contract.name.present? + ::Chat::DirectMessage.create(user_ids: ids, group: true) + else + ::Chat::DirectMessage.for_user_ids(ids) || ::Chat::DirectMessage.create(user_ids: ids) + end end def fetch_or_create_channel(direct_message:, **) - Chat::DirectMessageChannel.find_or_create_by(chatable: direct_message) + ::Chat::DirectMessageChannel.find_or_create_by(chatable: direct_message) + end + + def set_optional_name(channel:, contract:, **) + channel.update!(name: contract.name) if contract.name&.length&.positive? end def update_memberships(channel:, target_users:, **) - always_level = Chat::UserChatChannelMembership::NOTIFICATION_LEVELS[:always] + always_level = ::Chat::UserChatChannelMembership::NOTIFICATION_LEVELS[:always] memberships = target_users.map do |user| @@ -84,10 +96,17 @@ module Chat } end - Chat::UserChatChannelMembership.upsert_all( + ::Chat::UserChatChannelMembership.upsert_all( memberships, unique_by: %i[user_id chat_channel_id], ) end + + def recompute_users_count(channel:, **) + channel.update!( + user_count: ::Chat::ChannelMembershipsQuery.count(channel), + user_count_stale: false, + ) + end end end diff --git a/plugins/chat/app/services/chat/create_message.rb b/plugins/chat/app/services/chat/create_message.rb index 51e14ddf01e..4adcdae34d8 100644 --- a/plugins/chat/app/services/chat/create_message.rb +++ b/plugins/chat/app/services/chat/create_message.rb @@ -22,9 +22,9 @@ module Chat policy :no_silenced_user contract model :channel + step :enforce_system_membership policy :allowed_to_join_channel policy :allowed_to_create_message_in_channel, class_name: Chat::Channel::MessageCreationPolicy - step :enforce_system_membership model :channel_membership model :reply, optional: true policy :ensure_reply_consistency @@ -76,7 +76,13 @@ module Chat end def enforce_system_membership(guardian:, channel:, **) - channel.add(guardian.user) if guardian.user.is_system_user? + if guardian.user&.is_system_user? + channel.add(guardian.user) + + if channel.direct_message_channel? + channel.chatable.direct_message_users.find_or_create_by!(user: guardian.user) + end + end end def fetch_channel_membership(guardian:, channel:, **) diff --git a/plugins/chat/app/services/chat/list_channel_messages.rb b/plugins/chat/app/services/chat/list_channel_messages.rb index affcfabbe07..7fd4f2093f5 100644 --- a/plugins/chat/app/services/chat/list_channel_messages.rb +++ b/plugins/chat/app/services/chat/list_channel_messages.rb @@ -59,7 +59,7 @@ module Chat private def fetch_channel(contract:, **) - ::Chat::Channel.strict_loading.includes(:chatable).find_by(id: contract.channel_id) + ::Chat::Channel.includes(:chatable).find_by(id: contract.channel_id) end def fetch_optional_membership(channel:, guardian:, **) diff --git a/plugins/chat/app/services/chat/search_chatable.rb b/plugins/chat/app/services/chat/search_chatable.rb index d0edb6435dd..30e45541d64 100644 --- a/plugins/chat/app/services/chat/search_chatable.rb +++ b/plugins/chat/app/services/chat/search_chatable.rb @@ -15,78 +15,65 @@ module Chat # @return [Service::Base::Context] contract - step :set_mode step :clean_term - step :fetch_memberships - step :fetch_users - step :fetch_category_channels - step :fetch_direct_message_channels + model :memberships, optional: true + model :users, optional: true + model :category_channels, optional: true + model :direct_message_channels, optional: true # @!visibility private class Contract - attribute :term, default: "" + attribute :term, :string, default: "" + attribute :include_users, :boolean, default: true + attribute :include_category_channels, :boolean, default: true + attribute :include_direct_message_channels, :boolean, default: true + attribute :excluded_memberships_channel_id, :integer end private - def set_mode - context.mode = - if context.contract.term&.start_with?("#") - :channel - elsif context.contract.term&.start_with?("@") - :user - else - :all - end - end - def clean_term(contract:, **) context.term = contract.term.downcase&.gsub(/^#+/, "")&.gsub(/^@+/, "")&.strip end def fetch_memberships(guardian:, **) - context.memberships = ::Chat::ChannelMembershipManager.all_for_user(guardian.user) + ::Chat::ChannelMembershipManager.all_for_user(guardian.user) end - def fetch_users(guardian:, **) + def fetch_users(guardian:, contract:, **) + return unless contract.include_users return unless guardian.can_create_direct_message? - return if context.mode == :channel - context.users = search_users(context.term, guardian) + search_users(context, guardian, contract) end - def fetch_category_channels(guardian:, **) - return if context.mode == :user + def fetch_category_channels(guardian:, contract:, **) + return unless contract.include_category_channels return if !SiteSetting.enable_public_channels - context.category_channels = - ::Chat::ChannelFetcher.secured_public_channel_search( - guardian, - filter_on_category_name: false, - match_filter_on_starts_with: false, - filter: context.term, - status: :open, - limit: 10, - ) + ::Chat::ChannelFetcher.secured_public_channel_search( + guardian, + filter_on_category_name: false, + match_filter_on_starts_with: false, + filter: context.term, + status: :open, + limit: 10, + ) end - def fetch_direct_message_channels(guardian:, **args) - return if context.mode == :user - - user_ids = nil - if context.term.length > 0 - user_ids = - (context.users.nil? ? search_users(context.term, guardian) : context.users).map(&:id) - end + def fetch_direct_message_channels(guardian:, users:, contract:, **args) + return unless contract.include_direct_message_channels channels = ::Chat::ChannelFetcher.secured_direct_message_channels_search( guardian.user.id, guardian, limit: 10, - user_ids: user_ids, + match_filter_on_starts_with: false, + filter: context.term, ) || [] - if user_ids.present? && context.mode == :all + if users && contract.include_users + user_ids = users.map(&:id) channels = channels.reject do |channel| channel_user_ids = channel.allowed_user_ids - [guardian.user.id] @@ -96,17 +83,31 @@ module Chat end end - context.direct_message_channels = channels + channels end - def search_users(term, guardian) - user_search = ::UserSearch.new(term, limit: 10) + def search_users(context, guardian, contract) + user_search = ::UserSearch.new(context.term, limit: 10) - if term.blank? - user_search.scoped_users.includes(:user_option) + if context.term.blank? + user_search = user_search.scoped_users.real.includes(:user_option) else - user_search.search.includes(:user_option) + user_search = user_search.search.real.includes(:user_option) end + + if context.excluded_memberships_channel_id + user_search = + user_search.where( + "NOT EXISTS ( + SELECT 1 + FROM user_chat_channel_memberships + WHERE user_chat_channel_memberships.user_id = users.id AND user_chat_channel_memberships.chat_channel_id = ? + )", + context.excluded_memberships_channel_id, + ) + end + + user_search end end end diff --git a/plugins/chat/app/services/chat/update_channel.rb b/plugins/chat/app/services/chat/update_channel.rb index fdd7cd5f85e..6960fe44236 100644 --- a/plugins/chat/app/services/chat/update_channel.rb +++ b/plugins/chat/app/services/chat/update_channel.rb @@ -7,7 +7,7 @@ module Chat # and threading_enabled are also editable. # # @example - # Service::Chat::UpdateChannel.call( + # ::Chat::UpdateChannel.call( # channel_id: 2, # guardian: guardian, # name: "SuperChannel", @@ -26,13 +26,13 @@ module Chat # @option params_to_edit [String,nil] name # @option params_to_edit [String,nil] description # @option params_to_edit [String,nil] slug + # @option params_to_edit [Boolean] threading_enabled # @option params_to_edit [Boolean] auto_join_users Only valid for {CategoryChannel}. Whether active users # with permission to see the category should automatically join the channel. # @option params_to_edit [Boolean] allow_channel_wide_mentions Allow the use of @here and @all in the channel. # @return [Service::Base::Context] model :channel, :fetch_channel - policy :no_direct_message_channel policy :check_channel_permission contract default_values_from: :channel step :update_channel @@ -62,12 +62,8 @@ module Chat Chat::Channel.find_by(id: channel_id) end - def no_direct_message_channel(channel:, **) - !channel.direct_message_channel? - end - def check_channel_permission(guardian:, channel:, **) - guardian.can_preview_chat_channel?(channel) && guardian.can_edit_chat_channel? + guardian.can_preview_chat_channel?(channel) && guardian.can_edit_chat_channel?(channel) end def update_channel(channel:, contract:, **) diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-channel-info.gjs b/plugins/chat/assets/javascripts/discourse/components/chat-channel-info.gjs index e3f63cfe966..3bc5690ee73 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-channel-info.gjs +++ b/plugins/chat/assets/javascripts/discourse/components/chat-channel-info.gjs @@ -1,14 +1,19 @@ import Component from "@glimmer/component"; +import { action } from "@ember/object"; import { LinkTo } from "@ember/routing"; import { inject as service } from "@ember/service"; +import DButton from "discourse/components/d-button"; import icon from "discourse-common/helpers/d-icon"; import I18n from "discourse-i18n"; +import ChatModalEditChannelName from "discourse/plugins/chat/discourse/components/chat/modal/edit-channel-name"; import ChatChannelStatus from "discourse/plugins/chat/discourse/components/chat-channel-status"; import ChatChannelTitle from "discourse/plugins/chat/discourse/components/chat-channel-title"; export default class ChatChannelMessageEmojiPicker extends Component { @service chatChannelInfoRouteOriginManager; @service site; + @service modal; + @service chatGuardian; membersLabel = I18n.t("chat.channel_info.tabs.members"); settingsLabel = I18n.t("chat.channel_info.tabs.settings"); @@ -16,13 +21,25 @@ export default class ChatChannelMessageEmojiPicker extends Component { backToAllChannelsLabel = I18n.t("chat.channel_info.back_to_channel"); get showTabs() { + return this.site.desktopView && this.args.channel.isOpen; + } + + get canEditChannel() { return ( - this.site.desktopView && - this.args.channel.membershipsCount > 1 && - this.args.channel.isOpen + this.chatGuardian.canEditChatChannel() && + (this.args.channel.isCategoryChannel || + (this.args.channel.isDirectMessageChannel && + this.args.channel.chatable.group)) ); } + @action + editChannelTitle() { + return this.modal.show(ChatModalEditChannelName, { + model: this.args.channel, + }); + } +