Commit Graph

138 Commits

Author SHA1 Message Date
Loïc Guitaut
6158a1ae29 DEV: Refactor the Chat::CreateThread service a bit
Follow best practices from our docs.
2024-11-06 15:53:43 +01:00
Joffrey JAFFEUX
88eb96b315
DEV: sets an icon_upload_id on a channel (#29566)
There's no UI for it at the moment but when creating a channel or updating it, it's now possible to pass `icon_upload_id` as param. This will be available on the channel as `icon_upload_url`.
2024-11-04 17:19:44 +09:00
Joffrey JAFFEUX
ce76b88eb2
DEV: start/stop reply implementation (#29542)
* DEV: join/leave presence chat-reply when streaming

This commit ensures that starting/stopping a chat message with the streaming option will automatically make the creator of the message as present in the chat-reply channel.

* implements start/stop reply

* not needed
2024-11-04 08:14:35 +11:00
David Battersby
ec480e99ef
FIX: show chat thread notifications for direct message channels (#29414)
When adding threads to DM channels in #29170 we intentionally didn't add them to the My Threads section. However this makes it easy to miss notifications as we don't get the new thread badge on the sidebar and footer tabs (drawer/mobile). However they were also missing from the chat header and sidebar too, which is fixed with this PR.

When a new thread or a reply to an existing thread is created within a DM channel (either 1:1 or group), we now show the standard badges like we do for public channels.

We now also show the green dot in the sidebar for My Threads and public channels when they contain an unread watched thread.
2024-10-31 10:50:11 +04:00
Loïc Guitaut
2f334964f2 DEV: Remove hash-like access from service contracts
We decided to keep only one way to access values from a contract. This
patch thus removes the hash-like access from contracts.
2024-10-29 16:02:51 +01:00
Loïc Guitaut
584424594e DEV: Replace params by the contract object in services
This patch replaces the parameters provided to a service through
`params` by the contract object.

That way, it allows better consistency when accessing input params. For
example, if you have a service without a contract, to access a
parameter, you need to use `params[:my_parameter]`. But with a contract,
you do this through `contract.my_parameter`. Now, with this patch,
you’ll be able to access it through `params.my_parameter` or
`params[:my_parameter]`.

Some methods have been added to the contract object to better mimic a
Hash. That way, when accessing/using `params`, you don’t have to think
too much about it:
- `params.my_key` is also accessible through `params[:my_key]`.
- `params.my_key = value` can also be done through `params[:my_key] =
  value`.
- `#slice` and `#merge` are available.
- `#to_hash` has been implemented, so the contract object will be
  automatically cast as a hash by Ruby depending on the context. For
  example, with an AR model, you can do this: `user.update(**params)`.
2024-10-25 14:48:34 +02:00
Loïc Guitaut
41584ab40c DEV: Provide user input to services using params key
Currently in services, we don’t make a distinction between input
parameters, options and dependencies.

This can lead to user input modifying the service behavior, whereas it
was not the developer intention.

This patch addresses the issue by changing how data is provided to
services:
- `params` is now used to hold all data coming from outside (typically
  user input from a controller) and a contract will take its values from
  `params`.
- `options` is a new key to provide options to a service. This typically
  allows changing a service behavior at runtime. It is, of course,
  totally optional.
- `dependencies` is actually anything else provided to the service (like
  `guardian`) and available directly from the context object.

The `service_params` helper in controllers has been updated to reflect
those changes, so most of the existing services didn’t need specific
changes.

The options block has the same DSL as contracts, as it’s also based on
`ActiveModel`. There aren’t any validations, though. Here’s an example:
```ruby
options do
  attribute :allow_changing_hidden, :boolean, default: false
end
```
And here’s an example of how to call a service with the new keys:
```ruby
MyService.call(params: { key1: value1, … }, options: { my_option: true }, guardian:, …)
```
2024-10-25 09:57:59 +02:00
Loïc Guitaut
08e9364573 DEV: Refactor some services from chat
Extracted from https://github.com/discourse/discourse/pull/29129.

This patch makes the code more compliant with the upcoming service docs best practices.
2024-10-21 16:16:25 +02:00
Loïc Guitaut
93e02069b0 DEV: Don’t provide an array to site settings group lists in specs
This is extracted from https://github.com/discourse/discourse/pull/29129.

In some chat specs, we provide an array as a value for group lists like
`chat_allowed_groups`, which is wrong. This results in a value like
`"1|2|[3]"` instead of `"1|2|3"`.
2024-10-17 11:25:31 +02:00
David Battersby
a7a9148b1e
DEV: consolidate chat channel notification settings (#29080)
On the chat channel settings page, we want to show a single Send push notifications setting instead of the current Desktop notifications and Mobile push notifications settings.

For existing users, use the Mobile push notifications setting value for the new Send push notifications setting.
2024-10-08 13:13:01 +04:00
Loïc Guitaut
05b8ff436c DEV: Introduce a Service::ActionBase class for service actions
This will help to enforce a consistent pattern for creating service
actions.

This patch also namespaces actions and policies, making everything
related to a service available directly in
`app/services/<concept-name>`, making things more consistent at that
level too.
2024-09-18 17:02:46 +02:00
David Battersby
997fbc9757
FEATURE: Add ability to watch chat threads (#28639)
This change introduces a new thread notification level allowing users to get notified when someone replies to the thread.

Users who watch a thread will get a green notification on the chat icon and a user notification (blue). User notifications are consolidated based on thread id to prevent cluttering the original users notification area.

---------

Co-authored-by: Régis Hanol <regis@hanol.fr>
2024-09-02 16:45:55 +04:00
Loïc Guitaut
d26d45540e DEV: Use run_successfully matcher in service specs 2024-08-28 16:30:09 +02:00
David Battersby
6f2f34f786
DEV: fix chat message grace edit period flaky (#28095)
The message grace edit window (10 seconds) was too short after freezing time, possibly causing the test to fail occasionally if the record is not updated within 5 seconds.
2024-07-26 18:16:17 +04:00
Natalie Tay
9bed472a77
DEV: Temporarily skip failing test on CI (#27915) 2024-07-15 15:23:01 +08:00
David Battersby
3b653a918e
FEATURE: show my threads from muted chat channels (#27468)
We should show threads from muted channels in the My Threads area so that users can easily access their followed threads.
2024-06-13 18:39:35 +04:00
David Battersby
4e80c9eb13
FIX: chat direct message group user limit is off by 1 (#27014)
This change allows the correct number of members to be added when creating a group direct message, based on the site setting chat_max_direct_message_users.

Previously we counted the current user within the max user limit and therefore the count was off by 1.
2024-06-03 12:11:49 +04:00
Joffrey JAFFEUX
5aefda1dee
FIX: allows listing messages of any thread (#27259)
Before this fix we could only list messages of a thread if it was part of a `threading_enabled` channel or if the thread was set to `force`.

Due to our design of also using a thread id when this is just a chain of replies so we can switch from threading enabled to disabled at any time, we will allow `Chat:: ListChannelThreadMessages` to list the messages of any thread, the only important requirements are:
- having a thread id
- being able to access this thread

To allow this, this commit simply removes the check on `threading_enabled` or `force`.
2024-05-30 10:20:40 +02:00
Krzysztof Kotlarek
cfbbfd177c
DEV: move post flags into database (#27125)
This is preparation for a feature that will allow admins to define their custom flags. Current behaviour should stay untouched.
2024-05-23 12:19:07 +10:00
Jan Cernik
9889547475
FEATURE: Allow to bulk delete chat messages (#26586) 2024-05-22 08:57:00 -03:00
Krzysztof Kotlarek
40d65dddf8
Revert "DEV: move post flags into database (#26951)" (#27102)
This reverts commit 7aff9806eb.
2024-05-21 16:21:07 +10:00
Krzysztof Kotlarek
7aff9806eb
DEV: move post flags into database (#26951)
This is preparation for a feature that will allow admins to define their custom flags. Current behaviour should stay untouched.
2024-05-21 13:15:32 +10:00
Joffrey JAFFEUX
26c8eab1f3
FIX: allows bots to create/update/stream messages (#26900)
Prior to this commit, only system users had this pass.

Another significant change of the PR, is to make membership of a channel the angular stone of the permission check to create/update/stop streaming a message. The idea being, if you are a member of a channel already we don't need to check if you can join it AGAIN.

We also have `Chat::AutoRemove::HandleCategoryUpdated` which will deal with permissions change so it's simpler and less prone to error to consider the membership as the only source of truth.
2024-05-07 15:17:42 +02:00
Jarek Radosz
79870d3a1e
DEV: Fix random typos (#26881) 2024-05-06 20:52:48 +02:00
Joffrey JAFFEUX
f72f63660a
FIX: an existing member of a channel is allowed to join (#26884)
There's no point checking if a user can join a channel if they are already part of it. This case was frequent when using `enforce_membership: true` for custom bots for example.
2024-05-06 17:14:20 +02:00
Joffrey JAFFEUX
671e6066bf
DEV: adds first_messages/last_messages to thread SDK (#26861)
This commit introduces several enhancements to the ChatSDK module, aiming to improve the functionality and usability of chat thread interactions. Here's what has been changed and added:

1. **New Method: `first_messages`:**
   - Added a method to retrieve the first set of messages from a specified chat thread.
   - This method is particularly useful for fetching initial messages when entering a chat thread.
   - Parameters include `thread_id`, `guardian`, and an optional `page_size` which defaults to 10.
   - Usage example added to demonstrate fetching the first 15 messages from a thread.

2. **New Method: `last_messages`:**
   - Added a method to retrieve the last set of messages from a specified chat thread.
   - This method supports reverse pagination, where the user may want to see the most recent messages first.
   - Similar to `first_messages`, it accepts `thread_id`, `guardian`, and an optional `page_size` parameter, defaulting to 10.
   - Usage example provided to illustrate fetching the last 20 messages from a thread.
2024-05-03 17:30:39 +02:00
Joffrey JAFFEUX
dda4bb0f7c
DEV: allows to disable strip_whitespaces in messages (#26848)
The TextCleaner step has been moved from chat message’s validation to create_message/update_message services. It allows us to easily tweak part of its behavior depending on the needs.

For example we will now disable strip_whitespaces by default when streaming messages as we want to keep newlines and spaces at the end of the message.
2024-05-02 11:59:18 +02:00
David Battersby
0c8f531909
FEATURE: encourage users to set chat thread titles (#26617)
This change encourages users to title their threads to make it easier for other users to join in on conversations that matter to them.

The creator of the chat thread will receive a toast notification prompting them to add a thread title when on mobile and the thread has at least 5 sent replies.
2024-04-29 17:20:01 +08:00
David Battersby
c62d3610c6
PERF: Reduce overhead from chat message excerpt (#26712)
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.
2024-04-25 14:29:00 +02:00
Joffrey JAFFEUX
52e8d57293
FEATURE: implements last read message for threads (#26702)
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.
2024-04-25 10:47:54 +02:00
David Battersby
23fc0fb078
FIX: allow direct message when max dm users set to 1 (#26392)
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.
2024-03-27 15:59:12 +08:00
Sam
e3a0faefc5
FEATURE: allow re-scoping chat user search via a plugin (#26361)
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>
2024-03-27 08:55:53 +11:00
Jarek Radosz
4c860995e0
DEV: Remove unnecessary rails_helper requiring (#26364) 2024-03-26 11:32:01 +01:00
Joffrey JAFFEUX
a884842fa5
FIX: do not use return in block (#26260)
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.
2024-03-20 10:49:28 +01:00
Joffrey JAFFEUX
bbb8595107
PERF: defer loading channels (#26155)
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.
2024-03-18 08:35:07 +01:00
Joffrey JAFFEUX
821402d024
DEV: removes default service actions (#26078)
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
2024-03-07 12:10:43 +01:00
Joffrey JAFFEUX
76953cc356
FEATURE: allows to force a thread (#25987)
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)
```
2024-03-06 12:03:42 +01:00
Joffrey JAFFEUX
0c827980e6
FIX: do not show threads with no replies (#26033)
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.
2024-03-05 20:26:35 +01:00
Andrei Prigorshnev
b3a1199493
FEATURE: Hide user status when user is hiding public profile and presence (#24300)
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.
2024-02-26 17:40:48 +04:00
Joffrey JAFFEUX
77028e3675
DEV: adds a chat_can_create_direct_message_channel modifier (#25840)
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
```
2024-02-23 14:35:02 +01:00
Joffrey JAFFEUX
d8d756cd2f
DEV: chat streaming (#25736)
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
2024-02-20 09:49:19 +01:00
Andrei Prigorshnev
e83d8fb3e2
FIX: Allow several chat channels to have an empty slug (#25680)
In certain cases, chat channels may have empty slugs, it happens when:

1. The `slug_generation_method` setting is set to `None`
2. `slug_generation_method` is set to `ASCII` and a channel with 
a Unicode name and an empty slug is created (in this case, the code 
that creates channels tries to generate a slug and fallbacks to an empty slug)

At the moment, we have a unique index on the `chat_channels.slug` column 
which leads to errors when creating several channels with empty slugs 
(Discourse is able to create one such channel, but when trying to create 
the second one fails because of the unique constraint). This PR fixes that 
by adding a `where` condition to the index. Slugs still have to be unique, 
but now many channels may have empty slugs.

This fix is similar to the one we made to the category slugs – 7ba914f1e1.
2024-02-15 00:39:39 +04:00
Joffrey JAFFEUX
06bbed69f9
DEV: allows a context when creating a message (#25647)
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
```
2024-02-13 11:37:15 +01:00
Martin Brennan
d80345fa83
DEV: Chat hashtag test (#25638)
Followup a2a2785f0b, moving
stuff to an existing test.
2024-02-12 12:32:52 +10:00
Bianca Nenciu
a2a2785f0b
FIX: Look up all channel hashtags (#25617) 2024-02-09 19:59:38 +02:00
Ted Johansson
57ea56ee05
DEV: Remove full group refreshes from tests (#25414)
We have all these calls to Group.refresh_automatic_groups! littered throughout the tests. Including tests that are seemingly unrelated to groups. This is because automatic group memberships aren't fabricated when making a vanilla user. There are two places where you'd want to use this:

You have fabricated a user that needs a certain trust level (which is now based on group membership.)
You need the system user to have a certain trust level.
In the first case, we can pass refresh_auto_groups: true to the fabricator instead. This is a more lightweight operation that only considers a single user, instead of all users in all groups.

The second case is no longer a thing after #25400.
2024-01-25 14:28:26 +08:00
David Battersby
67244a2318
FIX: use site setting to show my threads chat footer tab (#25277)
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.
2024-01-23 19:14:46 +08:00
Jan Cernik
f4e51e0789
FEATURE: Allow users to DM groups in chat (#25189)
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."
2024-01-19 11:09:47 -03:00
Andrei Prigorshnev
62f423da15
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 15:24:01 +04:00
Joffrey JAFFEUX
40ce619edd
DEV: uses in: {} with lambda to work with eager_load (#25039)
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`
2023-12-29 12:45:07 +08:00