diff --git a/app/controllers/tag_wranglers_controller.rb b/app/controllers/tag_wranglers_controller.rb index 8419905245d..9722cbb3c87 100644 --- a/app/controllers/tag_wranglers_controller.rb +++ b/app/controllers/tag_wranglers_controller.rb @@ -6,6 +6,8 @@ class TagWranglersController < ApplicationController before_action :check_permission_to_wrangle, except: [:report_csv] def index + authorize :wrangling, :full_access? if logged_in_as_admin? + @wranglers = Role.find_by(name: "tag_wrangler").users.alphabetical conditions = ["canonical = 1"] joins = "LEFT JOIN wrangling_assignments ON (wrangling_assignments.fandom_id = tags.id) @@ -39,6 +41,8 @@ def index end def show + authorize :wrangling if logged_in_as_admin? + @wrangler = User.find_by!(login: params[:id]) @page_subtitle = @wrangler.login @fandoms = @wrangler.fandoms.by_name @@ -46,7 +50,7 @@ def show end def report_csv - authorize :tag_wrangler, :report_csv? + authorize :wrangling wrangler = User.find_by!(login: params[:id]) wrangled_tags = Tag @@ -64,6 +68,8 @@ def report_csv end def create + authorize :wrangling if logged_in_as_admin? + unless params[:tag_fandom_string].blank? names = params[:tag_fandom_string].gsub(/$/, ',').split(',').map(&:strip) fandoms = Fandom.where('name IN (?)', names) @@ -95,6 +101,8 @@ def create end def destroy + authorize :wrangling if logged_in_as_admin? + wrangler = User.find_by(login: params[:id]) assignment = WranglingAssignment.where(user_id: wrangler.id, fandom_id: params[:fandom_id]).first assignment.destroy diff --git a/app/policies/tag_wrangler_policy.rb b/app/policies/tag_wrangler_policy.rb deleted file mode 100644 index f71e9ac1839..00000000000 --- a/app/policies/tag_wrangler_policy.rb +++ /dev/null @@ -1,7 +0,0 @@ -class TagWranglerPolicy < ApplicationPolicy - WRANGLING_REPORT = %w[superadmin tag_wrangling].freeze - - def report_csv? - user_has_roles?(WRANGLING_REPORT) - end -end diff --git a/app/policies/wrangling_policy.rb b/app/policies/wrangling_policy.rb new file mode 100644 index 00000000000..40acf51c97a --- /dev/null +++ b/app/policies/wrangling_policy.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class WranglingPolicy < ApplicationPolicy + FULL_ACCESS_ROLES = %w[superadmin tag_wrangling].freeze + + def full_access? + user_has_roles?(FULL_ACCESS_ROLES) + end + + alias create? full_access? + alias destroy? full_access? + alias show? full_access? + alias report_csv? full_access? +end diff --git a/factories/wrangling_assignments.rb b/factories/wrangling_assignments.rb new file mode 100644 index 00000000000..1373dc4271f --- /dev/null +++ b/factories/wrangling_assignments.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :wrangling_assignment do + user + fandom + end +end diff --git a/spec/controllers/tag_wranglers_controller_spec.rb b/spec/controllers/tag_wranglers_controller_spec.rb index 60a9f3a129a..9b03c293b11 100644 --- a/spec/controllers/tag_wranglers_controller_spec.rb +++ b/spec/controllers/tag_wranglers_controller_spec.rb @@ -4,8 +4,74 @@ include LoginMacros include RedirectExpectationHelper + wrangling_roles = %w[superadmin tag_wrangling] + let(:user) { create(:tag_wrangler) } + shared_examples "denies access to unauthorized admins" do |verb, action, **kwargs| + context "when logged in as an admin with no role" do + let(:admin) { create(:admin) } + + before do + fake_login_admin(admin) + send(verb, action, **kwargs) + end + + it "redirects with an error" do + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + + (Admin::VALID_ROLES - wrangling_roles).each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + before do + fake_login_admin(admin) + send(verb, action, **kwargs) + end + + it "redirects with an error" do + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + end + + before(:all) do + Role.find_or_create_by(name: "tag_wrangler") + end + + describe "#index" do + it_behaves_like "denies access to unauthorized admins", :get, :index + + wrangling_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + before do + fake_login_admin(admin) + end + + it "allows access" do + get :index + expect(response).to have_http_status(:success) + end + end + end + + context "when logged in as a tag wrangler" do + before do + fake_login_known_user(user) + end + + it "allows access" do + get :index + expect(response).to have_http_status(:success) + end + end + end + describe "#show" do before { fake_login_known_user(user) } @@ -16,6 +82,23 @@ end.to raise_exception(ActiveRecord::RecordNotFound) end end + + it_behaves_like "denies access to unauthorized admins", :get, :show, params: { id: -1 } + + wrangling_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + before do + fake_login_admin(admin) + end + + it "allows access" do + get :show, params: { id: user.login } + expect(response).to have_http_status(:success) + end + end + end end describe "#report_csv" do @@ -36,28 +119,12 @@ it_behaves_like "prevents access to the report" end - context "when logged in as an admin without proper authorization" do - before { fake_login_admin(admin) } - - context "with no role" do - let(:admin) { create(:admin) } - - it_behaves_like "prevents access to the report" - end - - (Admin::VALID_ROLES - %w[superadmin tag_wrangling]).each do |admin_role| - context "with role #{admin_role}" do - let(:admin) { create(:admin, roles: [admin_role]) } - - it_behaves_like "prevents access to the report" - end - end - end + it_behaves_like "denies access to unauthorized admins", :get, :report_csv, params: { id: 0 } context "when logged in as an admin with proper authorization" do before { fake_login_admin(admin) } - %w[superadmin tag_wrangling].each do |admin_role| + wrangling_roles.each do |admin_role| context "with role #{admin_role}" do let(:admin) { create(:admin, roles: [admin_role]) } @@ -75,7 +142,7 @@ result = CSV.parse(response.body.encode("utf-8")[1..], col_sep: "\t") expect(result) - .to eq([%w[Name Last\ Updated Type Merger Fandoms Unwrangleable], + .to eq([["Name", "Last Updated", "Type", "Merger", "Fandoms", "Unwrangleable"], [tag1.name, tag1.updated_at.to_s, tag1.type, "", "", "false"]]) end @@ -100,7 +167,7 @@ result = CSV.parse(response.body.encode("utf-8")[1..], col_sep: "\t") expect(result) - .to eq([%w[Name Last\ Updated Type Merger Fandoms Unwrangleable], + .to eq([["Name", "Last Updated", "Type", "Merger", "Fandoms", "Unwrangleable"], [tag2.name, tag2.updated_at.to_s, tag2.type, tag1.name, "", "false"], [tag1.name, tag1.updated_at.to_s, tag1.type, "", "", "false"]]) end @@ -114,7 +181,7 @@ result = CSV.parse(response.body.encode("utf-8")[1..], col_sep: "\t") expect(result) - .to eq([%w[Name Last\ Updated Type Merger Fandoms Unwrangleable], + .to eq([["Name", "Last Updated", "Type", "Merger", "Fandoms", "Unwrangleable"], [tag.name, tag.updated_at.to_s, tag.type, "", fandom.name, "false"]]) end @@ -129,7 +196,7 @@ result = CSV.parse(response.body.encode("utf-8")[1..], col_sep: "\t") expect(result) - .to eq([%w[Name Last\ Updated Type Merger Fandoms Unwrangleable], + .to eq([["Name", "Last Updated", "Type", "Merger", "Fandoms", "Unwrangleable"], [tag.name, tag.updated_at.to_s, tag.type, "", "#{fandom1.name}, #{fandom2.name}", "false"]]) end @@ -151,11 +218,51 @@ result = CSV.parse(response.body.encode("utf-8")[1..], col_sep: "\t") expect(result) - .to eq([%w[Name Last\ Updated Type Merger Fandoms Unwrangleable], + .to eq([["Name", "Last Updated", "Type", "Merger", "Fandoms", "Unwrangleable"], [tag.name, tag.updated_at.to_s, tag.type, "", "", "true"]]) end end end end end + + describe "#create" do + it_behaves_like "denies access to unauthorized admins", :post, :create + + wrangling_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + let(:fandom) { create(:fandom) } + + before do + fake_login_admin(admin) + end + + it "creates wrangling assignments" do + post :create, params: { assignments: { fandom.id.to_s => [user.login] } } + it_redirects_to_with_notice(tag_wranglers_path, "Wranglers were successfully assigned!") + end + end + end + end + + describe "#destroy" do + it_behaves_like "denies access to unauthorized admins", :delete, :destroy, params: { id: 0, fandom_id: 0 } + + wrangling_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + let(:wrangling_assignment) { create(:wrangling_assignment) } + + before do + fake_login_admin(admin) + end + + it "removes the wrangling assignment" do + delete :destroy, params: { id: wrangling_assignment.user.login, fandom_id: wrangling_assignment.fandom.id } + it_redirects_to_with_notice(tag_wranglers_path, "Wranglers were successfully unassigned!") + end + end + end + end end