diff --git a/app/components/admin/header.rb b/app/components/admin/header.rb new file mode 100644 index 000000000..015af44b0 --- /dev/null +++ b/app/components/admin/header.rb @@ -0,0 +1,13 @@ +module Admin::Header + extend ActiveSupport::Concern + + def header(options: {}) + provide(:title) do + title + end + + tag.h2 options do + title + end + end +end diff --git a/app/components/admin/sdg/managers/index_component.html.erb b/app/components/admin/sdg/managers/index_component.html.erb new file mode 100644 index 000000000..1abb68e4f --- /dev/null +++ b/app/components/admin/sdg/managers/index_component.html.erb @@ -0,0 +1,38 @@ +<%= header %> + +<%= render "admin/shared/user_search", url: admin_sdg_managers_path %> + +
+ <% if users.any? %> +

<%= page_entries_info users %>

+ + + + + + + + + <% users.each do |user| %> + + + + + + <% end %> + +
<%= SDG::Manager.human_attribute_name(:name) %><%= SDG::Manager.human_attribute_name(:email) %><%= t("admin.shared.actions") %>
+ <%= user.name %> + + <%= user.email %> + + <%= render Admin::Roles::TableActionsComponent.new(user.sdg_manager || user.build_sdg_manager) %> +
+ + <%= paginate users %> + <% else %> +
+ <%= t("admin.sdg_managers.index.no_sdg_managers") %> +
+ <% end %> +
diff --git a/app/components/admin/sdg/managers/index_component.rb b/app/components/admin/sdg/managers/index_component.rb new file mode 100644 index 000000000..d935f43e8 --- /dev/null +++ b/app/components/admin/sdg/managers/index_component.rb @@ -0,0 +1,15 @@ +class Admin::SDG::Managers::IndexComponent < ApplicationComponent + include Admin::Header + + attr_reader :users + + def initialize(users) + @users = users + end + + private + + def title + SDG::Manager.model_name.human(count: 2).upcase_first + end +end diff --git a/app/controllers/admin/sdg/managers_controller.rb b/app/controllers/admin/sdg/managers_controller.rb new file mode 100644 index 000000000..3310e47f0 --- /dev/null +++ b/app/controllers/admin/sdg/managers_controller.rb @@ -0,0 +1,23 @@ +class Admin::SDG::ManagersController < Admin::BaseController + load_and_authorize_resource instance_name: :sdg_manager, class: "SDG::Manager" + + def index + if params[:search] + @users = User.accessible_by(current_ability).search(params[:search]).page(params[:page]) + else + @users = User.accessible_by(current_ability).sdg_managers.page(params[:page]) + end + end + + def create + @sdg_manager.user_id = params[:user_id] + @sdg_manager.save! + + redirect_to admin_sdg_managers_path + end + + def destroy + @sdg_manager.destroy! + redirect_to admin_sdg_managers_path + end +end diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index 978672daf..e93e68e96 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -56,6 +56,7 @@ module Abilities can [:search, :create, :index, :destroy], ::Moderator can [:search, :show, :edit, :update, :create, :index, :destroy, :summary], ::Valuator can [:search, :create, :index, :destroy], ::Manager + can [:create, :read, :destroy], ::SDG::Manager can [:search, :index], ::User can :manage, Dashboard::Action diff --git a/app/models/user.rb b/app/models/user.rb index 083f21732..f20db4bea 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -95,6 +95,7 @@ class User < ApplicationRecord scope :administrators, -> { joins(:administrator) } scope :moderators, -> { joins(:moderator) } scope :organizations, -> { joins(:organization) } + scope :sdg_managers, -> { joins(:sdg_manager) } scope :officials, -> { where("official_level > 0") } scope :male, -> { where(gender: "male") } scope :female, -> { where(gender: "female") } diff --git a/app/views/admin/sdg/managers/index.html.erb b/app/views/admin/sdg/managers/index.html.erb new file mode 100644 index 000000000..b884b74df --- /dev/null +++ b/app/views/admin/sdg/managers/index.html.erb @@ -0,0 +1 @@ +<%= render Admin::SDG::Managers::IndexComponent.new(@users) %> diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 73edfc440..bc561d093 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -4,6 +4,9 @@ en: results_enabled: "Show results" stats_enabled: "Show stats" advanced_stats_enabled: "Show advanced stats" + name: Name + email: Email + description: Description activerecord: models: activity: @@ -78,6 +81,9 @@ en: sdg/local_target: one: "local target" other: "local targets" + sdg/manager: + one: "SDG manager" + other: "SDG managers" sdg/target: one: "target" other: "targets" diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 6c05bf15c..8fe8c4236 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -621,6 +621,12 @@ en: add: Add search: title: "Managers: User search" + sdg_managers: + index: + no_sdg_managers: There are no users. + sdg/managers: + sdg/manager: + add: Add menu: activity: Moderator activity admin: Admin menu @@ -637,6 +643,7 @@ en: hidden_users: Hidden users administrators: Administrators managers: Managers + sdg_managers: SDG Managers moderators: Moderators messaging_users: Messages to users newsletters: Newsletters diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 070ec9aa4..96f7fcd63 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -4,6 +4,9 @@ es: results_enabled: "Mostrar resultados" stats_enabled: "Mostrar estadísticas" advanced_stats_enabled: "Mostrar estadísticas avanzadas" + name: Nombre + email: Email + description: Descripción activerecord: models: activity: @@ -78,6 +81,9 @@ es: sdg/local_target: one: "meta localizada" other: "metas localizadas" + sdg/manager: + one: "gestor ODS" + other: "gestores ODS" sdg/target: one: "meta" other: "metas" diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index f970c74f4..0c18e9209 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -620,6 +620,12 @@ es: add: Añadir como gestor search: title: "Gestores: Búsqueda de usuarios" + sdg_managers: + index: + no_sdg_managers: No hay usuarios. + sdg/managers: + sdg/manager: + add: Añadir como gestor ODS menu: activity: Actividad de moderadores admin: Menú de administración @@ -636,6 +642,7 @@ es: hidden_users: Usuarios bloqueados administrators: Administradores managers: Gestores + sdg_managers: Gestores ODS moderators: Moderadores messaging_users: Mensajes a usuarios newsletters: Newsletters diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 20300220c..632a91a64 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -113,6 +113,10 @@ namespace :admin do get :search, on: :collection end + namespace :sdg do + resources :managers, only: [:index, :create, :destroy] + end + resources :administrators, only: [:index, :create, :destroy, :edit, :update] do get :search, on: :collection end diff --git a/spec/models/abilities/administrator_spec.rb b/spec/models/abilities/administrator_spec.rb index 47534629e..f237964dc 100644 --- a/spec/models/abilities/administrator_spec.rb +++ b/spec/models/abilities/administrator_spec.rb @@ -109,4 +109,8 @@ describe Abilities::Administrator do it { should be_able_to(:read, SDG::Goal) } it { should be_able_to(:read, SDG::Target) } + + it { should be_able_to(:read, SDG::Manager) } + it { should be_able_to(:create, SDG::Manager) } + it { should be_able_to(:destroy, SDG::Manager) } end diff --git a/spec/models/abilities/common_spec.rb b/spec/models/abilities/common_spec.rb index f90960888..336116012 100644 --- a/spec/models/abilities/common_spec.rb +++ b/spec/models/abilities/common_spec.rb @@ -307,4 +307,8 @@ describe Abilities::Common do it { should_not be_able_to(:read, SDG::Goal) } it { should_not be_able_to(:read, SDG::Target) } + + it { should_not be_able_to(:read, SDG::Manager) } + it { should_not be_able_to(:create, SDG::Manager) } + it { should_not be_able_to(:delete, SDG::Manager) } end diff --git a/spec/models/abilities/everyone_spec.rb b/spec/models/abilities/everyone_spec.rb index 0b27be818..a5399e25b 100644 --- a/spec/models/abilities/everyone_spec.rb +++ b/spec/models/abilities/everyone_spec.rb @@ -55,4 +55,8 @@ describe Abilities::Everyone do it { should_not be_able_to(:read, SDG::Goal) } it { should_not be_able_to(:read, SDG::Target) } + + it { should_not be_able_to(:read, SDG::Manager) } + it { should_not be_able_to(:create, SDG::Manager) } + it { should_not be_able_to(:delete, SDG::Manager) } end diff --git a/spec/models/abilities/moderator_spec.rb b/spec/models/abilities/moderator_spec.rb index 55e39372e..762583534 100644 --- a/spec/models/abilities/moderator_spec.rb +++ b/spec/models/abilities/moderator_spec.rb @@ -111,4 +111,8 @@ describe Abilities::Moderator do it { should_not be_able_to(:read, SDG::Goal) } it { should_not be_able_to(:read, SDG::Target) } + + it { should_not be_able_to(:read, SDG::Manager) } + it { should_not be_able_to(:create, SDG::Manager) } + it { should_not be_able_to(:delete, SDG::Manager) } end diff --git a/spec/models/abilities/organization_spec.rb b/spec/models/abilities/organization_spec.rb index d10ac4507..2553b3f18 100644 --- a/spec/models/abilities/organization_spec.rb +++ b/spec/models/abilities/organization_spec.rb @@ -25,4 +25,8 @@ describe "Abilities::Organization" do it { should_not be_able_to(:read, SDG::Goal) } it { should_not be_able_to(:read, SDG::Target) } + + it { should_not be_able_to(:read, SDG::Manager) } + it { should_not be_able_to(:create, SDG::Manager) } + it { should_not be_able_to(:delete, SDG::Manager) } end diff --git a/spec/models/abilities/sdg/manager.rb b/spec/models/abilities/sdg/manager.rb index 910b886e2..004ad0ada 100644 --- a/spec/models/abilities/sdg/manager.rb +++ b/spec/models/abilities/sdg/manager.rb @@ -9,4 +9,8 @@ describe "Abilities::SDG::Manager" do it { should be_able_to(:read, SDG::Goal) } it { should be_able_to(:read, SDG::Target) } + + it { should_not be_able_to(:read, SDG::Manager) } + it { should_not be_able_to(:create, SDG::Manager) } + it { should_not be_able_to(:delete, SDG::Manager) } end diff --git a/spec/models/abilities/valuator_spec.rb b/spec/models/abilities/valuator_spec.rb index a8eeeb236..634dd7e92 100644 --- a/spec/models/abilities/valuator_spec.rb +++ b/spec/models/abilities/valuator_spec.rb @@ -42,4 +42,8 @@ describe Abilities::Valuator do it { should_not be_able_to(:read, SDG::Goal) } it { should_not be_able_to(:read, SDG::Target) } + + it { should_not be_able_to(:read, SDG::Manager) } + it { should_not be_able_to(:create, SDG::Manager) } + it { should_not be_able_to(:delete, SDG::Manager) } end diff --git a/spec/system/admin/sdg/managers_spec.rb b/spec/system/admin/sdg/managers_spec.rb new file mode 100644 index 000000000..0f893e79b --- /dev/null +++ b/spec/system/admin/sdg/managers_spec.rb @@ -0,0 +1,96 @@ +require "rails_helper" + +describe "Admin SDG managers", :js do + let!(:user) { create(:user) } + let!(:sdg_manager) { create(:sdg_manager) } + + before do + login_as(create(:administrator).user) + visit admin_sdg_managers_path + end + + scenario "Index" do + expect(page).to have_content sdg_manager.name + expect(page).to have_content sdg_manager.email + expect(page).not_to have_content user.name + end + + scenario "Create SDG Manager" do + fill_in "search", with: user.email + click_button "Search" + + expect(page).to have_content user.name + + click_link "Add" + + within("#sdg_managers") do + expect(page).to have_content user.name + end + end + + scenario "Delete SDG Manager" do + accept_confirm { click_link "Delete" } + + within("#sdg_managers") do + expect(page).not_to have_content sdg_manager.name + end + end + + context "Search" do + let(:user) { create(:user, username: "Taylor Swift", email: "taylor@swift.com") } + let(:user2) { create(:user, username: "Stephanie Corneliussen", email: "steph@mrrobot.com") } + let!(:sdg_manager1) { create(:sdg_manager, user: user) } + let!(:sdg_manager2) { create(:sdg_manager, user: user2) } + + before do + visit admin_sdg_managers_path + end + + scenario "returns no results if search term is empty" do + expect(page).to have_content(sdg_manager1.name) + expect(page).to have_content(sdg_manager2.name) + + fill_in "search", with: " " + click_button "Search" + + expect(page).to have_content("SDG managers") + expect(page).to have_content("There are no users.") + expect(page).not_to have_content(sdg_manager1.name) + expect(page).not_to have_content(sdg_manager2.name) + end + + scenario "search by name" do + expect(page).to have_content(sdg_manager1.name) + expect(page).to have_content(sdg_manager2.name) + + fill_in "search", with: "Taylor" + click_button "Search" + + expect(page).to have_content("SDG managers") + expect(page).to have_content(sdg_manager1.name) + expect(page).not_to have_content(sdg_manager2.name) + end + + scenario "search by email" do + expect(page).to have_content(sdg_manager1.email) + expect(page).to have_content(sdg_manager2.email) + + fill_in "search", with: sdg_manager2.email + click_button "Search" + + expect(page).to have_content("SDG managers") + expect(page).to have_content(sdg_manager2.email) + expect(page).not_to have_content(sdg_manager1.email) + end + + scenario "Delete after searching" do + fill_in "Search user by name or email", with: sdg_manager2.email + click_button "Search" + + accept_confirm { click_link "Delete" } + + expect(page).to have_content(sdg_manager1.email) + expect(page).not_to have_content(sdg_manager2.email) + end + end +end diff --git a/spec/system/admin_spec.rb b/spec/system/admin_spec.rb index e6949140d..169205b7f 100644 --- a/spec/system/admin_spec.rb +++ b/spec/system/admin_spec.rb @@ -42,6 +42,16 @@ describe "Admin" do expect(page).to have_content "You do not have permission to access this page" end + scenario "Access as SDG manager is not authorized", :js do + create(:sdg_manager, user: user) + login_as(user) + visit admin_root_path + + expect(page).not_to have_current_path(admin_root_path) + expect(page).to have_current_path(root_path) + expect(page).to have_content "You do not have permission to access this page" + end + scenario "Access as poll officer is not authorized" do login_as(create(:poll_officer).user) visit admin_root_path @@ -59,12 +69,15 @@ describe "Admin" do end scenario "Admin access links", :admin do + Setting["feature.sdg"] = true + visit root_path expect(page).to have_link("Administration") expect(page).to have_link("Moderation") expect(page).to have_link("Valuation") expect(page).to have_link("Management") + expect(page).to have_link("SDG content") end scenario "Admin dashboard", :admin do diff --git a/spec/system/moderation_spec.rb b/spec/system/moderation_spec.rb index 42199fcca..46923e1a1 100644 --- a/spec/system/moderation_spec.rb +++ b/spec/system/moderation_spec.rb @@ -43,6 +43,21 @@ describe "Moderation" do expect(page).to have_content "You do not have permission to access this page" end + scenario "Access as SDG manager is not authorized", :js do + create(:sdg_manager, user: user) + + login_as(user) + visit root_path + + expect(page).not_to have_link("Moderation") + + visit moderation_root_path + + expect(page).not_to have_current_path(moderation_root_path) + expect(page).to have_current_path(root_path) + expect(page).to have_content "You do not have permission to access this page" + end + scenario "Access as poll officer is not authorized" do create(:poll_officer, user: user) diff --git a/spec/system/officing_spec.rb b/spec/system/officing_spec.rb index a2298d8fd..79301f8b3 100644 --- a/spec/system/officing_spec.rb +++ b/spec/system/officing_spec.rb @@ -42,6 +42,20 @@ describe "Poll Officing" do expect(page).to have_content "You do not have permission to access this page" end + scenario "Access as SDG manager is not authorized", :js do + create(:sdg_manager, user: user) + login_as(user) + visit root_path + + expect(page).not_to have_link("Polling officers") + + visit officing_root_path + + expect(page).not_to have_current_path(officing_root_path) + expect(page).to have_current_path(root_path) + expect(page).to have_content "You do not have permission to access this page" + end + scenario "Access as a valuator is not authorized" do create(:valuator, user: user) login_as(user) diff --git a/spec/system/valuation_spec.rb b/spec/system/valuation_spec.rb index b14dbcc25..68c5f8285 100644 --- a/spec/system/valuation_spec.rb +++ b/spec/system/valuation_spec.rb @@ -42,6 +42,19 @@ describe "Valuation" do expect(page).to have_content "You do not have permission to access this page" end + scenario "Access as SDG manager is not authorized" do + create(:sdg_manager, user: user) + login_as(user) + visit root_path + + expect(page).not_to have_link("Valuation") + visit valuation_root_path + + expect(page).not_to have_current_path(valuation_root_path) + expect(page).to have_current_path(root_path) + expect(page).to have_content "You do not have permission to access this page" + end + scenario "Access as poll officer is not authorized" do create(:poll_officer, user: user) login_as(user)