Commit Graph

176 Commits

Author SHA1 Message Date
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
Penar Musaraj 8cf2f909f5
DEV: Dedicated route for current user notification counts (#26106)
Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
2024-03-15 12:08:37 -04: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 27407a25b4
FIX: correctly shows as disabled a user who can't chat (#26010)
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.
2024-03-05 09:13:42 +01:00
Mark VanLandingham 04b0f40db8
DEV: Modifier for Chat::Mailer to skip summary email for users (#26011) 2024-03-04 09:21:02 -06:00
Martin Brennan df4197c8b8
FIX: Show deleted bookmark reminders in user bookmarks menu (#25905)
When we send a bookmark reminder, there is an option to delete
the underlying bookmark. The Notification record stays around.
However, if you want to filter your notifications user menu
to only bookmark-based notifications, we were not showing unread
bookmark notifications for deleted bookmarks.

This commit fixes the issue _going forward_ by adding the
bookmarkable_id and bookmarkable_type to the Notification data,
so we can look up the underlying Post/Topic/Chat::Message
for a deleted bookmark and check user access in this way. Then,
it doesn't matter if the bookmark was deleted.
2024-02-29 09:03:49 +10:00
Joffrey JAFFEUX 41790f7739
DEV: allows stop/resume streaming on a message (#25774)
```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.
2024-02-26 14:16:29 +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
Krzysztof Kotlarek fc9648578b
DEV: Make more group-based settings client: false (#25735)
Affects the following settings:

delete_all_posts_and_topics_allowed_groups
experimental_new_new_view_groups
enable_experimental_admin_ui_groups
custom_summarization_allowed_groups
pm_tags_allowed_for_groups
chat_allowed_groups
direct_message_enabled_groups
chat_message_flag_allowed_groups

This turns off client: true for these group-based settings,
because there is no guarantee that the current user gets all
their group memberships serialized to the client. Better to check
server-side first.
2024-02-19 13:25:59 +11: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
Bianca Nenciu 1403217ca4
FEATURE: Async load of category and chat hashtags (#25526)
This commit includes several changes to make hashtags work when "lazy
load categories" is enabled. The previous hashtag implementation use the
category colors CSS variables, but these are not defined when the site
setting is enabled because categories are no longer preloaded.

This commit implements two fundamental changes:

1. load colors together with the other hashtag information

2. load cooked hashtag data asynchronously

The first change is implemented by adding "colors" to the HashtagItem
model. It is a list because two colors are returned for subcategories:
the color of the parent category and subcategory.

The second change is implemented on the server-side in a new route
/hashtags/by-ids and on the client side by loading previously unseen
hashtags, generating the CSS on the fly and injecting it into the page.

There have been minimal changes outside of these two fundamental ones,
but a refactoring will be coming soon to reuse as much of the code
and maybe favor use of `style` rather than injecting CSS into the page,
which can lead to page rerenders and indefinite grow of the styles.
2024-02-12 12:07:14 +02:00
Bianca Nenciu a2a2785f0b
FIX: Look up all channel hashtags (#25617) 2024-02-09 19:59:38 +02:00
Andrei Prigorshnev 429a7d09e2
FIX: Chat messages exporter (#25461)
We usually don't enforce foreign key relationships on the database level. 
Because of that, occasionally it's possible to see a chat message that 
references to a non-existent chat_channel or user. MessagesExporter 
failed in such case before, this PR fixes that.
2024-01-30 18:37:11 +04: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
Andrei Prigorshnev 93ca13e534
DEV: Add new chat metrics (#23872)
This adds the following chat metrics:

- _chat_open_channels_with_threads_enabled_ — a count of open channels 
where threading is enabled.
- _chat_channel_messages_ — a count of messages sent in a chat channel 
(i.e. not a personal chat / direct message), within a thread or outside of a thread.
- _chat_threaded_messages_ — a count of messages sent within a thread 
in a chat channel (i.e. not a personal chat / direct messages).
- _chat_direct_messages_ — a count of messages sent in a personal chat / direct messages.

The metrics added using the plugin API introduced in 098ab29d, 
and extended in d91456fd.

Note that these stats won't be exposed at the `about.json` 
and the `site/statistics.json` routes.
2024-01-04 16:10:03 +04:00
David Battersby 1010bbf2ce
FIX: whitelist uploads before creating thumbnail variants (#25013)
Only attempt to create thumbnails for whitelisted upload extensions.
2023-12-22 17:59:53 +08:00
Andrei Prigorshnev fbd24fa6ae
DEV: Allow chat mentions to have several notifications (#24874)
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.
2023-12-19 18:53:00 +04:00
Kelv 2477bcc32e
DEV: lint against Layout/EmptyLineBetweenDefs (#24914) 2023-12-15 23:46:04 +08:00
Jan Cernik 437c2c5552
FIX: Do not display chat replies as threads in transcripts (#24768)
* FIX: Do not display chat replies as threads in transcripts

* specs
2023-12-15 09:50:43 -03:00
Jan Cernik ca3792221a
FIX: Do not notify users for quoted mentions in chat (#24902) 2023-12-14 15:39:28 -03:00
Jarek Radosz 694b5f108b
DEV: Fix various rubocop lints (#24749)
These (21 + 3 from previous PRs) are soon to be enabled in rubocop-discourse:

Capybara/VisibilityMatcher
Lint/DeprecatedOpenSSLConstant
Lint/DisjunctiveAssignmentInConstructor
Lint/EmptyConditionalBody
Lint/EmptyEnsure
Lint/LiteralInInterpolation
Lint/NonLocalExitFromIterator
Lint/ParenthesesAsGroupedExpression
Lint/RedundantCopDisableDirective
Lint/RedundantRequireStatement
Lint/RedundantSafeNavigation
Lint/RedundantStringCoercion
Lint/RedundantWithIndex
Lint/RedundantWithObject
Lint/SafeNavigationChain
Lint/SafeNavigationConsistency
Lint/SelfAssignment
Lint/UnreachableCode
Lint/UselessMethodDefinition
Lint/Void

Previous PRs:
Lint/ShadowedArgument
Lint/DuplicateMethods
Lint/BooleanSymbol
RSpec/SpecFilePathSuffix
2023-12-06 23:25:00 +01:00
Jarek Radosz 4280c01153
DEV: Fix Lint/ShadowedArgument (#24733) 2023-12-06 13:16:10 +01:00
David Battersby 8b46dc8bb5
FEATURE: Add thumbnails for chat image uploads (#24328)
Introduces the concept of image thumbnails in chat, prior to this we uploaded and used full size chat images within channels and direct messages.

The following changes are covered:
- Post processing of image uploads to create the thumbnail within Chat::MessageProcessor
- Extract responsive image ratios into CookedProcessorMixin (used for creating upload variations)
- Add thumbnail to upload serializer from plugin.rb
- Convert chat upload template to glimmer component using .gjs format
- Use thumbnail image within chat upload component (stores full size img in orig-src data attribute)
- Old uploads which don't have thumbnails will fallback to full size images in channels/DMs
- Update Magnific lightbox to use full size image when clicked
- Update Glimmer lightbox to use full size image (enables zooming for chat images)
2023-12-06 14:59:18 +08:00
Martin Brennan 30d5e752d7
DEV: Revert guardian changes (#24742)
I took the wrong approach here, need to rethink.

* Revert "FIX: Use Guardian.basic_user instead of new (anon) (#24705)"

This reverts commit 9057272ee2.

* Revert "DEV: Remove unnecessary method_missing from GuardianUser (#24735)"

This reverts commit a5d4bf6dd2.

* Revert "DEV: Improve Guardian devex (#24706)"

This reverts commit 77b6a038ba.

* Revert "FIX: Introduce Guardian::BasicUser for oneboxing checks (#24681)"

This reverts commit de983796e1.
2023-12-06 16:37:32 +10:00
Martin Brennan 9057272ee2
FIX: Use Guardian.basic_user instead of new (anon) (#24705)
c.f. de983796e1

There will soon be additional login_required checks
for Guardian, and the intent of many checks by automated
systems is better fulfilled by using BasicUser, which
simulates a logged in TL0 forum user, rather than an
anon user.

In some cases the use of anon still makes sense (e.g.
anonymous_cache), and in that case the more explicit
`Guardian.anon_user` is used
2023-12-06 11:56:21 +10:00
Ted Johansson c7667f791e
DEV: Fix chat notifier deprecation warnings from job arguments (#24708)
We're seeing some deprecation warnings in production. This is because we're passing a raw Ruby timestamp, which gets stringified implicitly when written to Redis. As per #15842, this conversion needs to be done explicitly.
2023-12-05 18:03:30 +08:00
Jan Cernik 0af8bbd378
FIX: Multiple nested threads and duplicated messages in chat transcripts (#24685) 2023-12-04 12:43:04 -03:00
Jan Cernik ac9e804dbe
FEATURE: Add threads support to chat archives (#24325)
This PR introduces thread support for channel archives. Now, threaded messages are rendered inside a `details` HTML tag in posts.

The transcript markdown rules now support two new attributes: `threadId` and `threadTitle`.

- If `threadId` is present, all nested `chat` tags are rendered inside the first one.
- `threadTitle` (optional) defines the summary content.

```
[chat threadId=19 ... ]
thread OM

  [chat ... ]
  thread reply
  [/chat]

[/chat]
```

If threads are split across multiple posts when archiving, the range of messages in each part will be displayed alongside the thread title. For example: `(message 1 to 16 of 20)` and `(message 17 to 20 of 20)`.
2023-11-27 15:47:35 +01:00
Joffrey JAFFEUX 57584c38c0
FIX: correctly uses private_email site setting in chat (#24528)
Chat will now check for the state of `SiteSetting.private_email` when sending the summary, when enabled, the mail will not display user information, channel information other than the ID and no message information, only the count of messages.
2023-11-23 15:54:22 +01:00
Daniel Waterworth 0bc568f66d
FIX: Preload the right fields on categories (#24396) 2023-11-15 16:34:03 -06:00
Joffrey JAFFEUX ab832cc865
FEATURE: introduces group channels (#24288)
Group channels will allow users to create channels with a name and invite people. It's possible to add people even after creation of the channel. Removing users is not yet possible but will be added in the near future.

Technically a group channel is `direct_message_channel` with a group attribute set to true on its direct message (chatable). This model might evolve in the future but offers much flexibility for now without having to rely on a complex migration.

The commit essentially consists of:
- a migration to set existing direct message channels with more than 2 users to a group
- a new message creator which allows to search, add members, and create groups
- a new `AddUsersToChannel` service
- a modified `SearchChatable` service
2023-11-10 11:29:28 +01:00
Andrei Prigorshnev d91456fd53
DEV: Ability to collect stats without exposing them via API (#23933)
This adds the ability to collect stats without exposing them 
among other stats via API.

The most important thing I wanted to achieve is to provide 
an API where stats are not exposed by default, and a developer 
has to explicitly specify that they should be 
exposed (`expose_via_api: true`). Implementing an opposite 
solution would be simpler, but that's less safe in terms of 
potential security issues. 

When working on this, I had to refactor the current solution. 
I would go even further with the refactoring, but the next steps 
seem to be going too far in changing the solution we have, 
and that would also take more time. Two things that can be 
improved in the future:
1. Data structures for holding stats can be further improved
2. Core stats are hard-coded in the About template (it's hard 
to fix it without correcting data structures first, see point 1):
    63a0700d45/app/views/about/index.html.erb (L61-L101)

The most significant refactorings are:
1. Introducing the `Stat` model
2. Aligning the way the core and the plugin stats' are registered
2023-11-10 00:44:05 +04:00
Martin Brennan 3c5fb871c0 SECURITY: Filter unread bookmark reminders the user cannot see
There is an edge case where the following occurs:

1. The user sets a bookmark reminder on a post/topic
2. The post/topic is changed to a PM before or after the reminder
   fires, and the notification remains unread by the user
3. The user opens their bookmark reminder notification list
   and they can still see the notification even though they cannot
   access the topic anymore

There is a very low chance for information leaking here, since
the only thing that could be exposed is the topic title if it
changes to something sensitive.

This commit filters the bookmark unread notifications by using
the bookmarkable can_see? methods and also prevents sending
reminder notifications for bookmarks the user can no longer see.
2023-11-09 13:39:16 +11:00
Joffrey JAFFEUX 90efdd7f9d
PERF: cook message in background (#24227)
This commit starts from a simple observation: cooking messages on the hot path can be slow. Especially with a lot of mentions.

To move cooking from the hot path, this commit has made the following changes:

- updating cooked, inserting mentions and notifying user of new mentions has been moved inside the `process_message` job. It happens right after the `Chat::MessageProcessor` run, which is where the cooking happens.
- the similar existing code in `rebake!` has also been moved to rely on the `process_message`job only
- refactored `create_mentions` and `update_mentions` into one single `upsert_mentions` which can be called invariably
- allows services to decide if their job is ran inline or later. It avoids to need to know you have to use `Jobs.run_immediately!` in this case, in tests it will be inline per default
- made various frontend changes to make the chat-channel component lifecycle clearer. we had to handle `did-update @channel` which was super awkward and creating bugs with listeners which the changes of the PR made clear in failing specs
- adds a new `-processed` (and `-not-processed`) class on the chat message, this is made to have a good lifecyle hook in system specs
2023-11-06 15:45:30 +01:00
Andrei Prigorshnev a32fce9e1d
FIX: Further optimize mentioning groups in chat messages (part 2) (#24185)
This is a follow-up to e6299a3. I additionally fixed these three things:

1. Since e6299a3 there's no need anymore to join the group_users table 
when looking for users who were reached by a group mention, so 
I removed that join in that commit. But turned out we were joining 
the group_users table twice, so I removed the second join in this PR. 
That drastically speeded up my test query, from 6 sec to 0.26 sec.
2. We also were joining twice the user_chat_channel_memebership table, 
so I removed the second unnecessary join too.
3. We actually need to join the user_chat_channel_memebership table 
only in certain cases, and we don't need to do that for group mentions, 
so I fixed that too.

As a result of these changes, time of my test query fall down from 
6 sec to 0.001 sec. And the resulting SQL query now contains only 
one JOIN statement.
2023-11-01 17:05:54 +04:00
Andrei Prigorshnev e6299a310f
FIX: Further optimize mentioning groups in chat messages (#24122)
A follow-up to faac6773. This PR eliminates one more heavy join by forcing 
Active Record to do two queries instead.

Also, along the way, I made this change:
```
# this generates two quries to the groups table
def groups_to_mention
  @groups_to_mention = mentionable_groups - groups_with_too_many_members
end

# so I changed it to (this makes only one query to the groups table):
def groups_to_mention
  @groups_to_mention ||= mentionable_groups.where("user_count <= ?", SiteSetting.max_users_notified_per_group_mention)
end
```
This one is kind of a premature optimization, because we don't have evidence that 
this extra query is a problem, but it seems cleaner this way.

Commits history on this PR may help better understand the change.
2023-10-31 18:17:37 +04:00
Jan Cernik 6269134eed
FiX: Update date url for thread oneboxes (#24172) 2023-10-31 08:04:40 -03:00
David Battersby 8465324168
FEATURE: Add new chat indicator preference for Only Mentions (#23848)
Add new chat indicator preference within chat user preferences.

Enabling this option will mean that green notifications will only appear for mentions (within channels and DMs.

This change also enables mentions within direct messages.
2023-10-27 15:58:19 +08:00
Andrei Prigorshnev faac6773c5
FIX: Optimize a slow query when mentioning groups in chat messages (#24103) 2023-10-26 17:37:54 +04:00
Jan Cernik 3f5a00e20f
FEATURE: Add onebox support for chat threads (#23580)
With this commit we now support onboxes of:
- channel
- channel message
- thread
- thread message
2023-10-25 14:30:39 +02:00
David Battersby f1e22dfebd
FEATURE: add grace period for chat edits (#23800)
This change allows users to edit their chat messages based on the criteria added to Site Settings.

If the grace period conditions are met then there will be no (edited) text applied to the message.

The following site settings are added to chat:

chat editing grace period (seconds since message created)
chat editing grace period max diff for low trust levels (number of characters changed)
chat editing grace period max diff for high trust levels (number of characters changed)
2023-10-23 16:40:30 +08:00
Krzysztof Kotlarek c468110929
FEATURE: granular webhooks (#23070)
Before this change, webhooks could be only configured for specific groups like for example, all topic events.

We would like to have more granular control like for example topic_created or topic_destroyed.

Test are failing because plugins changed has to be merged as well:
discourse/discourse-assign#498
discourse/discourse-solved#248
discourse/discourse-topic-voting#159
2023-10-09 03:35:31 +00:00
Sérgio Saquetim e03dd76dc6
FEATURE: add outgoing web hooks for Chat messages 2023-09-13 17:31:42 -03:00
David Battersby 7f7e7fe516
Revert "FEATURE: Add chat message notifications for personal chats (#23307)" (#23559)
This reverts commit 0a1a07fff8.
2023-09-13 19:33:22 +08:00
David Battersby 0a1a07fff8
FEATURE: Add chat message notifications for personal chats (#23307)
This feature adds notifications for chat messages that are sent within personal chats (1:1 and personal group chats).

To prevent notification spam we make use of consolidated notifications to combine updated message information in a meaningful way that allows the receiver to quickly jump into the chat to see what they missed.

This update respects muted channels, muted and blocked users. It will only create a new notification when the user has not muted the channel and the notified user is not muting or ignoring the message sender.
2023-09-13 17:15:11 +08:00
Loïc Guitaut 243793ec6e
DEV: Migrate `Chat::MessageCreator` to a service (#22390)
Currently, the logic for creating a new chat message is scattered
between a controller and an “old” service.

This patch address this issue by creating a new service (using the “new”
sevice object system) encapsulating all the necessary logic.
(authorization, publishing events, etc.)
2023-09-07 08:57:29 +02:00
Jan Cernik aaf47c02bc
DEV: Refactor chat oneboxes (#23031)
- moves the onebox logic away from `plugin.rb` to a new `onebox_handler` lib
- splits the `discourse_chat_message` template into two: one for channels, and one for messages
- refactors the logic code slightly to send only the necessary arguments to each template

This commit shouldn't change end-user behavior.
2023-09-04 16:55:02 +02:00
Mark VanLandingham 9c65e2140a
DEV: Use Notice API for mention warnings (#23238)
This PR swaps out the custom pathway to publishing and rendering mention warnings after a message is sent.

ChatPublisher#publish_notice is used, and expanded. Now, instead of only accepting text_content as an argument, component and component_args are accepted and there is a renderer for these components.

Translations moved to server, as notices expect text to be passed in unless a component is rendered

The warnings are rendered at the top now, outside of the scope of the single message that sent it.

I entirely removed the jit_messages_spec b/c it's duplicate testing of other parts of the app. IMO we don't need a backend test for a feature, a component test for the feature AND a system test (that is slow and potentially even flakey due to timing issues with wait) to test the same thing. So jit_messages_spec is gone.
2023-09-01 09:07:23 -05:00
Ted Johansson 5d5e919530
FIX: Create a reviewable when flagging a chat message for 'something else' (#23264)
In #22914 we added a fix to stop creating reviewables in the review queue when flagging a chat message and choosing the "notify user" option. By mistake we also stopped creating it when selecting the "something else" option.

This change makes it so a "something else" flag once again creates a reviewable. (Same behaviour as posts.)
2023-08-25 17:38:27 +08:00