Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
Already on GitHub? Sign in to your account
AO3-5234 Moderate Works #3162
Merged
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
2ffed73
AO3-5234: Add admin pages for reviewing and updating moderated spam w…
elzj db1be44
AO3-5234 Frontend tweaks
sarken 038c5fe
AO3-5234: Add admin setting for automatically hiding spam works
elzj 4f7d7ae
AO3-5234: Testing spam features
elzj 76d9efd
AO3-5234: Unhide ham
elzj eb04931
AO3-5234: Add pagination for admin page
elzj b5075ed
AO3-5234: Send emails about hiding spam works and hide works on revie…
elzj
Jump to file or symbol
Failed to load files and symbols.
| @@ -0,0 +1,30 @@ | ||
| +class Admin::SpamController < ApplicationController | ||
| + before_action :admin_only | ||
| + | ||
| + def index | ||
| + conditions = case params[:show] | ||
| + when "reviewed" | ||
| + { reviewed: true, approved: false } | ||
| + when "approved" | ||
| + { approved: true } | ||
| + else | ||
| + { reviewed: false, approved: false } | ||
| + end | ||
| + @works = ModeratedWork.where(conditions).order(:created_at).page(params[:page]) | ||
| + end | ||
| + | ||
| + def bulk_update | ||
| + if ModeratedWork.bulk_update(spam_params) | ||
| + flash[:notice] = "Works were successfully updated" | ||
| + else | ||
| + flash[:error] = "Sorry, please try again" | ||
| + end | ||
| + redirect_to admin_spam_index_path | ||
| + end | ||
| + | ||
| + private | ||
| + | ||
| + def spam_params | ||
| + params.slice(:spam, :ham) | ||
| + end | ||
| +end |
| @@ -0,0 +1,73 @@ | ||
| +class ModeratedWork < ApplicationRecord | ||
| + belongs_to :work | ||
| + validates :work_id, uniqueness: true | ||
| + | ||
| + delegate :title, :revised_at, to: :work | ||
| + | ||
| + def self.register(work) | ||
| + find_or_create_by(work_id: work.id) | ||
| + end | ||
| + | ||
| + def self.mark_reviewed(work) | ||
| + register(work).mark_reviewed! | ||
| + end | ||
| + | ||
| + def self.mark_approved(work) | ||
| + register(work).mark_approved! | ||
| + end | ||
| + | ||
| + def self.bulk_update(params = {}) | ||
| + ids = processed_bulk_ids(params) | ||
| + transaction do | ||
| + bulk_review(ids[:spam]) | ||
| + bulk_approve(ids[:ham]) | ||
| + end | ||
| + end | ||
| + | ||
| + def self.processed_bulk_ids(params = {}) | ||
| + spam_ids = params[:spam] || [] | ||
| + ham_ids = params[:ham] || [] | ||
| + # Ensure no overlap | ||
| + admin_confusion = spam_ids & ham_ids | ||
| + if admin_confusion | ||
| + spam_ids -= admin_confusion | ||
| + ham_ids -= admin_confusion | ||
| + end | ||
| + { spam: spam_ids, ham: ham_ids } | ||
| + end | ||
| + | ||
| + def self.bulk_review(ids) | ||
| + return unless ids.present? | ||
| + where(id: ids).update_all("reviewed = 1") | ||
| + admin_settings = Rails.cache.fetch("admin_settings"){ AdminSetting.first } | ||
| + # If spam isn't hidden by default, hide it now | ||
| + unless admin_settings.hide_spam? | ||
| + Work.joins(:moderated_work).where("moderated_works.id IN (?)", ids).each do |work| | ||
| + work.update_attribute(:hidden_by_admin, true) | ||
| + end | ||
| + end | ||
| + end | ||
| + | ||
| + def self.bulk_approve(ids) | ||
| + return unless ids.present? | ||
| + where(id: ids).update_all("approved = 1") | ||
| + Work.joins(:moderated_work).where("moderated_works.id IN (?)", ids).each do |work| | ||
| + work.mark_as_ham! | ||
| + end | ||
| + end | ||
| + | ||
| + def mark_reviewed! | ||
| + update_attribute(:reviewed, true) | ||
| + end | ||
| + | ||
| + def mark_approved! | ||
| + update_attribute(:approved, true) | ||
| + end | ||
| + | ||
| + # Easy access to the creators of spam works | ||
| + def admin_user_links | ||
| + work.users.map do |u| | ||
| + "<a href='/admin/users/#{u.to_param}'>#{u.login}</a>" | ||
| + end.join(", ").html_safe | ||
| + end | ||
| +end |
| @@ -0,0 +1,78 @@ | ||
| +<!--Descriptive page name, messages and instructions--> | ||
| +<h2 class="heading"><%= ts("Works Marked as Spam") %></h2> | ||
| +<!--/descriptions--> | ||
| + | ||
| +<!--subnav--> | ||
| +<!--/subnav--> | ||
| + | ||
| +<!--main content--> | ||
| +<%= form_tag "/admin/spam/bulk_update", method: :post do %> | ||
| + <%= submit_button nil, ts("Update Works") %> | ||
| + <table id="spam_works" summary="<%= ts("Titles, creators, and revision dates for works that have been automatically marked as spam, along with options to verify or correct their spam status.") %>"> | ||
| + <caption><%= ts("Works Marked as Spam") %></caption> | ||
| + <thead> | ||
| + <tr> | ||
| + <th scope="col"><%= ts("Title") %></th> | ||
| + <th scope="col"><%= ts("Creator") %></th> | ||
| + <th scope="col"><%= ts("Revised At") %></th> | ||
| + <th scope="col"> | ||
| + <%= ts("Mark Reviewed") %> | ||
| + <ul class="actions"> | ||
| + <li> | ||
| + <button id="spam_all_select" type="button"> | ||
| + <%= ts("All") %> | ||
| + </button> | ||
| + </li> | ||
| + <li> | ||
| + <button id="spam_all_deselect" type="button"> | ||
| + <%= ts("None") %> | ||
| + </button> | ||
| + </li> | ||
| + </ul> | ||
| + </th> | ||
| + <th scope="col"> | ||
| + <%= ts("Mark As Not Spam") %> | ||
| + <ul class="actions"> | ||
| + <li> | ||
| + <button id="ham_all_select" type="button"> | ||
| + <%= ts("All") %> | ||
| + </button> | ||
| + </li> | ||
| + <li> | ||
| + <button id="ham_all_deselect" type="button"> | ||
| + <%= ts("None") %> | ||
| + </button> | ||
| + </li> | ||
| + </ul> | ||
| + </th> | ||
| + </tr> | ||
| + </thead> | ||
| + <tbody> | ||
| + <% @works.each do |work| %> | ||
| + <tr> | ||
| + <th scope="row"> | ||
| + <%= link_to work.title, work_path(id: work.work_id) %> | ||
| + </th> | ||
| + <td><%= work.admin_user_links %></td> | ||
| + <td><%= work.revised_at %></td> | ||
| + <td> | ||
| + <%= check_box_tag 'spam[]', work.id, nil, id: "spam_#{work.id}" %> | ||
| + <%= label_tag "spam_#{work.id}", "Spam" %> | ||
| + </td> | ||
| + <td> | ||
| + <%= check_box_tag 'ham[]', work.id, nil, id: "ham_#{work.id}" %> | ||
| + <%= label_tag "ham_#{work.id}", "Not Spam" %> | ||
| + </td> | ||
| + </tr> | ||
| + <% end %> | ||
| + </tbody> | ||
| + </table> | ||
| + <%= submit_button nil, ts("Update Works") %> | ||
| +<% end %> | ||
| + | ||
| +<%= will_paginate @works %> | ||
| +<!--/content--> | ||
| + | ||
| +<% content_for :footer_js do %> | ||
| + <%= javascript_include_tag "select_all" %> | ||
| +<% end %> |
| @@ -0,0 +1,11 @@ | ||
| +class CreateModeratedWorks < ActiveRecord::Migration[5.1] | ||
| + def change | ||
| + create_table :moderated_works do |t| | ||
| + t.references :work, null: false #, foreign_key: true | ||
| + t.boolean :approved, null: false, default: false | ||
| + t.boolean :reviewed, null: false, default: false | ||
| + | ||
| + t.timestamps | ||
| + end | ||
| + end | ||
| +end |
| @@ -0,0 +1,5 @@ | ||
| +class AddSpamHidingToAdminSettings < ActiveRecord::Migration[5.1] | ||
| + def change | ||
| + add_column :admin_settings, :hide_spam, :boolean, default: false, null: false | ||
| + end | ||
| +end |
| @@ -0,0 +1,22 @@ | ||
| +@admin | ||
| +Feature: Admin spam management | ||
| + In order to manage spam works | ||
| + As an an admin | ||
| + I want to be able to view and update works marked as spam | ||
| + | ||
| +Scenario: Review spam | ||
| + Given the spam work "Spammity Spam" | ||
| + And the spam work "Totally Legit" | ||
| + And I am logged in as an admin | ||
| + Then I should see "Spam" | ||
| + When I follow "Spam" | ||
| + Then I should see "Works Marked as Spam" | ||
| + And I should see "Spammity" | ||
| + And I should see "Totally Legit" | ||
| + When I check "spam_1" | ||
| + And I check "ham_2" | ||
| + And I press "Update Works" | ||
| + Then I should not see "Spammity" | ||
| + And I should not see "Totally Legit" | ||
| + And the work "Spammity Spam" should be hidden | ||
| + And the work "Totally Legit" should not be hidden |
Oops, something went wrong.
'$j' is not defined.