diff --git a/plugins/chat/app/controllers/chat/api/channels_current_user_membership_controller.rb b/plugins/chat/app/controllers/chat/api/channels_current_user_membership_controller.rb index 5f1e4b2af14..3ee9ac0af07 100644 --- a/plugins/chat/app/controllers/chat/api/channels_current_user_membership_controller.rb +++ b/plugins/chat/app/controllers/chat/api/channels_current_user_membership_controller.rb @@ -12,10 +12,6 @@ class Chat::Api::ChannelsCurrentUserMembershipController < Chat::Api::ChannelsCo end def destroy - render_serialized( - channel_from_params.remove(current_user), - Chat::UserChannelMembershipSerializer, - root: "membership", - ) + with_service(Chat::LeaveChannel) { on_model_not_found(:channel) { raise Discourse::NotFound } } end end diff --git a/plugins/chat/app/controllers/chat/api/channels_current_user_membership_follows_controller.rb b/plugins/chat/app/controllers/chat/api/channels_current_user_membership_follows_controller.rb new file mode 100644 index 00000000000..cff2138e44d --- /dev/null +++ b/plugins/chat/app/controllers/chat/api/channels_current_user_membership_follows_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class Chat::Api::ChannelsCurrentUserMembershipFollowsController < Chat::Api::ChannelsController + def destroy + with_service(Chat::UnfollowChannel) do + on_success do + render_serialized( + result.membership, + Chat::UserChannelMembershipSerializer, + root: "membership", + ) + end + on_model_not_found(:channel) { raise Discourse::NotFound } + end + end +end diff --git a/plugins/chat/app/services/chat/leave_channel.rb b/plugins/chat/app/services/chat/leave_channel.rb new file mode 100644 index 00000000000..106edb651a5 --- /dev/null +++ b/plugins/chat/app/services/chat/leave_channel.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Chat + # Service responsible to flag a message. + # + # @example + # ::Chat::LeaveChannel.call( + # guardian: guardian, + # channel_id: 1, + # ) + # + class LeaveChannel + include Service::Base + + # @!method call(guardian:, channel_id:,) + # @param [Guardian] guardian + # @param [Integer] channel_id of the channel + + # @return [Service::Base::Context] + contract + model :channel + step :leave + step :recompute_users_count + + # @!visibility private + class Contract + attribute :channel_id, :integer + validates :channel_id, presence: true + end + + private + + def fetch_channel(contract:, **) + Chat::Channel.find_by(id: contract.channel_id) + end + + def leave(channel:, guardian:, **) + ActiveRecord::Base.transaction do + if channel.direct_message_channel? && channel.chatable&.group + channel.membership_for(guardian.user)&.destroy! + channel.chatable.direct_message_users.where(user_id: guardian.user.id).destroy_all + else + channel.remove(guardian.user) + end + end + 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/unfollow_channel.rb b/plugins/chat/app/services/chat/unfollow_channel.rb new file mode 100644 index 00000000000..335f1ff3a3e --- /dev/null +++ b/plugins/chat/app/services/chat/unfollow_channel.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Chat + # Service responsible to flag a message. + # + # @example + # ::Chat::UnfollowChannel.call( + # guardian: guardian, + # channel_id: 1, + # ) + # + class UnfollowChannel + include Service::Base + + # @!method call(guardian:, channel_id:,) + # @param [Guardian] guardian + # @param [Integer] channel_id of the channel + + # @return [Service::Base::Context] + contract + model :channel + step :unfollow + + # @!visibility private + class Contract + attribute :channel_id, :integer + validates :channel_id, presence: true + end + + private + + def fetch_channel(contract:, **) + Chat::Channel.find_by(id: contract.channel_id) + end + + def unfollow(channel:, guardian:, **) + context.membership = channel.remove(guardian.user) + end + end +end diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-channel-row.gjs b/plugins/chat/assets/javascripts/discourse/components/chat-channel-row.gjs index eddb3460197..f8f1d1366e5 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-channel-row.gjs +++ b/plugins/chat/assets/javascripts/discourse/components/chat-channel-row.gjs @@ -131,7 +131,7 @@ export default class ChatChannelRow extends Component { } get leaveDirectMessageLabel() { - return I18n.t("chat.direct_messages.leave"); + return I18n.t("chat.direct_messages.close"); } get leaveChannelLabel() { diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-channel-settings.gjs b/plugins/chat/assets/javascripts/discourse/components/chat-channel-settings.gjs index e102defdc54..03e20868cd8 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-channel-settings.gjs +++ b/plugins/chat/assets/javascripts/discourse/components/chat-channel-settings.gjs @@ -29,12 +29,14 @@ const NOTIFICATION_LEVELS = [ export default class ChatAboutScreen extends Component { @service chatApi; @service chatGuardian; + @service chatChannelsManager; @service currentUser; @service siteSettings; @service dialog; @service modal; @service site; @service toasts; + @service router; notificationLevels = NOTIFICATION_LEVELS; @@ -309,6 +311,12 @@ export default class ChatAboutScreen extends Component { }); } + @action + onLeaveChannel(channel) { + this.chatChannelsManager.remove(channel); + return this.router.transitionTo("chat"); + } + @action onEditChannelDescription() { return this.modal.show(ChatModalEditChannelDescription, { @@ -573,6 +581,7 @@ export default class ChatAboutScreen extends Component { <:action> { - this.onToggle?.(); + this.args.onJoin?.(this.args.channel); }) .catch(popupAjaxError) .finally(() => { @@ -67,22 +70,22 @@ export default class ToggleChannelMembershipButton extends Component { } @action - onLeaveChannel() { + async onLeaveChannel() { this.isLoading = true; - return this.chat - .unfollowChannel(this.args.channel) - .then(() => { - this.onToggle?.(); - }) - .catch(popupAjaxError) - .finally(() => { - if (this.isDestroying || this.isDestroyed) { - return; - } + try { + if (this.args.channel.chatable.group) { + await this.chatApi.leaveChannel(this.args.channel.id); + } else { + await this.chat.unfollowChannel(this.args.channel); + } - this.isLoading = false; - }); + this.args.onLeave?.(this.args.channel); + } catch (error) { + popupAjaxError(error); + } finally { + this.isLoading = false; + } }