diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb new file mode 100644 index 0000000..94c7f00 --- /dev/null +++ b/app/controllers/admin/dashboard_controller.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +module Admin + class DashboardController < AdminController + def show + authorize :dashboard + @quizzes = policy_scope Quiz.includes(:questions).all + @users = policy_scope User.order(:role, :name) + end + end +end diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index b152c8e..2c2daf6 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -4,17 +4,10 @@ class AdminController < ApplicationController layout 'admin' before_action :authorize_user - after_action :verify_authorized, except: :index - after_action :verify_policy_scoped, only: :index - rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized - # TODO: move to DashboardController#index - def dashboard - authorize :admin, :dashboard? - @quizzes = Quiz.includes(:questions).all - @users = User.order(:role, :name) - end + after_action :verify_authorized, except: :index + after_action :verify_policy_scoped, only: :index def current_user @current_user ||= User.find_by(id: session[:user]) if session[:user] diff --git a/app/models/user.rb b/app/models/user.rb index c20f17e..a44ec5b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -15,22 +15,19 @@ class User < ApplicationRecord save end - # TODO: move to mixin: UserRoles + # Roles def admin? 'admin' == role end - # TODO: move to mixin: UserRoles def manager? %w(admin manager).include? role end - # TODO: move to mixin: UserRoles def recruiter? 'recruiter' == role end - # TODO: move to mixin: UserRoles def reviewer? 'reviewer' == role end diff --git a/app/policies/admin_policy.rb b/app/policies/admin_policy.rb deleted file mode 100644 index 2644868..0000000 --- a/app/policies/admin_policy.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true -class AdminPolicy < Struct.new(:user, :dashboard) - attr_reader :user, :record - - def initialize(user, record) - raise Pundit::NotAuthorizedError, "Must be logged in." unless user - @user = user - @record = record - end - - def dashboard? - true - end - - def scope - Pundit.policy_scope!(user, record.class) - end - - class Scope - attr_reader :user, :scope - - def initialize(user, scope) - @user = user - @scope = scope - end - - def resolve - scope - end - end -end diff --git a/app/policies/dashboard_policy.rb b/app/policies/dashboard_policy.rb new file mode 100644 index 0000000..1ba609e --- /dev/null +++ b/app/policies/dashboard_policy.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true +class DashboardPolicy < Struct.new(:user, :dashboard) + attr_reader :user, :record + + def initialize(user, record) + raise Pundit::NotAuthorizedError, "Must be logged in." unless user + @user = user + @record = record + end + + def show? + true + end +end diff --git a/app/policies/quiz_policy.rb b/app/policies/quiz_policy.rb index 49505e8..4b2dc56 100644 --- a/app/policies/quiz_policy.rb +++ b/app/policies/quiz_policy.rb @@ -6,6 +6,10 @@ class QuizPolicy < ApplicationPolicy # Reviewers can view any quiz they are linked to # Recruiters can only list quiz names (for candidate assignments) + def index? + true + end + def view? return true if user.admin? || user.manager? user.quizzes.include? record diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index 5a1140e..c02a137 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -5,6 +5,10 @@ class UserPolicy < ApplicationPolicy # Only Admins can view, create, or update, users # All other users can only access themselves (profile interface) + def index? + user.admin? + end + def view? user.admin? || user == record end @@ -25,7 +29,7 @@ class UserPolicy < ApplicationPolicy class Scope < Scope def resolve return scope if user.admin? - raise Pundit::NotAuthorizedError, "No access to resource." + scope.where(id: user.id) end end end diff --git a/app/views/admin/dashboard.html.erb b/app/views/admin/dashboard.html.erb deleted file mode 100644 index 9939146..0000000 --- a/app/views/admin/dashboard.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -<% - content_for :section_title, "Admin Dashboard" -%> - -
-

Quizzes

- <%= render partial: 'admin/quiz/table_list', locals: { quizzes: @quizzes } %> - <%= link_to('New Quiz', admin_new_quiz_path, { class: 'btn' }) %> -
- -
-

Users

- <%= render partial: 'admin/user/table_list', locals: { users: @users } %> - <%= link_to('New User', admin_new_user_path, { class: 'btn' }) %> -
diff --git a/app/views/admin/dashboard/show.html.erb b/app/views/admin/dashboard/show.html.erb new file mode 100644 index 0000000..ee1284a --- /dev/null +++ b/app/views/admin/dashboard/show.html.erb @@ -0,0 +1,35 @@ +<% + content_for :section_title, "Admin Dashboard" +%> + +
+## Admin
+Users | Dept/Unit | Quizzes | Candidates | Results | Profile | Logout
+
+## Manager
+Quizzes | Results | Profile | Logout
+
+## Recruiter
+Results | Profile | Logout
+
+## Reviewer
+Candidates | Profile | Logout
+
+ +<% if policy(Quiz).index? %> +
+

Quizzes

+ <%= render partial: 'admin/quiz/table_list', locals: { quizzes: @quizzes } %> + <%= link_to('New Quiz', admin_new_quiz_path, { class: 'btn' }) %> +
+<% end %> + +<% if policy(User).index? %> +
+

Users

+ <%= render partial: 'admin/user/table_list', locals: { users: @users } %> + <%= link_to('New User', admin_new_user_path, { class: 'btn' }) %> +
+<% end %> + + diff --git a/config/routes.rb b/config/routes.rb index 0a9f7e8..41c8002 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -37,7 +37,7 @@ Rails.application.routes.draw do post "/admin/profile", to: "admin/profile#update", as: :admin_update_profile get "/admin/profile/edit", to: "admin/profile#edit", as: :admin_edit_profile - get "/admin", to: "admin#dashboard", as: :admin + get "/admin", to: "admin/dashboard#show", as: :admin ######################################################################################### diff --git a/test/controllers/admin/dashboard_controller_test.rb b/test/controllers/admin/dashboard_controller_test.rb new file mode 100644 index 0000000..9b36041 --- /dev/null +++ b/test/controllers/admin/dashboard_controller_test.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +require 'test_helper' + +module Admin + class DashboardControllerTest < ActionDispatch::IntegrationTest + test "dashboard should require auth" do + get admin_url + assert_redirected_to admin_login_url + end + + test "should get dashboard" do + post admin_auth_url, params: { auth: + { email: 'alan.admin@mailinator.com', password: 'password' } } + get admin_url + assert_response :success + end + end +end diff --git a/test/controllers/admin_controller_test.rb b/test/controllers/admin_controller_test.rb index 56df4d6..60da372 100644 --- a/test/controllers/admin_controller_test.rb +++ b/test/controllers/admin_controller_test.rb @@ -2,15 +2,4 @@ require 'test_helper' class AdminControllerTest < ActionDispatch::IntegrationTest - test "dashboard should require auth" do - get admin_url - assert_redirected_to admin_login_url - end - - test "should get dashboard" do - post admin_auth_url, params: { auth: - { email: 'alan.admin@mailinator.com', password: 'password' } } - get admin_url - assert_response :success - end end diff --git a/test/policies/user_policy_test.rb b/test/policies/user_policy_test.rb index 2bd3b54..98f0dd3 100644 --- a/test/policies/user_policy_test.rb +++ b/test/policies/user_policy_test.rb @@ -13,11 +13,11 @@ class UserPolicyTest < PolicyAssertions::Test assert_equal User.count, scope.count end - test 'should not allow non_admin to scope' do + test 'non admins can only scope themselves' do %i(manager reviewer recruiter).each do |role| - assert_raise Pundit::NotAuthorizedError, "Failed to raise auth error for #{role}" do - UserPolicy::Scope.new(users(role), User).resolve - end + scope = UserPolicy::Scope.new(users(role), User).resolve + assert_equal 1, scope.count, "Scope did not have 1 result for #{role}" + assert_equal users(role), scope.first, "Scope did not contain self for #{role}" end end