2022-11-02 21:41:30 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:chat_channel, class_name: "Chat::Channel") do
|
2022-11-02 21:41:30 +08:00
|
|
|
name do
|
2022-11-09 08:28:31 +08:00
|
|
|
sequence(:name) do |n|
|
|
|
|
random_name = [
|
|
|
|
"Gaming Lounge",
|
|
|
|
"Music Lodge",
|
|
|
|
"Random",
|
|
|
|
"Politics",
|
|
|
|
"Sports Center",
|
|
|
|
"Kino Buffs",
|
|
|
|
].sample
|
|
|
|
"#{random_name} #{n}"
|
|
|
|
end
|
2022-11-02 21:41:30 +08:00
|
|
|
end
|
|
|
|
chatable { Fabricate(:category) }
|
2022-11-09 08:28:31 +08:00
|
|
|
type do |attrs|
|
2023-12-07 06:25:00 +08:00
|
|
|
if attrs[:chatable_type] == "Category" || attrs[:chatable].is_a?(Category)
|
DEV: start glimmer-ification and optimisations of chat plugin (#19531)
Note this is a very large PR, and some of it could have been splited, but keeping it one chunk made it to merge conflicts and to revert if necessary. Actual new code logic is also not that much, as most of the changes are removing js tests, adding system specs or moving things around.
To make it possible this commit is doing the following changes:
- converting (and adding new) existing js acceptances tests into system tests. This change was necessary to ensure as little regressions as possible while changing paradigm
- moving away from store. Using glimmer and tracked properties requires to have class objects everywhere and as a result works well with models. However store/adapters are suffering from many bugs and limitations. As a workaround the `chat-api` and `chat-channels-manager` are an answer to this problem by encapsulating backend calls and frontend storage logic; while still using js models.
- dropping `appEvents` as much as possible. Using tracked properties and a better local storage of channel models, allows to be much more reactive and doesn’t require arbitrary manual updates everywhere in the app.
- while working on replacing store, the existing work of a chat api (backend) has been continued to support more cases.
- removing code from the `chat` service to separate concerns, `chat-subscriptions-manager` and `chat-channels-manager`, being the largest examples of where the code has been rewritten/moved.
Future wok:
- improve behavior when closing/deleting a channel, it's already slightly buggy on live, it's rare enough that it's not a big issue, but should be improved
- improve page objects used in chat
- move more endpoints to the API
- finish temporarily skipped tests
- extract more code from the `chat` service
- use glimmer for `chat-messages`
- separate concerns in `chat-live-pane`
- eventually add js tests for `chat-api`, `chat-channels-manager` and `chat-subscriptions-manager`, they are indirectly heavy tested through system tests but it would be nice to at least test the public API
<!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in JavaScript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
2022-12-21 20:21:02 +08:00
|
|
|
"CategoryChannel"
|
|
|
|
else
|
|
|
|
"DirectMessageChannel"
|
|
|
|
end
|
2022-11-09 08:28:31 +08:00
|
|
|
end
|
2022-11-02 21:41:30 +08:00
|
|
|
status { :open }
|
|
|
|
end
|
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:category_channel, from: :chat_channel) {}
|
2022-11-02 21:41:30 +08:00
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:private_category_channel, from: :category_channel) do
|
DEV: start glimmer-ification and optimisations of chat plugin (#19531)
Note this is a very large PR, and some of it could have been splited, but keeping it one chunk made it to merge conflicts and to revert if necessary. Actual new code logic is also not that much, as most of the changes are removing js tests, adding system specs or moving things around.
To make it possible this commit is doing the following changes:
- converting (and adding new) existing js acceptances tests into system tests. This change was necessary to ensure as little regressions as possible while changing paradigm
- moving away from store. Using glimmer and tracked properties requires to have class objects everywhere and as a result works well with models. However store/adapters are suffering from many bugs and limitations. As a workaround the `chat-api` and `chat-channels-manager` are an answer to this problem by encapsulating backend calls and frontend storage logic; while still using js models.
- dropping `appEvents` as much as possible. Using tracked properties and a better local storage of channel models, allows to be much more reactive and doesn’t require arbitrary manual updates everywhere in the app.
- while working on replacing store, the existing work of a chat api (backend) has been continued to support more cases.
- removing code from the `chat` service to separate concerns, `chat-subscriptions-manager` and `chat-channels-manager`, being the largest examples of where the code has been rewritten/moved.
Future wok:
- improve behavior when closing/deleting a channel, it's already slightly buggy on live, it's rare enough that it's not a big issue, but should be improved
- improve page objects used in chat
- move more endpoints to the API
- finish temporarily skipped tests
- extract more code from the `chat` service
- use glimmer for `chat-messages`
- separate concerns in `chat-live-pane`
- eventually add js tests for `chat-api`, `chat-channels-manager` and `chat-subscriptions-manager`, they are indirectly heavy tested through system tests but it would be nice to at least test the public API
<!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in JavaScript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
2022-12-21 20:21:02 +08:00
|
|
|
transient :group
|
|
|
|
chatable { |attrs| Fabricate(:private_category, group: attrs[:group] || Group[:staff]) }
|
|
|
|
end
|
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:direct_message_channel, from: :chat_channel) do
|
2023-11-10 18:29:28 +08:00
|
|
|
transient :users, :group, following: true, with_membership: true
|
2022-11-02 21:41:30 +08:00
|
|
|
chatable do |attrs|
|
2023-11-10 18:29:28 +08:00
|
|
|
Fabricate(
|
|
|
|
:direct_message,
|
|
|
|
users: attrs[:users] || [Fabricate(:user), Fabricate(:user)],
|
|
|
|
group: attrs[:group] || false,
|
|
|
|
)
|
2022-11-02 21:41:30 +08:00
|
|
|
end
|
|
|
|
status { :open }
|
DEV: start glimmer-ification and optimisations of chat plugin (#19531)
Note this is a very large PR, and some of it could have been splited, but keeping it one chunk made it to merge conflicts and to revert if necessary. Actual new code logic is also not that much, as most of the changes are removing js tests, adding system specs or moving things around.
To make it possible this commit is doing the following changes:
- converting (and adding new) existing js acceptances tests into system tests. This change was necessary to ensure as little regressions as possible while changing paradigm
- moving away from store. Using glimmer and tracked properties requires to have class objects everywhere and as a result works well with models. However store/adapters are suffering from many bugs and limitations. As a workaround the `chat-api` and `chat-channels-manager` are an answer to this problem by encapsulating backend calls and frontend storage logic; while still using js models.
- dropping `appEvents` as much as possible. Using tracked properties and a better local storage of channel models, allows to be much more reactive and doesn’t require arbitrary manual updates everywhere in the app.
- while working on replacing store, the existing work of a chat api (backend) has been continued to support more cases.
- removing code from the `chat` service to separate concerns, `chat-subscriptions-manager` and `chat-channels-manager`, being the largest examples of where the code has been rewritten/moved.
Future wok:
- improve behavior when closing/deleting a channel, it's already slightly buggy on live, it's rare enough that it's not a big issue, but should be improved
- improve page objects used in chat
- move more endpoints to the API
- finish temporarily skipped tests
- extract more code from the `chat` service
- use glimmer for `chat-messages`
- separate concerns in `chat-live-pane`
- eventually add js tests for `chat-api`, `chat-channels-manager` and `chat-subscriptions-manager`, they are indirectly heavy tested through system tests but it would be nice to at least test the public API
<!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in JavaScript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
2022-12-21 20:21:02 +08:00
|
|
|
name nil
|
2024-10-11 17:05:07 +08:00
|
|
|
threading_enabled true
|
DEV: start glimmer-ification and optimisations of chat plugin (#19531)
Note this is a very large PR, and some of it could have been splited, but keeping it one chunk made it to merge conflicts and to revert if necessary. Actual new code logic is also not that much, as most of the changes are removing js tests, adding system specs or moving things around.
To make it possible this commit is doing the following changes:
- converting (and adding new) existing js acceptances tests into system tests. This change was necessary to ensure as little regressions as possible while changing paradigm
- moving away from store. Using glimmer and tracked properties requires to have class objects everywhere and as a result works well with models. However store/adapters are suffering from many bugs and limitations. As a workaround the `chat-api` and `chat-channels-manager` are an answer to this problem by encapsulating backend calls and frontend storage logic; while still using js models.
- dropping `appEvents` as much as possible. Using tracked properties and a better local storage of channel models, allows to be much more reactive and doesn’t require arbitrary manual updates everywhere in the app.
- while working on replacing store, the existing work of a chat api (backend) has been continued to support more cases.
- removing code from the `chat` service to separate concerns, `chat-subscriptions-manager` and `chat-channels-manager`, being the largest examples of where the code has been rewritten/moved.
Future wok:
- improve behavior when closing/deleting a channel, it's already slightly buggy on live, it's rare enough that it's not a big issue, but should be improved
- improve page objects used in chat
- move more endpoints to the API
- finish temporarily skipped tests
- extract more code from the `chat` service
- use glimmer for `chat-messages`
- separate concerns in `chat-live-pane`
- eventually add js tests for `chat-api`, `chat-channels-manager` and `chat-subscriptions-manager`, they are indirectly heavy tested through system tests but it would be nice to at least test the public API
<!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in JavaScript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
2022-12-21 20:21:02 +08:00
|
|
|
after_create do |channel, attrs|
|
|
|
|
if attrs[:with_membership]
|
|
|
|
channel.chatable.users.each do |user|
|
|
|
|
membership = channel.add(user)
|
|
|
|
membership.update!(following: false) if attrs[:following] == false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2022-11-02 21:41:30 +08:00
|
|
|
end
|
|
|
|
|
2023-08-24 21:22:51 +08:00
|
|
|
Fabricator(:chat_message, class_name: "Chat::Message") do
|
|
|
|
transient use_service: false
|
|
|
|
|
|
|
|
initialize_with do |transients|
|
|
|
|
Fabricate(
|
2023-09-07 14:57:29 +08:00
|
|
|
transients[:use_service] ? :chat_message_with_service : :chat_message_without_service,
|
2023-08-24 21:22:51 +08:00
|
|
|
**to_params,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-09-07 14:57:29 +08:00
|
|
|
Fabricator(:chat_message_without_service, class_name: "Chat::Message") do
|
2023-08-24 21:22:51 +08:00
|
|
|
user
|
|
|
|
chat_channel
|
2023-11-13 21:54:26 +08:00
|
|
|
message { Faker::Alphanumeric.alpha(number: SiteSetting.chat_minimum_message_length) }
|
2023-08-24 21:22:51 +08:00
|
|
|
|
|
|
|
after_build { |message, attrs| message.cook }
|
2023-11-06 22:45:30 +08:00
|
|
|
after_create { |message, attrs| message.upsert_mentions }
|
2023-08-24 21:22:51 +08:00
|
|
|
end
|
|
|
|
|
2023-09-07 14:57:29 +08:00
|
|
|
Fabricator(:chat_message_with_service, class_name: "Chat::CreateMessage") do
|
|
|
|
transient :chat_channel,
|
|
|
|
:user,
|
|
|
|
:message,
|
|
|
|
:in_reply_to,
|
|
|
|
:thread,
|
|
|
|
:upload_ids,
|
|
|
|
:incoming_chat_webhook
|
2023-05-17 23:49:52 +08:00
|
|
|
|
|
|
|
initialize_with do |transients|
|
|
|
|
channel =
|
|
|
|
transients[:chat_channel] || transients[:thread]&.channel ||
|
|
|
|
transients[:in_reply_to]&.chat_channel || Fabricate(:chat_channel)
|
2023-08-24 21:22:51 +08:00
|
|
|
user = transients[:user] || Fabricate(:user)
|
|
|
|
Group.refresh_automatic_groups!
|
|
|
|
channel.add(user)
|
2023-05-17 23:49:52 +08:00
|
|
|
|
2023-11-06 22:45:30 +08:00
|
|
|
result =
|
|
|
|
resolved_class.call(
|
|
|
|
chat_channel_id: channel.id,
|
|
|
|
guardian: user.guardian,
|
2023-11-13 21:54:26 +08:00
|
|
|
message:
|
|
|
|
transients[:message] ||
|
|
|
|
Faker::Alphanumeric.alpha(number: SiteSetting.chat_minimum_message_length),
|
2023-11-06 22:45:30 +08:00
|
|
|
thread_id: transients[:thread]&.id,
|
|
|
|
in_reply_to_id: transients[:in_reply_to]&.id,
|
|
|
|
upload_ids: transients[:upload_ids],
|
|
|
|
incoming_chat_webhook: transients[:incoming_chat_webhook],
|
|
|
|
process_inline: true,
|
|
|
|
)
|
|
|
|
|
|
|
|
if result.failure?
|
|
|
|
raise RSpec::Expectations::ExpectationNotMetError.new(
|
|
|
|
"Service `#{resolved_class}` failed, see below for step details:\n\n" +
|
|
|
|
result.inspect_steps.inspect,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
result.message_instance
|
2023-05-17 23:49:52 +08:00
|
|
|
end
|
2022-11-02 21:41:30 +08:00
|
|
|
end
|
|
|
|
|
2024-06-08 06:20:37 +08:00
|
|
|
Fabricator(:chat_mention_notification, class_name: "Chat::MentionNotification") do
|
|
|
|
chat_mention { Fabricate(:user_chat_mention) }
|
|
|
|
notification { Fabricate(:notification) }
|
|
|
|
end
|
|
|
|
|
DEV: Redesign chat mentions (#24752)
At the moment, when someone is mentioning a group, or using here or
all mention, we create a chat_mention record per user. What we want
instead is to have special kinds of mentions, so we can create only one
chat_mention record in such cases. This PR implements that.
Note, that such mentions will still have N related notifications, one
notification per a user. We don't expect we'll have performance
problems on the notifications side, but if at some point we do, we
should be able to solve them on the side of notifications
(notifications are handled in jobs, also some little delays with
the notifications are acceptable, so we can make sure notifications
are properly queued, and that processing of every notification is
fast enough to make delays small enough).
The preparation work for this PR was done in fbd24fa, where we make
it possible for one mention to have several related notifications.
A pretty tricky part of this PR is schema and data migration, I've explained
related details inline on the migration files.
2024-01-17 19:24:01 +08:00
|
|
|
Fabricator(:user_chat_mention, class_name: "Chat::UserMention") do
|
DEV: Chat service object initial implementation (#19814)
This is a combined work of Martin Brennan, Loïc Guitaut, and Joffrey Jaffeux.
---
This commit implements a base service object when working in chat. The documentation is available at https://discourse.github.io/discourse/chat/backend/Chat/Service.html
Generating documentation has been made as part of this commit with a bigger goal in mind of generally making it easier to dive into the chat project.
Working with services generally involves 3 parts:
- The service object itself, which is a series of steps where few of them are specialized (model, transaction, policy)
```ruby
class UpdateAge
include Chat::Service::Base
model :user, :fetch_user
policy :can_see_user
contract
step :update_age
class Contract
attribute :age, :integer
end
def fetch_user(user_id:, **)
User.find_by(id: user_id)
end
def can_see_user(guardian:, **)
guardian.can_see_user(user)
end
def update_age(age:, **)
user.update!(age: age)
end
end
```
- The `with_service` controller helper, handling success and failure of the service within a service and making easy to return proper response to it from the controller
```ruby
def update
with_service(UpdateAge) do
on_success { render_serialized(result.user, BasicUserSerializer, root: "user") }
end
end
```
- Rspec matchers and steps inspector, improving the dev experience while creating specs for a service
```ruby
RSpec.describe(UpdateAge) do
subject(:result) do
described_class.call(guardian: guardian, user_id: user.id, age: age)
end
fab!(:user) { Fabricate(:user) }
fab!(:current_user) { Fabricate(:admin) }
let(:guardian) { Guardian.new(current_user) }
let(:age) { 1 }
it { expect(user.reload.age).to eq(age) }
end
```
Note in case of unexpected failure in your spec, the output will give all the relevant information:
```
1) UpdateAge when no channel_id is given is expected to fail to find a model named 'user'
Failure/Error: it { is_expected.to fail_to_find_a_model(:user) }
Expected model 'foo' (key: 'result.model.user') was not found in the result object.
[1/4] [model] 'user' ❌
[2/4] [policy] 'can_see_user'
[3/4] [contract] 'default'
[4/4] [step] 'update_age'
/Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/update_age.rb:32:in `fetch_user': missing keyword: :user_id (ArgumentError)
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:202:in `instance_exec'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:202:in `call'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:219:in `call'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:417:in `block in run!'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:417:in `each'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:417:in `run!'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:411:in `run'
from <internal:kernel>:90:in `tap'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:302:in `call'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/spec/services/update_age_spec.rb:15:in `block (3 levels) in <main>'
```
2023-02-13 20:09:57 +08:00
|
|
|
transient read: false
|
|
|
|
transient high_priority: true
|
|
|
|
transient identifier: :direct_mentions
|
|
|
|
|
2022-11-02 21:41:30 +08:00
|
|
|
user { Fabricate(:user) }
|
DEV: Chat service object initial implementation (#19814)
This is a combined work of Martin Brennan, Loïc Guitaut, and Joffrey Jaffeux.
---
This commit implements a base service object when working in chat. The documentation is available at https://discourse.github.io/discourse/chat/backend/Chat/Service.html
Generating documentation has been made as part of this commit with a bigger goal in mind of generally making it easier to dive into the chat project.
Working with services generally involves 3 parts:
- The service object itself, which is a series of steps where few of them are specialized (model, transaction, policy)
```ruby
class UpdateAge
include Chat::Service::Base
model :user, :fetch_user
policy :can_see_user
contract
step :update_age
class Contract
attribute :age, :integer
end
def fetch_user(user_id:, **)
User.find_by(id: user_id)
end
def can_see_user(guardian:, **)
guardian.can_see_user(user)
end
def update_age(age:, **)
user.update!(age: age)
end
end
```
- The `with_service` controller helper, handling success and failure of the service within a service and making easy to return proper response to it from the controller
```ruby
def update
with_service(UpdateAge) do
on_success { render_serialized(result.user, BasicUserSerializer, root: "user") }
end
end
```
- Rspec matchers and steps inspector, improving the dev experience while creating specs for a service
```ruby
RSpec.describe(UpdateAge) do
subject(:result) do
described_class.call(guardian: guardian, user_id: user.id, age: age)
end
fab!(:user) { Fabricate(:user) }
fab!(:current_user) { Fabricate(:admin) }
let(:guardian) { Guardian.new(current_user) }
let(:age) { 1 }
it { expect(user.reload.age).to eq(age) }
end
```
Note in case of unexpected failure in your spec, the output will give all the relevant information:
```
1) UpdateAge when no channel_id is given is expected to fail to find a model named 'user'
Failure/Error: it { is_expected.to fail_to_find_a_model(:user) }
Expected model 'foo' (key: 'result.model.user') was not found in the result object.
[1/4] [model] 'user' ❌
[2/4] [policy] 'can_see_user'
[3/4] [contract] 'default'
[4/4] [step] 'update_age'
/Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/update_age.rb:32:in `fetch_user': missing keyword: :user_id (ArgumentError)
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:202:in `instance_exec'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:202:in `call'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:219:in `call'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:417:in `block in run!'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:417:in `each'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:417:in `run!'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:411:in `run'
from <internal:kernel>:90:in `tap'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/app/services/base.rb:302:in `call'
from /Users/joffreyjaffeux/Code/pr-discourse/plugins/chat/spec/services/update_age_spec.rb:15:in `block (3 levels) in <main>'
```
2023-02-13 20:09:57 +08:00
|
|
|
chat_message { Fabricate(:chat_message) }
|
2022-11-02 21:41:30 +08:00
|
|
|
end
|
|
|
|
|
DEV: Redesign chat mentions (#24752)
At the moment, when someone is mentioning a group, or using here or
all mention, we create a chat_mention record per user. What we want
instead is to have special kinds of mentions, so we can create only one
chat_mention record in such cases. This PR implements that.
Note, that such mentions will still have N related notifications, one
notification per a user. We don't expect we'll have performance
problems on the notifications side, but if at some point we do, we
should be able to solve them on the side of notifications
(notifications are handled in jobs, also some little delays with
the notifications are acceptable, so we can make sure notifications
are properly queued, and that processing of every notification is
fast enough to make delays small enough).
The preparation work for this PR was done in fbd24fa, where we make
it possible for one mention to have several related notifications.
A pretty tricky part of this PR is schema and data migration, I've explained
related details inline on the migration files.
2024-01-17 19:24:01 +08:00
|
|
|
Fabricator(:group_chat_mention, class_name: "Chat::GroupMention") do
|
|
|
|
chat_message { Fabricate(:chat_message) }
|
|
|
|
group { Fabricate(:group) }
|
|
|
|
end
|
|
|
|
|
|
|
|
Fabricator(:all_chat_mention, class_name: "Chat::AllMention") do
|
|
|
|
chat_message { Fabricate(:chat_message) }
|
|
|
|
end
|
|
|
|
|
|
|
|
Fabricator(:here_chat_mention, class_name: "Chat::HereMention") do
|
|
|
|
chat_message { Fabricate(:chat_message) }
|
|
|
|
end
|
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:chat_message_reaction, class_name: "Chat::MessageReaction") do
|
2022-11-02 21:41:30 +08:00
|
|
|
chat_message { Fabricate(:chat_message) }
|
|
|
|
user { Fabricate(:user) }
|
|
|
|
emoji { %w[+1 tada heart joffrey_facepalm].sample }
|
DEV: start glimmer-ification and optimisations of chat plugin (#19531)
Note this is a very large PR, and some of it could have been splited, but keeping it one chunk made it to merge conflicts and to revert if necessary. Actual new code logic is also not that much, as most of the changes are removing js tests, adding system specs or moving things around.
To make it possible this commit is doing the following changes:
- converting (and adding new) existing js acceptances tests into system tests. This change was necessary to ensure as little regressions as possible while changing paradigm
- moving away from store. Using glimmer and tracked properties requires to have class objects everywhere and as a result works well with models. However store/adapters are suffering from many bugs and limitations. As a workaround the `chat-api` and `chat-channels-manager` are an answer to this problem by encapsulating backend calls and frontend storage logic; while still using js models.
- dropping `appEvents` as much as possible. Using tracked properties and a better local storage of channel models, allows to be much more reactive and doesn’t require arbitrary manual updates everywhere in the app.
- while working on replacing store, the existing work of a chat api (backend) has been continued to support more cases.
- removing code from the `chat` service to separate concerns, `chat-subscriptions-manager` and `chat-channels-manager`, being the largest examples of where the code has been rewritten/moved.
Future wok:
- improve behavior when closing/deleting a channel, it's already slightly buggy on live, it's rare enough that it's not a big issue, but should be improved
- improve page objects used in chat
- move more endpoints to the API
- finish temporarily skipped tests
- extract more code from the `chat` service
- use glimmer for `chat-messages`
- separate concerns in `chat-live-pane`
- eventually add js tests for `chat-api`, `chat-channels-manager` and `chat-subscriptions-manager`, they are indirectly heavy tested through system tests but it would be nice to at least test the public API
<!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in JavaScript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
2022-12-21 20:21:02 +08:00
|
|
|
after_build do |chat_message_reaction|
|
|
|
|
chat_message_reaction.chat_message.chat_channel.add(chat_message_reaction.user)
|
|
|
|
end
|
2022-11-02 21:41:30 +08:00
|
|
|
end
|
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:chat_message_revision, class_name: "Chat::MessageRevision") do
|
2022-11-02 21:41:30 +08:00
|
|
|
chat_message { Fabricate(:chat_message) }
|
|
|
|
old_message { "something old" }
|
|
|
|
new_message { "something new" }
|
2022-11-08 07:06:13 +08:00
|
|
|
user { |attrs| attrs[:chat_message].user }
|
2022-11-02 21:41:30 +08:00
|
|
|
end
|
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:chat_reviewable_message, class_name: "Chat::ReviewableMessage") do
|
2022-11-02 21:41:30 +08:00
|
|
|
reviewable_by_moderator true
|
|
|
|
type "ReviewableChatMessage"
|
|
|
|
created_by { Fabricate(:user) }
|
|
|
|
target { Fabricate(:chat_message) }
|
|
|
|
reviewable_scores { |p| [Fabricate.build(:reviewable_score, reviewable_id: p[:id])] }
|
|
|
|
end
|
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:direct_message, class_name: "Chat::DirectMessage") do
|
|
|
|
users { [Fabricate(:user), Fabricate(:user)] }
|
|
|
|
end
|
2022-11-02 21:41:30 +08:00
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:chat_webhook_event, class_name: "Chat::WebhookEvent") do
|
2022-11-02 21:41:30 +08:00
|
|
|
chat_message { Fabricate(:chat_message) }
|
|
|
|
incoming_chat_webhook do |attrs|
|
|
|
|
Fabricate(:incoming_chat_webhook, chat_channel: attrs[:chat_message].chat_channel)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:incoming_chat_webhook, class_name: "Chat::IncomingWebhook") do
|
2024-09-10 13:16:16 +08:00
|
|
|
name { sequence(:name) { |i| "Test webhook #{i + 1}" } }
|
|
|
|
emoji { %w[:joy: :rocket: :handshake:].sample }
|
2022-11-02 21:41:30 +08:00
|
|
|
chat_channel { Fabricate(:chat_channel, chatable: Fabricate(:category)) }
|
|
|
|
end
|
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:user_chat_channel_membership, class_name: "Chat::UserChatChannelMembership") do
|
2022-11-02 21:41:30 +08:00
|
|
|
user
|
|
|
|
chat_channel
|
|
|
|
following true
|
|
|
|
end
|
|
|
|
|
|
|
|
Fabricator(:user_chat_channel_membership_for_dm, from: :user_chat_channel_membership) do
|
|
|
|
user
|
|
|
|
chat_channel
|
|
|
|
following true
|
2024-10-08 17:13:01 +08:00
|
|
|
notification_level 2
|
2022-11-02 21:41:30 +08:00
|
|
|
end
|
2023-01-25 19:50:10 +08:00
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:chat_draft, class_name: "Chat::Draft") do
|
2023-01-25 19:50:10 +08:00
|
|
|
user
|
|
|
|
chat_channel
|
|
|
|
|
|
|
|
transient :value, "chat draft message"
|
|
|
|
transient :uploads, []
|
|
|
|
transient :reply_to_msg
|
|
|
|
|
|
|
|
data do |attrs|
|
|
|
|
{ value: attrs[:value], replyToMsg: attrs[:reply_to_msg], uploads: attrs[:uploads] }.to_json
|
|
|
|
end
|
|
|
|
end
|
FEATURE: Automatically create chat threads in background (#20206)
Whenever we create a chat message that is `in_reply_to` another
message, we want to lazily populate the thread record for the
message chain.
If there is no thread yet for the root message in the reply chain,
we create a new thread with the appropriate details, and use that
thread ID for every message in the chain that does not yet have
a thread ID.
* Root message (ID 1) - no thread ID
* Message (ID 2, in_reply_to 1) - no thread ID
* When I as a user create a message in reply to ID 2, we create a thread and apply it to ID 1, ID 2, and the new message
If there is a thread for the root message in the reply chain, we
do not create one, and use the thread ID for the newly created chat
message.
* Root message (ID 1) - thread ID 700
* Message (ID 2, in_reply_to 1) - thread ID 700
* When I as a user create a message in reply to ID 2, we use the existing thread ID 700 for the new message
We also support passing in the `thread_id` to `ChatMessageCreator`,
which will be used when replying to a message that is already part of
a thread, and we validate whether that `thread_id` is okay in the context
of the channel and also the reply chain.
This work is always done, regardless of channel `thread_enabled` settings
or the `enable_experimental_chat_threaded_discussions` site setting.
This commit does not include a large data migration to backfill threads for
all existing reply chains, its unnecessary to do this so early in the project,
we can do this later if necessary.
This commit also includes thread considerations in the `MessageMover` class:
* If the original message and N other messages of a thread is moved,
the remaining messages in the thread have a new thread created in
the old channel and are moved to it.
* The reply chain is not preserved for moved messages, so new threads are
not created in the destination channel.
In addition to this, I added a fix to also clear the `in_reply_to_id` of messages
in the old channel which are moved out of that channel for data cleanliness.
2023-02-08 08:22:07 +08:00
|
|
|
|
2023-03-17 21:24:38 +08:00
|
|
|
Fabricator(:chat_thread, class_name: "Chat::Thread") do
|
FEATURE: Automatically create chat threads in background (#20206)
Whenever we create a chat message that is `in_reply_to` another
message, we want to lazily populate the thread record for the
message chain.
If there is no thread yet for the root message in the reply chain,
we create a new thread with the appropriate details, and use that
thread ID for every message in the chain that does not yet have
a thread ID.
* Root message (ID 1) - no thread ID
* Message (ID 2, in_reply_to 1) - no thread ID
* When I as a user create a message in reply to ID 2, we create a thread and apply it to ID 1, ID 2, and the new message
If there is a thread for the root message in the reply chain, we
do not create one, and use the thread ID for the newly created chat
message.
* Root message (ID 1) - thread ID 700
* Message (ID 2, in_reply_to 1) - thread ID 700
* When I as a user create a message in reply to ID 2, we use the existing thread ID 700 for the new message
We also support passing in the `thread_id` to `ChatMessageCreator`,
which will be used when replying to a message that is already part of
a thread, and we validate whether that `thread_id` is okay in the context
of the channel and also the reply chain.
This work is always done, regardless of channel `thread_enabled` settings
or the `enable_experimental_chat_threaded_discussions` site setting.
This commit does not include a large data migration to backfill threads for
all existing reply chains, its unnecessary to do this so early in the project,
we can do this later if necessary.
This commit also includes thread considerations in the `MessageMover` class:
* If the original message and N other messages of a thread is moved,
the remaining messages in the thread have a new thread created in
the old channel and are moved to it.
* The reply chain is not preserved for moved messages, so new threads are
not created in the destination channel.
In addition to this, I added a fix to also clear the `in_reply_to_id` of messages
in the old channel which are moved out of that channel for data cleanliness.
2023-02-08 08:22:07 +08:00
|
|
|
before_create do |thread, transients|
|
|
|
|
thread.original_message_user = original_message.user
|
|
|
|
thread.channel = original_message.chat_channel
|
|
|
|
end
|
|
|
|
|
2023-08-24 21:22:51 +08:00
|
|
|
transient :with_replies, :channel, :original_message_user, :old_om, use_service: false
|
FEATURE: Automatically create chat threads in background (#20206)
Whenever we create a chat message that is `in_reply_to` another
message, we want to lazily populate the thread record for the
message chain.
If there is no thread yet for the root message in the reply chain,
we create a new thread with the appropriate details, and use that
thread ID for every message in the chain that does not yet have
a thread ID.
* Root message (ID 1) - no thread ID
* Message (ID 2, in_reply_to 1) - no thread ID
* When I as a user create a message in reply to ID 2, we create a thread and apply it to ID 1, ID 2, and the new message
If there is a thread for the root message in the reply chain, we
do not create one, and use the thread ID for the newly created chat
message.
* Root message (ID 1) - thread ID 700
* Message (ID 2, in_reply_to 1) - thread ID 700
* When I as a user create a message in reply to ID 2, we use the existing thread ID 700 for the new message
We also support passing in the `thread_id` to `ChatMessageCreator`,
which will be used when replying to a message that is already part of
a thread, and we validate whether that `thread_id` is okay in the context
of the channel and also the reply chain.
This work is always done, regardless of channel `thread_enabled` settings
or the `enable_experimental_chat_threaded_discussions` site setting.
This commit does not include a large data migration to backfill threads for
all existing reply chains, its unnecessary to do this so early in the project,
we can do this later if necessary.
This commit also includes thread considerations in the `MessageMover` class:
* If the original message and N other messages of a thread is moved,
the remaining messages in the thread have a new thread created in
the old channel and are moved to it.
* The reply chain is not preserved for moved messages, so new threads are
not created in the destination channel.
In addition to this, I added a fix to also clear the `in_reply_to_id` of messages
in the old channel which are moved out of that channel for data cleanliness.
2023-02-08 08:22:07 +08:00
|
|
|
|
2023-02-17 02:17:26 +08:00
|
|
|
original_message do |attrs|
|
2023-05-10 17:42:32 +08:00
|
|
|
Fabricate(
|
|
|
|
:chat_message,
|
2024-02-20 16:49:19 +08:00
|
|
|
chat_channel: attrs[:channel] || Fabricate(:chat_channel, threading_enabled: true),
|
2023-05-10 17:42:32 +08:00
|
|
|
user: attrs[:original_message_user] || Fabricate(:user),
|
2023-08-24 21:22:51 +08:00
|
|
|
use_service: attrs[:use_service],
|
2023-05-10 17:42:32 +08:00
|
|
|
)
|
2023-02-17 02:17:26 +08:00
|
|
|
end
|
2023-04-11 13:40:25 +08:00
|
|
|
|
2023-07-07 11:09:06 +08:00
|
|
|
after_create do |thread, transients|
|
2023-07-13 08:28:11 +08:00
|
|
|
attrs = { thread_id: thread.id }
|
|
|
|
|
|
|
|
# Sometimes we make this older via created_at so any messages fabricated for this thread
|
|
|
|
# afterwards are not created earlier in time than the OM.
|
|
|
|
attrs[:created_at] = 1.week.ago if transients[:old_om]
|
|
|
|
|
|
|
|
thread.original_message.update!(**attrs)
|
2023-06-15 08:49:27 +08:00
|
|
|
thread.add(thread.original_message_user)
|
2023-07-07 11:09:06 +08:00
|
|
|
|
|
|
|
if transients[:with_replies]
|
2023-12-11 14:38:07 +08:00
|
|
|
Fabricate
|
|
|
|
.times(
|
|
|
|
transients[:with_replies],
|
|
|
|
:chat_message,
|
|
|
|
thread: thread,
|
|
|
|
use_service: transients[:use_service],
|
|
|
|
)
|
|
|
|
.each { |message| thread.add(message.user) }
|
|
|
|
|
|
|
|
thread.update!(replies_count: transients[:with_replies])
|
2023-07-07 11:09:06 +08:00
|
|
|
end
|
2023-06-15 08:49:27 +08:00
|
|
|
end
|
FEATURE: Automatically create chat threads in background (#20206)
Whenever we create a chat message that is `in_reply_to` another
message, we want to lazily populate the thread record for the
message chain.
If there is no thread yet for the root message in the reply chain,
we create a new thread with the appropriate details, and use that
thread ID for every message in the chain that does not yet have
a thread ID.
* Root message (ID 1) - no thread ID
* Message (ID 2, in_reply_to 1) - no thread ID
* When I as a user create a message in reply to ID 2, we create a thread and apply it to ID 1, ID 2, and the new message
If there is a thread for the root message in the reply chain, we
do not create one, and use the thread ID for the newly created chat
message.
* Root message (ID 1) - thread ID 700
* Message (ID 2, in_reply_to 1) - thread ID 700
* When I as a user create a message in reply to ID 2, we use the existing thread ID 700 for the new message
We also support passing in the `thread_id` to `ChatMessageCreator`,
which will be used when replying to a message that is already part of
a thread, and we validate whether that `thread_id` is okay in the context
of the channel and also the reply chain.
This work is always done, regardless of channel `thread_enabled` settings
or the `enable_experimental_chat_threaded_discussions` site setting.
This commit does not include a large data migration to backfill threads for
all existing reply chains, its unnecessary to do this so early in the project,
we can do this later if necessary.
This commit also includes thread considerations in the `MessageMover` class:
* If the original message and N other messages of a thread is moved,
the remaining messages in the thread have a new thread created in
the old channel and are moved to it.
* The reply chain is not preserved for moved messages, so new threads are
not created in the destination channel.
In addition to this, I added a fix to also clear the `in_reply_to_id` of messages
in the old channel which are moved out of that channel for data cleanliness.
2023-02-08 08:22:07 +08:00
|
|
|
end
|
2023-05-10 23:19:48 +08:00
|
|
|
|
2023-05-16 20:51:13 +08:00
|
|
|
Fabricator(:user_chat_thread_membership, class_name: "Chat::UserChatThreadMembership") do
|
|
|
|
user
|
|
|
|
after_create do |membership|
|
|
|
|
Chat::UserChatChannelMembership.find_or_create_by!(
|
|
|
|
user: membership.user,
|
|
|
|
chat_channel: membership.thread.channel,
|
|
|
|
).update!(following: true)
|
|
|
|
end
|
|
|
|
end
|