What is the problem?
The review queue throws a JavaScript error when processing MessageBus
updates:
```
MESSAGE BUS FAIL: callback /reviewable_action caused exception
TypeError: Cannot read properties of undefined (reading 'includes')
```
The bug flow is:
1. `Reviewable::PerformResult#initialize` only sets
`@remove_reviewable_ids`
when `success?` is true, leaving it nil otherwise
2. `ReviewablePerformResultSerializer` serializes nil as JSON null
3. MessageBus publishes this to `/reviewable_action` channel
4. The JS `_updateStatus` callback in `ReviewableItem` receives data
with
`remove_reviewable_ids` as null/undefined
5. Calling `.includes()` on null throws TypeError
What is the solution?
Always initialize `@remove_reviewable_ids` as an array in
`Reviewable::PerformResult#initialize` (empty for failures, containing
the reviewable id for successes). Also add defensive optional chaining
in the JS `ReviewableItem#_updateStatus` callback and update the truthy
check in `ReviewableItem#_performResult` to verify array length since
`[]` is truthy in JavaScript.
With reviewables now being able to have multiple actions performed on
them, we don't want to update the final reviewable state until an action
from every action bundle has been performed.
This change makes use of the new `ReviewableActionLog`, logging actions
when they occur, then checking to see if a reviewable has had all
actions performed before finalising it.
This is a step towards unifying how reviewable types are defined.
In this change, we add a new `ReviewableActionBuilder` concern, which can be included by the various reviewable types to give them a standard helper for adding actions that can be performed on the reviewable.
The first feature for this concern takes the `build_action()` helper that some reviewables used, and makes it available to all reviewables. This is done in a backward compatible fashion, so it will work even whilst we transition to the new reviewable UI.
When performing an action in the review queue, this change makes two improvements:
- The buttons on the reviewable item are disabled, so you can't accidentally multi-click.
- A toast is displayed when the action is complete, as a success indication.
Followup c7e471d35a
It is currently possible to add a bundle (which is a collection
of actions used for a dropdown on the client) for a reviewable
via actions.add_bundle and then never add any actions to it.
This causes the client to explode, as seen in the referenced
commit, because of the way our store expects to resolve objects
referenced by ID that are passed down by the serializer, which
then causes Ember to have an unrecoverable render error.
Fixing this on the serializer level is not really possible because
of all the ActiveModel::Serializer magic that serializes
objects by ID reference when doing things like has_many.
`Reviewable#actions_for` is a better place to do this anyway,
because this is the main location where the bundles and actions
are built for every action via the serializer.
Currently, if the review queue has both a flagged post and a flagged chat message, one of the two will have some of the labels of their actions replaced by those of the other. In other words, the labels are getting mixed up. For example, a flagged chat message might show up with an action labelled "Delete post".
This is happening because when using bundles, we are sending along the actions in a separate part of the response, so they can be shared by many reviewables. The bundles then index into this bag of actions by their ID, which is something generic describing the server action, e.g. "agree_and_delete".
The problem here is the same action can have different labels depending on the type of reviewable. Now that the bag of actions contains multiple actions with the same ID, which one is chosen is arbitrary. I.e. it doesn't distinguish based on the type of the reviewable.
This change adds an additional field to the actions, server_action, which now contains what used to be the ID. Meanwhile, the ID has been turned into a concatenation of the reviewable type and the server action, e.g. post-agree_and_delete.
This still provides the upside of denormalizing the actions while allowing for different reviewable types to have different labels and descriptions.
At first I thought I would prepend the reviewable type to the ID, but this doesn't work well because the ID is used on the server-side to determine which actions are possible, and these need to be shared between different reviewables. Hence the introduction of server_action, which now serves that purpose.
I also thought about changing the way that the bundle indexes into the bag of actions, but this is happening through some EmberJS mechanism, so we don't own that code.
Plugins like chat add custom score type to override the title in the UI, but that should be reserved for situations when you need to manage the flag priority separately, which is configurable in the queue settings page.
Currently, if a plugin creates a custom score type, it won't be able to associate a priority, so there's no real gain from doing so. Priorities are tightly related to post-action types, which is something we might want to revise. For now, this change lets plugins move away from custom score types without compromises.
Feature for `Must Approve Users` setup. When a user is rejected, a staff member can optionally set a reason for audit purposes. In addition, feedback email can be sent to the user.
Meta: https://meta.discourse.org/t/account-rejection-email/103112/8
- Increase size of the reviewable's conversation excerpt to prevent truncation of the new copy
- Remove the `domain` parameter from the `flag_linked_posts_as_spam` method in the user model since it is no longer needed
- Remove the `domain` interpolation variable from all translation files
- Add "All posts from this user that include links should be reviewed." to server.en.yml for added clarity on why the posts entered the queue
Zeitwerk simplifies working with dependencies in dev and makes it easier reloading class chains.
We no longer need to use Rails "require_dependency" anywhere and instead can just use standard
Ruby patterns to require files.
This is a far reaching change and we expect some followups here.
This reduces chances of errors where consumers of strings mutate inputs
and reduces memory usage of the app.
Test suite passes now, but there may be some stuff left, so we will run
a few sites on a branch prior to merging
Includes support for flags, reviewable users and queued posts, with REST API
backwards compatibility.
Co-Authored-By: romanrizzi <romanalejandro@gmail.com>
Co-Authored-By: jjaffeux <j.jaffeux@gmail.com>