This change moves the chat message excerpt into a new database column (string) on the chat_messages table.
As part of this change, we will now set the excerpt within the `Chat::CreateMessage` service, and update it within the `Chat::UpdateMessage` service.
This commit will now allow us to track read position in a thread and returns to this position when you open the thread.
Note this commit is also extracting the following components to make it possible:
- `<ChatMessagesScroller />`
- `<ChatMessagesContainer />`
The `UpdateUserThreadLastRead` has been updated to allow this.
Various refactorings have also been done to the code and specs to improve the support of last read.
Why this change?
When the site setting for chat_max_direct_message_users is set to 1, it is expected that users can have a 1:1 chat with other users. However, since the current user is counting as 1 user it makes starting a new chat impossible.
This change hands this validation off to DirectMessageChannel::MaxUsersExcessPolicy which handles the count correctly by filtering out the current user.
This enables the following in Discourse AI
```
plugin.register_modifier(:chat_allowed_bot_user_ids) do |user_ids, guardian|
if guardian.user
mentionables = AiPersona.mentionables(user: guardian.user)
allowed_bot_ids = mentionables.map { |mentionable| mentionable[:user_id] }
user_ids.concat(allowed_bot_ids)
end
user_ids
end
```
some bots that are id < 0 need to be discoverable in search otherwise people can not talk to them.
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
We were incorrectly using `return` in a block which was causing exceptions at runtime. These exceptions were not causing much issues as they are in defer block.
While working on writing a test for this specific case, I noticed that our `upsert_custom_fields` function was using rails `update_all` which is not updating the `updated_at` timestamp. This commit also fixes it and adds a test for it.
Prior to this change we would pre-load all the user channels which making initial page load slower. This change will make them be loaded right after initial load. In the past this was not possible as the channels would have to be loaded on each page transition. However since about a year, we made the channels to be cached on the frontend and no other request will be needed.
I have decided for now to not show a loading state in the sidebar as I think it would be noise, but we can reconsider this later.
Note given we don't have the channels loaded at first certain things where harder to accomplish. The biggest UX change of this commit is that we removed all the complex logic of computing the best channel to display when you load /chat. We will now store the id of the last channel you visited and will use this id to decide which channel to show.
Previously services would let you define a high level default `def default_actions_for_service; end` which would define various handlers like `on_success`, after months of usage we consider the cons are superior to the pros here.
Two mains cons:
- people would often not understand where the handling was coming from
- it's easy to miss a case when you write your specs
Forcing a thread will work even in channel which don't have `threading_enabled` or in direct message channels.
For now this feature is only available through the `ChatSDK`:
```ruby
ChatSDK::Message.create(in_reply_to_id: 1, guardian: guardian, raw: "foo bar baz", channel_id: 2, force_thread: true)
```
Prior to this fix if a user had started to reply to a message without actually sending a message, the thread would still be created and we would end up listing it in the threads list of a channel.
This commit also improves adds thread and thread_replies_count to the 4th parameter of the chat_message_created event.
Prior to this fix we were checking if user was not part of a group which allows to chat, but we were not checking if this user was part of groups who can use direct messages.
Users can hide their public profile and presence information by checking
“Hide my public profile and presence features” on the
`u/{username}/preferences/interface` page. In that case, we also don't
want to return user status from the server.
This work has been started in https://github.com/discourse/discourse/pull/23946.
The current PR fixes all the remaining places in Core.
Note that the actual fix is quite simple – a5802f484d.
But we had a fair amount of duplication in the code responsible for
the user status serialization, so I had to dry that up first. The refactoring
as well as adding some additional tests is the main part of this PR.
```ruby
ChatSDK::Message.start_stream(message_id: 1, guardian: guardian)
ChatSDK::Message.stream(raw: "foo", message_id: 1, guardian: guardian)
ChatSDK::Message.stream(raw: "bar", message_id: 1, guardian: guardian)
ChatSDK::Message.stop_stream(message_id: 1, guardian: guardian)
```
Generally speaking only admins or owners of the message can interact with a message. Also note, Streaming to an existing message with a different user won't change the initial user of the message.
Prior to this fix, if the last message of a thread had been made by a deleted user it would cause an exception as we would have no user to display, this commit uses a solution we have been using at other places: the null pattern, through the use of `Chat::NullUser.new`.
Plugins can now register this modifier:
```ruby
register_modifier(:chat_can_create_direct_message_channel) do |user, target_users|
# your logic which should return true or false
end
```
If a user had `123456789` as username, it could be passed to the query as a number and the query would fail as it expects a string.
Also applies the same fix to groups.
This commit introduces the possibility to stream messages. To allow plugins to use streaming this commit also ships a `ChatSDK` library to allow to interact with few parts of discourse chat.
```ruby
ChatSDK::Message.create_with_stream(raw: "test") do |helper|
5.times do |i|
is_streaming = helper.stream(raw: "more #{i}")
next if !is_streaming
sleep 2
end
end
```
This commit also introduces all the frontend parts:
- messages can now be marked as streaming
- when streaming their content will be updated when a new content is appended
- a special UI will be showing (a blinking indicator)
- a cancel button allows the user to stop the streaming, when cancelled `helper.stream(...)` will return `false`, and the plugin can decide exit early
The service `Chat::CreateMessage` will now accept `context_post_ids` and `context_topic_id` as params. These values represent the topic which might be visible when sending a message (for now, this is only possible when using the drawer).
The `DiscourseEvent` `chat_message_created` will now have the following signature:
```ruby
on(:chat_message_created) do | message, channel, user, meta|
p meta[:context][:post_ids]
end
```
Fixes an issue with delayed rendering of the My Threads tab in chat mobile footer.
Previously we made an ajax request to determine the number of threads a user had before rendering the tab, however it is much faster (and better UX) if we can rely on a site setting for this.
The new chat_threads_enabled site setting is set to true when the site has chat channels with threading enabled.
This commit creates a shared implementation of the dates computation and moves all the logic (new messages since last visit and dates separator into one single component <ChatMessageSeparator />).
The frontend tests have been removed and only a single system spec has been added for threads as everything is sharing the same implementation and the existing channel specs should catch any regression.
Allows users to create DMs by selecting groups as a target. It also allows adding user groups to an existing chat
- When creating the channel, it expands the user group and adds all its members with chat enabled to the channel.
- After creation, there's no difference between adding a group or adding its members individually.
- Users can add multiple groups and users simultaneously.
- There are UI validations; the member count preview updates according to the member count of added groups, and it does not allow users to add more members than SiteSetting.chat_max_direct_message_users."
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.
This update adds three tabs to the bottom of the chat overlay to make it easier for users to navigate chat on mobile.
As a result of this change:
- Direct Messages are now shown separately from public channels on mobile
- My Threads has now moved from the channel list to it's own tab on mobile
- My Threads can still be accessed on desktop via the sidebar and within the drawer channel list
- Chat back button has been updated to navigate to the correct tab (for both channels and threads)
Some special cases:
- If DMs are not used then the tab is not rendered
- If the user has no threads then the tab is not rendered
- If both the tabs for DMs and Threads aren't available then the whole footer will not be rendered
- Chat footer is only shown on the listing pages (DMs, Channels, My Threads)
---------
Co-authored-by: chapoi <101828855+chapoi@users.noreply.github.com>
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
This regressed in 2791e75072. That commit
fixed subfolder URLs in general, but the `full_url` was adding the
subfolder prefix a second time, thus breaking this URL in emails.
Prior to this fix the number of users rendered by mentioned_users could equal the number of members in a channel which would be slow but could in more extreme case crash the page and/or server.
When validating with a dynamic set of values, especially one that might change during runtime, we should use a lambda or a proc to ensure that the validation uses the most up-to-date set of values. This is particularly important when using config.eager_load = true, which can cause some elements to be loaded only once at startup, thus not reflecting changes made at runtime.
This was the root cause of the issues here, as we were adding more ReviewableScore types after initial load through: `register_reviewable_type Chat::ReviewableMessage`
This PR is a reworked version of https://github.com/discourse/discourse/pull/24670.
In chat, we need the ability to have several notifications per `chat_mention`.
Currently, we have one_to_one relationship between `chat_mentions` and `notifications`:
d7a09fb08d/plugins/chat/app/models/chat/mention.rb (L9)
We want to have one_to_many relationship. This PR implements that by introducing
a join table between `chat_mentions` and `notifications`.
The main motivation for this is that we want to solve some performance problems
with mentions that we're having now. Let's say a user sends a message with @ all
in a channel with 50 members, we do two things in this case at the moment:
- create 50 chat_mentions
- create 50 notifications
We don't want to change how notifications work in core, but we want to be more
efficient in chat, and create only 1 `chat_mention` which would link to 50 notifications.
Also note, that on the side of notifications, having a lot of notifications is not so
big problem, because notifications processing can be queued.
Apart from improving performance, this change will make the code design better.
Note that I've marked the old `chat_mention.notification_id` column as ignored, but
I'm not deleting it in this PR. We'll delete it later in https://github.com/discourse/discourse/pull/24800.
This commit adds a new "My threads" link in sidebar and drawer. This link will open the "/chat/threads" page which contains all threads where the current user is a member. It's ordered by activity (unread and then last message created).
Moreover, the threads list of a channel page is now showing every threads of a channel, and not just the ones where you are a member.