Skip to content
This repository has been archived by the owner on Feb 6, 2023. It is now read-only.

FEATURE: allows to unfollow direct message channel #402

Merged
merged 5 commits into from Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/controllers/chat_controller.rb
Expand Up @@ -108,6 +108,12 @@ def create_message
@user_chat_channel_membership.update(
last_read_message_id: chat_message_creator.chat_message.id
)

if @chat_channel.direct_message_channel?
@chat_channel.user_chat_channel_memberships.update_all(following: true)
ChatPublisher.publish_new_direct_message_channel(@chat_channel, @chat_channel.chatable.users)
end

ChatPublisher.publish_user_tracking_state(
current_user,
@chat_channel.id,
Expand Down
11 changes: 1 addition & 10 deletions app/controllers/direct_messages_controller.rb
Expand Up @@ -7,16 +7,7 @@ def create

users = [current_user]
users.concat(User.where(username: params[:usernames].split(",")).to_a) if current_user.username != params[:usernames]
user_ids = users.map(&:id).uniq

direct_messages_channel = DirectMessageChannel.for_user_ids(user_ids)
if direct_messages_channel
chat_channel = ChatChannel.find_by(chatable: direct_messages_channel)
else
chat_channel = DiscourseChat::DirectMessageChannelCreator.create(users)
ChatPublisher.publish_new_direct_message_channel(chat_channel, users)
end

chat_channel = DiscourseChat::DirectMessageChannelCreator.create!(users)
render_serialized(chat_channel, ChatChannelSerializer, root: "chat_channel")
end
end
1 change: 0 additions & 1 deletion app/models/user_chat_channel_membership.rb
Expand Up @@ -27,7 +27,6 @@ class UserChatChannelMembership < ActiveRecord::Base
def changes_for_direct_message_channels
needs_validation = VALIDATED_ATTRS.any? { |attr| changed_attribute_names_to_save.include?(attr.to_s) }
if needs_validation && chat_channel.direct_message_channel?
errors.add(:following) if !following
errors.add(:muted) if muted
errors.add(:desktop_notification_level) if desktop_notification_level.to_sym != :always
errors.add(:mobile_notification_level) if mobile_notification_level.to_sym != :always
Expand Down
15 changes: 15 additions & 0 deletions assets/javascripts/discourse/components/chat-channel-row.js
@@ -1,14 +1,18 @@
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";
import getURL from "discourse-common/lib/get-url";
import { equal } from "@ember/object/computed";
import { inject as service } from "@ember/service";
import { action } from "@ember/object";

export default Component.extend({
channel: null,
switchChannel: null,
isDirectMessageRow: equal("channel.chatable_type", "DirectMessageChannel"),
router: service(),
chat: service(),

@discourseComputed("active", "channel.muted")
rowClassNames(active, muted) {
Expand Down Expand Up @@ -62,4 +66,15 @@ export default Component.extend({
hasUnread(trackingState) {
return trackingState[this.channel.id]?.unread_count || 0;
},

@action
leaveChatChannel() {
return ajax(`/chat/chat_channels/${this.channel.id}/unfollow`, {
method: "POST",
})
.then(() => {
this.chat.stopTrackingChannel(this.channel);
})
.catch(popupAjaxError);
},
});
Expand Up @@ -3,4 +3,13 @@
{{#if hasUnread}}
<span class={{unreadIndicatorClassName}}></span>
{{/if}}

{{#if isDirectMessageRow}}
{{d-button
icon="times"
action=(action "leaveChatChannel")
class="btn-flat leave-channel-btn"
title="chat.direct_messages.leave"
}}
{{/if}}
</div>
12 changes: 12 additions & 0 deletions assets/stylesheets/common/common.scss
Expand Up @@ -1164,6 +1164,18 @@ body.composer-open .topic-chat-floar-container {
cursor: pointer;
color: var(--primary-high);

.leave-channel-btn {
margin-left: auto;
background: none;
visibility: hidden;
}

&:hover {
.leave-channel-btn {
visibility: visible;
}
}

&:hover,
&.active {
background: var(--primary-low);
Expand Down
1 change: 1 addition & 0 deletions config/locales/client.en.yml
Expand Up @@ -132,6 +132,7 @@ en:
title: "Personal chat"
new: "New personal chat"
create: "Go"
leave: "Leave this personal chat"

incoming_webhooks:
back: "Back"
Expand Down
40 changes: 27 additions & 13 deletions lib/direct_message_channel_creator.rb
Expand Up @@ -3,21 +3,35 @@
module DiscourseChat::DirectMessageChannelCreator
attr_reader :chat_channel, :users

def self.create(users)
direct_messages_channel = DirectMessageChannel.create!(users: users)
chat_channel = ChatChannel.create!(chatable: direct_messages_channel)
users.each do |user|
UserChatChannelMembership.create(
user_id: user.id,
chat_channel_id: chat_channel.id,
last_read_message_id: nil,
following: true,
muted: false,
desktop_notification_level: UserChatChannelMembership::NOTIFICATION_LEVELS[:always],
mobile_notification_level: UserChatChannelMembership::NOTIFICATION_LEVELS[:always],
)
def self.create!(users)
direct_messages_channel = DirectMessageChannel.for_user_ids(users.map(&:id).uniq)
unless direct_messages_channel
direct_messages_channel = DirectMessageChannel.create!(users: users)
chat_channel = ChatChannel.create!(chatable: direct_messages_channel)
else
jjaffeux marked this conversation as resolved.
Show resolved Hide resolved
chat_channel = ChatChannel.find_by!(chatable_id: direct_messages_channel.id)
end

update_memberships(users, chat_channel.id)
ChatPublisher.publish_new_direct_message_channel(chat_channel, users)
chat_channel
end

private

def self.update_memberships(users, chat_channel_id)
users.each do |user|
membership = UserChatChannelMembership.find_or_initialize_by(user_id: user.id, chat_channel_id: chat_channel_id)

if membership.new_record?
membership.last_read_message_id = nil
membership.desktop_notification_level = UserChatChannelMembership::NOTIFICATION_LEVELS[:always]
membership.mobile_notification_level = UserChatChannelMembership::NOTIFICATION_LEVELS[:always]
membership.muted = false
end

membership.following = true
membership.save!
end
end
end
2 changes: 1 addition & 1 deletion spec/components/chat_message_creator_spec.rb
Expand Up @@ -20,7 +20,7 @@
[admin1, admin2, user1, user2, user3].each do |user|
Fabricate(:user_chat_channel_membership, chat_channel: public_chat_channel, user: user)
end
@direct_message_channel = DiscourseChat::DirectMessageChannelCreator.create([user1, user2])
@direct_message_channel = DiscourseChat::DirectMessageChannelCreator.create!([user1, user2])
end

describe "Integration tests with jobs running immediately" do
Expand Down
2 changes: 1 addition & 1 deletion spec/components/chat_message_updater_spec.rb
Expand Up @@ -20,7 +20,7 @@
[admin1, admin2, user1, user2, user3, user4].each do |user|
Fabricate(:user_chat_channel_membership, chat_channel: public_chat_channel, user: user)
end
@direct_message_channel = DiscourseChat::DirectMessageChannelCreator.create([user1, user2])
@direct_message_channel = DiscourseChat::DirectMessageChannelCreator.create!([user1, user2])
end

def create_chat_message(user, message, channel, upload_ids: nil)
Expand Down
26 changes: 26 additions & 0 deletions spec/lib/direct_message_channel_creator_spec.rb
@@ -0,0 +1,26 @@
# frozen_string_literal: true

require 'rails_helper'

describe DiscourseChat::DirectMessageChannelCreator do
fab!(:user_1) { Fabricate(:user) }
fab!(:user_2) { Fabricate(:user) }

context 'existing direct message channel' do
fab!(:dm_chat_channel) { Fabricate(:chat_channel, chatable: Fabricate(:direct_message_channel, users: [user_1, user_2])) }

it 'doesn’t create a new chat channel' do
expect {
subject.create!([user_1, user_2])
}.to change { ChatChannel.count }.by(0)
end
end

context 'non existing direct message channel' do
it 'creates a new chat channel' do
expect {
subject.create!([user_1, user_2])
}.to change { ChatChannel.count }.by(1)
end
end
end
14 changes: 7 additions & 7 deletions spec/requests/chat_channel_controller_spec.rb
Expand Up @@ -136,10 +136,10 @@
fab!(:user3) { Fabricate(:user) }

before do
@dm1 = DiscourseChat::DirectMessageChannelCreator.create([user1, user2])
@dm2 = DiscourseChat::DirectMessageChannelCreator.create([user1, user3])
@dm3 = DiscourseChat::DirectMessageChannelCreator.create([user1, user2, user3])
@dm4 = DiscourseChat::DirectMessageChannelCreator.create([user2, user3])
@dm1 = DiscourseChat::DirectMessageChannelCreator.create!([user1, user2])
@dm2 = DiscourseChat::DirectMessageChannelCreator.create!([user1, user3])
@dm3 = DiscourseChat::DirectMessageChannelCreator.create!([user1, user2, user3])
@dm4 = DiscourseChat::DirectMessageChannelCreator.create!([user2, user3])
end

it "returns correct DMs for user1" do
Expand Down Expand Up @@ -226,7 +226,7 @@
expect(response.status).to eq(200)
end

it "errors when you try to unfollow a direct_message_channel" do
it "allows to unfollow a direct_message_channel" do
sign_in(user)
membership_record = UserChatChannelMembership.create!(
chat_channel_id: dm_chat_channel.id,
Expand All @@ -237,8 +237,8 @@
)

post "/chat/chat_channels/#{dm_chat_channel.id}/unfollow.json"
expect(response.status).to eq(422)
expect(membership_record.reload.following).to eq(true)
expect(response.status).to eq(200)
expect(membership_record.reload.following).to eq(false)
end
end

Expand Down
21 changes: 21 additions & 0 deletions spec/requests/chat_controller_spec.rb
Expand Up @@ -185,6 +185,27 @@
expect(ChatMessage.last.message).to eq(message)
end
end

describe 'for direct message' do
fab!(:user1) { Fabricate(:user) }
fab!(:user2) { Fabricate(:user) }
fab!(:chatable) { Fabricate(:direct_message_channel, users: [user1, user2]) }
fab!(:direct_message_channel) { Fabricate(:chat_channel, chatable: chatable) }

it 'forces users to follow the channel' do
UserChatChannelMembership.create!(user: user1, chat_channel: direct_message_channel, following: true, desktop_notification_level: UserChatChannelMembership::NOTIFICATION_LEVELS[:always], mobile_notification_level: UserChatChannelMembership::NOTIFICATION_LEVELS[:always])
UserChatChannelMembership.create!(user: user2, chat_channel: direct_message_channel, following: false, desktop_notification_level: UserChatChannelMembership::NOTIFICATION_LEVELS[:always], mobile_notification_level: UserChatChannelMembership::NOTIFICATION_LEVELS[:always])

expect(UserChatChannelMembership.find_by(user_id: user2.id).following).to eq(false)

ChatPublisher.expects(:publish_new_direct_message_channel).once

sign_in(user1)
post "/chat/#{direct_message_channel.id}.json", params: { message: message }

expect(UserChatChannelMembership.find_by(user_id: user2.id).following).to eq(true)
end
end
end

describe "#edit_message" do
Expand Down