Commit Graph

6 Commits

Author SHA1 Message Date
Régis Hanol 7cf28fec7b
PERF: optimize chat user membership cleanup when removing a single user (#29833)
This optimizes a hot path when users are being removed from one or more groups since we use the `on(:user_removed_from_group)` event to call the `Chat::AutoLeaveChannels` with a `user_id` parameter. In such case, we don't need to clear the membership of all users, just that one user.

DEBUG: Also added a "-- event = <event>" comment on top of the SQL queries used by the "AutoLeaveChannels" so they show up in the logs and hopefully facilitate any performance issues that might arise in the future.
2024-11-20 09:21:02 +01:00
Régis Hanol 6dfe2fbe16
PERF: auto join & leave chat channels (#29193)
Chat channels that are linked to a category can be set to automatically join users.

This is handled by subscribing to the following events

- group_destroyed
- user_seen
- user_confirmed_email
- user_added_to_group
- user_removed_from_group
- category_updated
- site_setting_changed (for `chat_allowed_groups`)

As well as a

- hourly background job (`AutoJoinUsers`)
- `CreateCategoryChannel` service
- `UpdateChannel` service

There was however two issues with the current implementation

1. We were triggering a lot of background jobs, mostly because it was decided to batch to auto join/leave into groups of 1000 users, adding a lot of stress to the system
2. We had one "class" (a service or a background job) per "event" and all of them had slightly different ways to select users to join/leave, making it hard to keep everything in sync

This PR "simply" adds two new servicesL `AutoJoinChannels` and `AutoLeaveChannels` that takes care, in an efficient way, of all the cases when users might automatically join a leave a chat channel.

Every other changes come from the fact that we're now always calling either one of those services, depending on the event that happened.

In the making of these classes, a few bugs were encountered and fixed, notably

- A user is only ever able to access chat channels if and only if they're part of a group listed in the `chat_allowed_group` site setting
- A category that has no associated "category groups" is only accessible to staff members (and not "Everyone")
- A silenced user should not be able to automatically join channels
- We should not attempt to automatically join users to deleted chat channels
- There is no need to automatically join users to chat channels that have already more than `max_chat_auto_joined_users` users

Internal - t/135259 & t/70607

* DEV: add specs for auto join/leave channels services

* DEV: less hacky specs

* DEV: no instance variables in specs
2024-11-12 15:00:59 +11:00
Ted Johansson f0a46f8b6f
DEV: Automatically update groups for test users with explicit TL (#25415)
For performance reasons we don't automatically add fabricated users to trust level auto-groups. However, when explicitly passing a trust level to the fabricator, in 99% of cases it means that trust level is relevant for the test, and we need the groups.

This change makes it so that when a trust level is explicitly passed to the fabricator, the auto-groups are refreshed. There's no longer a need to also pass refresh_auto_groups: true, which means clearer tests, fewer mistakes, and less confusion.
2024-01-29 17:52:02 +08: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
Daniel Waterworth 6e161d3e75
DEV: Allow fab! without block (#24314)
The most common thing that we do with fab! is:

    fab!(:thing) { Fabricate(:thing) }

This commit adds a shorthand for this which is just simply:

    fab!(:thing)

i.e. If you omit the block, then, by default, you'll get a `Fabricate`d object using the fabricator of the same name.
2023-11-09 16:47:59 -06:00
Martin Brennan 520d4f504b
FEATURE: Auto-remove users without permission from channel (#20344)
There are many situations that may cause users to lose permission to
send messages in a chat channel. Until now we have relied on security
checks in `Chat::ChatChannelFetcher` to remove channels which the
user may have a `UserChatChannelMembership` record for but which
they do not have access to.

This commit takes a more proactive approach. Now any of these following
`DiscourseEvent` triggers may cause `UserChatChannelMembership`
records to be deleted:

* `category_updated` - Permissions of the category changed
   (i.e. CategoryGroup records changed)
* `user_removed_from_group` - Means the user may not be able to access the
   channel based on `GroupUser` or also `chat_allowed_groups`
* `site_setting_changed` - The `chat_allowed_groups` was updated, some
   users may no longer be in groups that can access chat.
* `group_destroyed` - Means the user may not be able to access the
   channel based on `GroupUser` or also `chat_allowed_groups`

All of these are handled in a distinct service run in a background
job. Users removed are logged via `StaffActionLog` and then we
publish messages on a per-channel basis to users who had their
memberships deleted.

When the user has a channel they are kicked from open, we show
a dialog saying "You no longer have access to this channel".

When they click OK we redirect them either:

* To their first other public channel, if they have any followed
* The chat browse page if they don't

This is to save on tons of requests from kicked out users getting messages
from other channels.

When the user does not have the kicked channel open, we can just
silently yoink it out of their sidebar and turn off subscriptions.
2023-03-22 10:19:59 +10:00