# Proposal: Consolidated Review Queue

**URL:** https://meta.discourse.org/t/proposal-consolidated-review-queue/105588
**Category:** Feature
**Created:** [January 3, 2019, 3:33pm UTC](https://meta.discourse.org/t/proposal-consolidated-review-queue/105588 "2019-01-03T15:33:08Z")
**Posts on this page:** 1
**Showing post:** 8

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [January 8, 2019, 9:52pm UTC](https://meta.discourse.org/t/proposal-consolidated-review-queue/105588/8 "2019-01-08T21:52:16Z")

</div>

I’ve made some good progress on the design spike of this feature over the last week. I’m working in this branch (which I force push to frequently) if you want to follow along:

[https://github.com/discourse/discourse/tree/reviewable](https://github.com/discourse/discourse/tree/reviewable)

### Current Design

The current design is you have a `Reviewable` model, which uses Rails’ [Single Table Inheritance](https://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html). If you have a thing you want to be added to the review queue, you create a model for it that extends `Reviewable`. For example a `ReviewableUser` would represent a `User` that needs review.

Each `Reviewable` has a polymorphic association called `target`. For a `ReviewableUser` you’d set it to be the `User` you want reviewed:

```plaintext
reviewable = ReviewableUser.needs_review!(target: user, created_by: current_user)` 

```

You can then establish the `actions` that can be performed on a `ReviewableUser`:

```plaintext
class ReviewableUser < Reviewable

  def build_actions(actions, guardian)
    return unless pending?

    actions.add(:approve) if guardian.can_approve?(target)
    actions.add(:reject) if guardian.can_delete_user?(target)
  end

  def perform_approve(performed_by)
    target.approved = true
    target.approved_by ||= approved_by
    target.approved_at ||= Time.zone.now
    target.save!

    PerformResult.new(:success, transition_to: :approved)
  end

  def perform_reject(performed_by)
    destroyer = UserDestroyer.new(performed_by)
    destroyer.destroy(target)

    PerformResult.new(:success, transition_to: :rejected)
  rescue UserDestroyer::PostsExistError
    PerformResult.new(:failed)
  end
end

```

A few notes about actions:

- They can be built based on the user requesting their list of stuff to review. So it’s easy to add logic that says only certain user types (admins? in a group?).

- The UI will build buttons for those actions. When selected, the call will delegate to the `perform_#{action_id}` method to do the thing. The results of operations can be success/failure, and can optionally return a new state for the reviewable. So in the code above, the `perform_approve` action handler will transition the reviewable to `approved` when complete.

### More Fun Stuff

- Reviewable content has its own system for choose who can see it. You can restrict a reviewable to be shown only do admins, to moderators, or to a particular group.

- I am building in the ability to “claim” a reviewable. Claiming topics for moderation currently works via the discourse-assign plugin but it’s very awkward and buggy. Most people probably won’t use it but having the ability to do at a row level will help a lot.

---

_[View the full topic](https://meta.discourse.org/t/proposal-consolidated-review-queue/105588)._
