new admin features: manager-role, nav, candidates, and results
completes #76 Merge branch 'feature/admin-managers' into develop
This commit is contained in:
commit
33f0358fa5
@ -38,6 +38,10 @@ Style/SpaceBeforeFirstArg:
|
|||||||
Style/StringLiterals:
|
Style/StringLiterals:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
Style/StructInheritance:
|
||||||
|
Exclude:
|
||||||
|
- app/policies/**/*
|
||||||
|
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Exclude:
|
Exclude:
|
||||||
- db/migrate/**/*
|
- db/migrate/**/*
|
||||||
|
22
Gemfile
22
Gemfile
@ -11,6 +11,7 @@ gem 'jquery-rails'
|
|||||||
gem 'json', '~> 2.0.2'
|
gem 'json', '~> 2.0.2'
|
||||||
gem 'mailjet', '~> 1.3.8'
|
gem 'mailjet', '~> 1.3.8'
|
||||||
gem 'puma', '~> 3.0'
|
gem 'puma', '~> 3.0'
|
||||||
|
gem 'pundit'
|
||||||
gem 'sass-rails', '~> 5.0'
|
gem 'sass-rails', '~> 5.0'
|
||||||
gem 'settingslogic', '~> 2.0.9'
|
gem 'settingslogic', '~> 2.0.9'
|
||||||
gem 'turbolinks', '~> 5'
|
gem 'turbolinks', '~> 5'
|
||||||
@ -32,23 +33,30 @@ group :development do
|
|||||||
end
|
end
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'awesome_print'
|
gem 'spring'
|
||||||
gem 'binding_of_caller'
|
gem 'spring-watcher-listen', '~> 2.0.0'
|
||||||
gem 'byebug', platform: :mri
|
gem 'listen'
|
||||||
|
|
||||||
gem 'guard'
|
gem 'guard'
|
||||||
|
gem 'guard-brakeman'
|
||||||
gem 'guard-livereload'
|
gem 'guard-livereload'
|
||||||
gem 'guard-minitest'
|
gem 'guard-minitest'
|
||||||
gem 'guard-rubocop'
|
gem 'guard-rubocop'
|
||||||
gem 'guard-shell'
|
gem 'guard-shell'
|
||||||
gem 'listen', '~> 3.0'
|
|
||||||
gem 'minitest-reporters'
|
gem 'minitest-reporters'
|
||||||
|
gem 'rails-controller-testing'
|
||||||
|
gem 'policy-assertions'
|
||||||
|
|
||||||
|
gem 'byebug', platform: :mri
|
||||||
gem 'pry-byebug'
|
gem 'pry-byebug'
|
||||||
gem 'pry-rails'
|
gem 'pry-rails'
|
||||||
gem 'rails-controller-testing'
|
gem 'binding_of_caller'
|
||||||
|
gem 'awesome_print'
|
||||||
|
|
||||||
gem 'rubocop', '~> 0.42.0'
|
gem 'rubocop', '~> 0.42.0'
|
||||||
gem 'simplecov', require: false
|
gem 'simplecov', require: false
|
||||||
gem 'spring'
|
gem 'brakeman'
|
||||||
gem 'spring-watcher-listen', '~> 2.0.0'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
||||||
|
15
Gemfile.lock
15
Gemfile.lock
@ -53,6 +53,7 @@ GEM
|
|||||||
bourbon (4.2.7)
|
bourbon (4.2.7)
|
||||||
sass (~> 3.4)
|
sass (~> 3.4)
|
||||||
thor (~> 0.19)
|
thor (~> 0.19)
|
||||||
|
brakeman (3.4.0)
|
||||||
builder (3.2.2)
|
builder (3.2.2)
|
||||||
byebug (9.0.5)
|
byebug (9.0.5)
|
||||||
choice (0.2.0)
|
choice (0.2.0)
|
||||||
@ -86,6 +87,9 @@ GEM
|
|||||||
pry (>= 0.9.12)
|
pry (>= 0.9.12)
|
||||||
shellany (~> 0.0)
|
shellany (~> 0.0)
|
||||||
thor (>= 0.18.1)
|
thor (>= 0.18.1)
|
||||||
|
guard-brakeman (0.8.3)
|
||||||
|
brakeman (>= 2.1.1)
|
||||||
|
guard (>= 2.0.0)
|
||||||
guard-compat (1.2.1)
|
guard-compat (1.2.1)
|
||||||
guard-livereload (2.5.2)
|
guard-livereload (2.5.2)
|
||||||
em-websocket (~> 0.5)
|
em-websocket (~> 0.5)
|
||||||
@ -157,6 +161,9 @@ GEM
|
|||||||
parser (2.3.1.2)
|
parser (2.3.1.2)
|
||||||
ast (~> 2.2)
|
ast (~> 2.2)
|
||||||
pkg-config (1.1.7)
|
pkg-config (1.1.7)
|
||||||
|
policy-assertions (0.0.3)
|
||||||
|
activesupport (>= 3.0.0)
|
||||||
|
pundit (>= 1.0.0)
|
||||||
powerpack (0.1.1)
|
powerpack (0.1.1)
|
||||||
premailer (1.8.7)
|
premailer (1.8.7)
|
||||||
css_parser (>= 1.4.5)
|
css_parser (>= 1.4.5)
|
||||||
@ -174,6 +181,8 @@ GEM
|
|||||||
pry-rails (0.3.4)
|
pry-rails (0.3.4)
|
||||||
pry (>= 0.9.10)
|
pry (>= 0.9.10)
|
||||||
puma (3.6.0)
|
puma (3.6.0)
|
||||||
|
pundit (1.1.0)
|
||||||
|
activesupport (>= 3.0.0)
|
||||||
rack (2.0.1)
|
rack (2.0.1)
|
||||||
rack-livereload (0.3.16)
|
rack-livereload (0.3.16)
|
||||||
rack
|
rack
|
||||||
@ -287,9 +296,11 @@ DEPENDENCIES
|
|||||||
better_errors
|
better_errors
|
||||||
binding_of_caller
|
binding_of_caller
|
||||||
bourbon
|
bourbon
|
||||||
|
brakeman
|
||||||
byebug
|
byebug
|
||||||
figaro (~> 1.1.1)
|
figaro (~> 1.1.1)
|
||||||
guard
|
guard
|
||||||
|
guard-brakeman
|
||||||
guard-livereload
|
guard-livereload
|
||||||
guard-minitest
|
guard-minitest
|
||||||
guard-rubocop
|
guard-rubocop
|
||||||
@ -298,15 +309,17 @@ DEPENDENCIES
|
|||||||
jbuilder (~> 2.6)
|
jbuilder (~> 2.6)
|
||||||
jquery-rails
|
jquery-rails
|
||||||
json (~> 2.0.2)
|
json (~> 2.0.2)
|
||||||
listen (~> 3.0)
|
listen
|
||||||
mailjet (~> 1.3.8)
|
mailjet (~> 1.3.8)
|
||||||
minitest-reporters
|
minitest-reporters
|
||||||
mysql2 (>= 0.3.18, < 0.5)
|
mysql2 (>= 0.3.18, < 0.5)
|
||||||
neat
|
neat
|
||||||
|
policy-assertions
|
||||||
premailer-rails
|
premailer-rails
|
||||||
pry-byebug
|
pry-byebug
|
||||||
pry-rails
|
pry-rails
|
||||||
puma (~> 3.0)
|
puma (~> 3.0)
|
||||||
|
pundit
|
||||||
rack-livereload
|
rack-livereload
|
||||||
rails (~> 5.0, >= 5.0.0.1)
|
rails (~> 5.0, >= 5.0.0.1)
|
||||||
rails-controller-testing
|
rails-controller-testing
|
||||||
|
14
Guardfile
14
Guardfile
@ -72,14 +72,26 @@ end
|
|||||||
|
|
||||||
# ESLint
|
# ESLint
|
||||||
guard :shell, all_on_start: true do
|
guard :shell, all_on_start: true do
|
||||||
|
# TODO: Annoyingly, all files are linted twice on start/full runs. Why?
|
||||||
watch %r{app/assets/javascripts/*/.*} do |file|
|
watch %r{app/assets/javascripts/*/.*} do |file|
|
||||||
system %(echo "ESLint:\033[32m #{file[0]}\033[0m")
|
system %(echo "ESLint:\033[32m #{file[0]}\033[0m")
|
||||||
system %(eslint #{file[0]})
|
system %(eslint #{file[0]})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
guard :rubocop do
|
guard :rubocop, cli: %w(-D -S) do
|
||||||
|
watch(/.rubocop.yml/)
|
||||||
watch(/.+\.rb$/)
|
watch(/.+\.rb$/)
|
||||||
watch(/Rakefile/)
|
watch(/Rakefile/)
|
||||||
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
guard 'brakeman', run_on_start: true, quiet: true do
|
||||||
|
## Lets not watch files for brakeman,
|
||||||
|
## just scan on guard start, and full runs.
|
||||||
|
#
|
||||||
|
# watch(%r{^app/.+\.(erb|haml|rhtml|rb)$})
|
||||||
|
# watch(%r{^config/.+\.rb$})
|
||||||
|
# watch(%r{^lib/.+\.rb$})
|
||||||
|
# watch('Gemfile')
|
||||||
|
end
|
||||||
|
17
app/assets/stylesheets/molecules/_nav.scss
Normal file
17
app/assets/stylesheets/molecules/_nav.scss
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
nav {
|
||||||
|
margin: 15px 0;
|
||||||
|
padding: 0;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
a,
|
||||||
|
a:visited {
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $gray-lighter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,10 @@ header {
|
|||||||
&.no-progressbar {
|
&.no-progressbar {
|
||||||
padding-top: 52px;
|
padding-top: 52px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.no-progressbar.admin {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.page-title {
|
.page-title {
|
||||||
@include omega();
|
@include omega();
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
module Admin
|
module Admin
|
||||||
class AuthController < AdminController
|
class AuthController < AdminController
|
||||||
skip_before_action :authorize_admin
|
skip_before_action :authorize_user
|
||||||
|
|
||||||
|
# bypass pundit lockdowns for auth requests.
|
||||||
|
after_action :skip_policy_scope
|
||||||
|
after_action :skip_authorization
|
||||||
|
|
||||||
def login
|
def login
|
||||||
end
|
end
|
||||||
|
|
||||||
def auth
|
def auth
|
||||||
admin = User.find_by(email: auth_params[:email], role: 'admin')
|
user = User.find_by(email: auth_params[:email])
|
||||||
|
|
||||||
if admin && admin.authenticate(auth_params[:password])
|
if user && user.authenticate(auth_params[:password])
|
||||||
session[:user] = admin.to_i
|
session[:user] = user.to_i
|
||||||
redirect_to admin_path
|
redirect_to admin_path
|
||||||
else
|
else
|
||||||
redirect_to admin_login_path,
|
redirect_to admin_login_path,
|
||||||
|
70
app/controllers/admin/candidate_controller.rb
Normal file
70
app/controllers/admin/candidate_controller.rb
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
module Admin
|
||||||
|
class CandidateController < AdminController
|
||||||
|
before_action :collect_quizzes, except: [:login, :auth]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@candidates = policy_scope Candidate.order(:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
authorize Candidate
|
||||||
|
@candidate = Candidate.new
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
authorize Candidate
|
||||||
|
@candidate = Candidate.create(candidate_params.merge(recruiter_id: current_user.id))
|
||||||
|
|
||||||
|
if @candidate.persisted?
|
||||||
|
send_notifications @candidate
|
||||||
|
redirect_to admin_candidates_path,
|
||||||
|
flash: { success: "Sucessfully created candidate #{@candidate.name}" }
|
||||||
|
else
|
||||||
|
flash[:error] = "Failed to save candidate."
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
authorize Candidate
|
||||||
|
@candidate = Candidate.find_by(id: params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
authorize Candidate
|
||||||
|
@candidate = Candidate.find_by(id: params[:id])
|
||||||
|
@candidate.update(candidate_params)
|
||||||
|
|
||||||
|
if @candidate.save
|
||||||
|
redirect_to admin_candidates_path, flash: { success: "#{@candidate.name} updated!" }
|
||||||
|
else
|
||||||
|
flash[:error] = "Failed to save candidate."
|
||||||
|
render :edit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def resend_welcome
|
||||||
|
authorize Candidate
|
||||||
|
candidate = Candidate.find_by(id: params[:id])
|
||||||
|
CandidateMailer.welcome(candidate).deliver_later
|
||||||
|
render json: { message: "Email queued!" }.to_json
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def candidate_params
|
||||||
|
params.require(:candidate).permit(:name, :email, :experience, :quiz_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def collect_quizzes
|
||||||
|
@quizzes ||= Quiz.order(:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_notifications candidate
|
||||||
|
CandidateMailer.welcome(candidate).deliver_later
|
||||||
|
RecruiterMailer.candidate_created(candidate).deliver_later
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
27
app/controllers/admin/dashboard_controller.rb
Normal file
27
app/controllers/admin/dashboard_controller.rb
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
module Admin
|
||||||
|
class DashboardController < AdminController
|
||||||
|
def show
|
||||||
|
authorize :dashboard
|
||||||
|
send "redirect_for_#{current_user.role}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def redirect_for_admin
|
||||||
|
redirect_to admin_users_url
|
||||||
|
end
|
||||||
|
|
||||||
|
def redirect_for_manager
|
||||||
|
redirect_to admin_quizzes_url
|
||||||
|
end
|
||||||
|
|
||||||
|
def redirect_for_reviewer
|
||||||
|
redirect_to admin_results_url
|
||||||
|
end
|
||||||
|
|
||||||
|
def redirect_for_recruiter
|
||||||
|
redirect_to admin_candidates_url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -2,14 +2,17 @@
|
|||||||
module Admin
|
module Admin
|
||||||
class ProfileController < AdminController
|
class ProfileController < AdminController
|
||||||
def view
|
def view
|
||||||
|
authorize current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@user = current_admin
|
@user = current_user
|
||||||
|
authorize @user
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@user = current_admin
|
@user = current_user
|
||||||
|
authorize @user
|
||||||
|
|
||||||
if @user.update_attributes(user_params)
|
if @user.update_attributes(user_params)
|
||||||
redirect_to admin_profile_path,
|
redirect_to admin_profile_path,
|
||||||
@ -23,7 +26,7 @@ module Admin
|
|||||||
private
|
private
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
params.require(:user).permit(:name, :email, :password, :password_confirmation)
|
params.require(:user).permit(policy(User).permitted_attributes)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,16 +2,20 @@
|
|||||||
module Admin
|
module Admin
|
||||||
class QuestionController < AdminController
|
class QuestionController < AdminController
|
||||||
def index
|
def index
|
||||||
@questions = Question.includes(:quiz).order("quizzes.name", { active: :desc }, :sort)
|
@questions = policy_scope Question.includes(:quiz).order("quizzes.name", { active: :desc }, :sort)
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
authorize Question
|
||||||
|
|
||||||
@question = Question.new(active: true)
|
@question = Question.new(active: true)
|
||||||
@quizzes = Quiz.all
|
@quizzes = policy_scope Quiz.all
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@quizzes = Quiz.all
|
authorize Quiz
|
||||||
|
|
||||||
|
@quizzes = policy_scope Quiz.all
|
||||||
@question = Question.create(process_question_params)
|
@question = Question.create(process_question_params)
|
||||||
|
|
||||||
if @question.persisted?
|
if @question.persisted?
|
||||||
@ -24,16 +28,20 @@ module Admin
|
|||||||
|
|
||||||
def view
|
def view
|
||||||
@question = Question.includes(:quiz).find(params[:question_id])
|
@question = Question.includes(:quiz).find(params[:question_id])
|
||||||
|
authorize @question
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@quizzes = Quiz.all
|
@quizzes = policy_scope Quiz.all
|
||||||
@question = Question.includes(:quiz).find(params[:question_id])
|
@question = Question.includes(:quiz).find(params[:question_id])
|
||||||
|
|
||||||
|
authorize @question
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@quizzes = Quiz.all
|
@quizzes = policy_scope Quiz.all
|
||||||
@question = Question.find(params[:question_id])
|
@question = Question.find(params[:question_id])
|
||||||
|
authorize @question
|
||||||
|
|
||||||
if @question.update_attributes(process_question_params)
|
if @question.update_attributes(process_question_params)
|
||||||
redirect_to admin_question_path(@question.to_i),
|
redirect_to admin_question_path(@question.to_i),
|
||||||
@ -46,6 +54,7 @@ module Admin
|
|||||||
|
|
||||||
def options
|
def options
|
||||||
@question = params[:question_id].present? ? Question.find(params[:question_id]) : Question.new
|
@question = params[:question_id].present? ? Question.find(params[:question_id]) : Question.new
|
||||||
|
authorize @question
|
||||||
render layout: false
|
render layout: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
module Admin
|
module Admin
|
||||||
class QuizController < AdminController
|
class QuizController < AdminController
|
||||||
def index
|
def index
|
||||||
@quizzes = Quiz.all
|
@quizzes = policy_scope Quiz.all
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
authorize Quiz
|
||||||
@quiz = Quiz.new
|
@quiz = Quiz.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
authorize Quiz
|
||||||
@quiz = Quiz.create(quiz_params)
|
@quiz = Quiz.create(quiz_params)
|
||||||
|
|
||||||
if @quiz.persisted?
|
if @quiz.persisted?
|
||||||
@ -22,14 +24,17 @@ module Admin
|
|||||||
|
|
||||||
def view
|
def view
|
||||||
@quiz = Quiz.find(params[:quiz_id])
|
@quiz = Quiz.find(params[:quiz_id])
|
||||||
|
authorize @quiz
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@quiz = Quiz.find(params[:quiz_id])
|
@quiz = Quiz.find(params[:quiz_id])
|
||||||
|
authorize @quiz
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@quiz = Quiz.find(params[:quiz_id])
|
@quiz = Quiz.find(params[:quiz_id])
|
||||||
|
authorize @quiz
|
||||||
|
|
||||||
if @quiz.update_attributes(quiz_params)
|
if @quiz.update_attributes(quiz_params)
|
||||||
redirect_to admin_quiz_path(@quiz.to_i),
|
redirect_to admin_quiz_path(@quiz.to_i),
|
||||||
|
21
app/controllers/admin/result_controller.rb
Normal file
21
app/controllers/admin/result_controller.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
module Admin
|
||||||
|
class ResultController < AdminController
|
||||||
|
#
|
||||||
|
# TODO: change context from Candidate to Quiz
|
||||||
|
# bypass pundit lockdowns until completed
|
||||||
|
after_action :skip_policy_scope
|
||||||
|
after_action :skip_authorization
|
||||||
|
#
|
||||||
|
|
||||||
|
def index
|
||||||
|
@candidates = Candidate.where(completed: true).includes(:recruiter)
|
||||||
|
end
|
||||||
|
|
||||||
|
def view
|
||||||
|
@candidate = Candidate.find_by(test_hash: params[:test_hash])
|
||||||
|
@quiz = @candidate.my_quiz
|
||||||
|
@status = QuizStatus.new(@candidate)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -2,14 +2,16 @@
|
|||||||
module Admin
|
module Admin
|
||||||
class UserController < AdminController
|
class UserController < AdminController
|
||||||
def index
|
def index
|
||||||
@users = User.order(:name)
|
@users = policy_scope User.order(:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@user = User.new
|
@user = User.new
|
||||||
|
authorize @user
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
authorize User
|
||||||
default_passwd = SecureRandom.urlsafe_base64(12)
|
default_passwd = SecureRandom.urlsafe_base64(12)
|
||||||
@user = User.create({ password: default_passwd }.merge(user_params.to_h))
|
@user = User.create({ password: default_passwd }.merge(user_params.to_h))
|
||||||
|
|
||||||
@ -24,14 +26,17 @@ module Admin
|
|||||||
|
|
||||||
def view
|
def view
|
||||||
@user = User.find(params[:user_id])
|
@user = User.find(params[:user_id])
|
||||||
|
authorize @user
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@user = User.find(params[:user_id])
|
@user = User.find(params[:user_id])
|
||||||
|
authorize @user
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@user = User.find(params[:user_id])
|
@user = User.find(params[:user_id])
|
||||||
|
authorize @user
|
||||||
|
|
||||||
if @user.update_attributes(user_params)
|
if @user.update_attributes(user_params)
|
||||||
redirect_to admin_user_path(@user.to_i),
|
redirect_to admin_user_path(@user.to_i),
|
||||||
@ -45,7 +50,7 @@ module Admin
|
|||||||
private
|
private
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
params.require(:user).permit(:name, :email, :role, :password, quiz_ids: [])
|
params.require(:user).permit(policy(User).permitted_attributes)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,22 +1,27 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class AdminController < ApplicationController
|
class AdminController < ApplicationController
|
||||||
|
include Pundit
|
||||||
layout 'admin'
|
layout 'admin'
|
||||||
before_action :authorize_admin
|
before_action :authorize_user
|
||||||
|
|
||||||
def dashboard
|
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
||||||
@quizzes = Quiz.includes(:questions).all
|
|
||||||
@users = User.order(:role, :name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def current_admin
|
after_action :verify_authorized, except: :index
|
||||||
user_args = { id: session[:user], role: 'admin' }
|
after_action :verify_policy_scoped, only: :index
|
||||||
@current_admin ||= User.find_by(user_args) if session[:user]
|
|
||||||
|
def current_user
|
||||||
|
@current_user ||= User.find_by(id: session[:user]) if session[:user]
|
||||||
end
|
end
|
||||||
helper_method :current_admin
|
helper_method :current_user
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def authorize_admin
|
def authorize_user
|
||||||
redirect_to admin_login_path unless current_admin
|
redirect_to admin_login_path unless current_user
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_not_authorized
|
||||||
|
flash[:error] = "You are not authorized to perform this action."
|
||||||
|
redirect_to(request.referer || admin_login_path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -4,16 +4,6 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
add_flash_types :warning, :success
|
add_flash_types :warning, :success
|
||||||
|
|
||||||
def current_recruiter
|
|
||||||
user_parms = { id: session[:user], role: %w(admin recruiter) }
|
|
||||||
@current_recruiter ||= User.find_by(user_parms) if session[:user]
|
|
||||||
end
|
|
||||||
|
|
||||||
def current_reviewer
|
|
||||||
user_parms = { id: session[:user], role: %w(admin reviewer) }
|
|
||||||
@current_reviewer ||= User.find_by(user_parms) if session[:user]
|
|
||||||
end
|
|
||||||
|
|
||||||
def current_candidate
|
def current_candidate
|
||||||
@current_candidate ||= Candidate.find_by(test_hash: session[:test_id]) if session[:test_id]
|
@current_candidate ||= Candidate.find_by(test_hash: session[:test_id]) if session[:test_id]
|
||||||
end
|
end
|
||||||
@ -29,14 +19,6 @@ class ApplicationController < ActionController::Base
|
|||||||
params.require(:auth).permit(:email, :password)
|
params.require(:auth).permit(:email, :password)
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorize_recruiter
|
|
||||||
redirect_to recruiter_login_path unless current_recruiter
|
|
||||||
end
|
|
||||||
|
|
||||||
def authorize_reviewer
|
|
||||||
redirect_to review_login_path unless current_reviewer
|
|
||||||
end
|
|
||||||
|
|
||||||
def authorize_candidate
|
def authorize_candidate
|
||||||
redirect_to login_path unless current_candidate
|
redirect_to login_path unless current_candidate
|
||||||
end
|
end
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
class RecruiterController < ApplicationController
|
|
||||||
before_action :authorize_recruiter, except: [:login, :auth]
|
|
||||||
before_action :collect_quizzes, except: [:login, :auth]
|
|
||||||
|
|
||||||
def index
|
|
||||||
@candidates = current_recruiter.candidates
|
|
||||||
end
|
|
||||||
|
|
||||||
def new
|
|
||||||
@candidate = Candidate.new
|
|
||||||
render :new
|
|
||||||
end
|
|
||||||
|
|
||||||
def create
|
|
||||||
@candidate = Candidate.create(candidate_params.merge(recruiter_id: current_recruiter.id))
|
|
||||||
|
|
||||||
if @candidate.persisted?
|
|
||||||
CandidateMailer.welcome(@candidate).deliver_later
|
|
||||||
RecruiterMailer.candidate_created(@candidate).deliver_later
|
|
||||||
redirect_to recruiter_path, flash: { success: "Sucessfully created candidate #{@candidate.name}" }
|
|
||||||
else
|
|
||||||
flash[:error] = "Failed to save candidate."
|
|
||||||
render :new
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def edit
|
|
||||||
@candidate = Candidate.find_by(id: params[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def update
|
|
||||||
@candidate = Candidate.find_by(id: params[:id])
|
|
||||||
@candidate.update(candidate_params)
|
|
||||||
|
|
||||||
if @candidate.save
|
|
||||||
redirect_to recruiter_path, flash: { success: "#{@candidate.name} updated!" }
|
|
||||||
else
|
|
||||||
flash[:error] = "Failed to save candidate."
|
|
||||||
render :edit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def login
|
|
||||||
redirect_to recruiter_path unless current_recruiter.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def auth
|
|
||||||
recruiter = User.find_by(email: auth_params[:email], role: %w(admin recruiter))
|
|
||||||
|
|
||||||
if recruiter && recruiter.authenticate(auth_params[:password])
|
|
||||||
session[:user] = recruiter.to_i
|
|
||||||
redirect_to recruiter_path
|
|
||||||
else
|
|
||||||
redirect_to recruiter_login_path,
|
|
||||||
flash: { error: "Sorry, incorrect email or password. Please try again." }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
reset_session
|
|
||||||
redirect_to recruiter_login_path
|
|
||||||
end
|
|
||||||
|
|
||||||
def resend_welcome
|
|
||||||
candidate = Candidate.find_by(id: params[:id])
|
|
||||||
CandidateMailer.welcome(candidate).deliver_later
|
|
||||||
render json: { message: "Email queued!" }.to_json
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def candidate_params
|
|
||||||
params.require(:candidate).permit(:name, :email, :experience, :quiz_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def collect_quizzes
|
|
||||||
@quizzes ||= Quiz.order(:name)
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,34 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
class ReviewController < ApplicationController
|
|
||||||
before_action :authorize_reviewer, except: [:login, :auth]
|
|
||||||
|
|
||||||
def index
|
|
||||||
@candidates = Candidate.where(completed: true).includes(:recruiter)
|
|
||||||
end
|
|
||||||
|
|
||||||
def view
|
|
||||||
@candidate = Candidate.find_by(test_hash: params[:test_hash])
|
|
||||||
@quiz = @candidate.my_quiz
|
|
||||||
@status = QuizStatus.new(@candidate)
|
|
||||||
end
|
|
||||||
|
|
||||||
def login
|
|
||||||
redirect_to review_path unless current_reviewer.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def auth
|
|
||||||
reviewer = User.find_by(email: auth_params[:email], role: %w(admin reviewer))
|
|
||||||
|
|
||||||
if reviewer && reviewer.authenticate(auth_params[:password])
|
|
||||||
session[:user] = reviewer.to_i
|
|
||||||
redirect_to review_path
|
|
||||||
else
|
|
||||||
redirect_to review_login_path, flash: { error: "Sorry, incorrect email or password. Please try again." }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout
|
|
||||||
reset_session
|
|
||||||
redirect_to review_login_path
|
|
||||||
end
|
|
||||||
end
|
|
@ -19,6 +19,7 @@ module ApplicationHelper
|
|||||||
options_for_select([
|
options_for_select([
|
||||||
%w(Reviewer reviewer),
|
%w(Reviewer reviewer),
|
||||||
%w(Recruiter recruiter),
|
%w(Recruiter recruiter),
|
||||||
|
%w(Manager manager),
|
||||||
%w(Admin admin)
|
%w(Admin admin)
|
||||||
], disabled: "-", selected: (val.blank? ? '' : val))
|
], disabled: "-", selected: (val.blank? ? '' : val))
|
||||||
end
|
end
|
||||||
|
@ -15,6 +15,39 @@ class User < ApplicationRecord
|
|||||||
save
|
save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Roles
|
||||||
|
def admin?
|
||||||
|
'admin' == role
|
||||||
|
end
|
||||||
|
|
||||||
|
def acts_as_admin?
|
||||||
|
'admin' == role
|
||||||
|
end
|
||||||
|
|
||||||
|
def manager?
|
||||||
|
'manager' == role
|
||||||
|
end
|
||||||
|
|
||||||
|
def acts_as_manager?
|
||||||
|
%w(admin manager).include? role
|
||||||
|
end
|
||||||
|
|
||||||
|
def recruiter?
|
||||||
|
'recruiter' == role
|
||||||
|
end
|
||||||
|
|
||||||
|
def acts_as_recruiter?
|
||||||
|
%w(admin recruiter).include? role
|
||||||
|
end
|
||||||
|
|
||||||
|
def reviewer?
|
||||||
|
'reviewer' == role
|
||||||
|
end
|
||||||
|
|
||||||
|
def acts_as_reviewer?
|
||||||
|
%w(admin reviewer).include? role
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def gen_reset_token
|
def gen_reset_token
|
||||||
|
60
app/policies/application_policy.rb
Normal file
60
app/policies/application_policy.rb
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
class ApplicationPolicy
|
||||||
|
attr_reader :user, :record
|
||||||
|
|
||||||
|
def initialize(user, record)
|
||||||
|
raise Pundit::NotAuthorizedError, "Must be logged in." unless user
|
||||||
|
@user = user
|
||||||
|
@record = record
|
||||||
|
end
|
||||||
|
|
||||||
|
def index?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def show?
|
||||||
|
scope.where(id: record.id).exists?
|
||||||
|
end
|
||||||
|
|
||||||
|
def view?
|
||||||
|
show?
|
||||||
|
end
|
||||||
|
|
||||||
|
def create?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def new?
|
||||||
|
create?
|
||||||
|
end
|
||||||
|
|
||||||
|
def update?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit?
|
||||||
|
update?
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy?
|
||||||
|
false
|
||||||
|
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
|
||||||
|
# This is a closed system.
|
||||||
|
raise Pundit::NotAuthorizedError, "No access to resource."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
33
app/policies/candidate_policy.rb
Normal file
33
app/policies/candidate_policy.rb
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
class CandidatePolicy < ApplicationPolicy
|
||||||
|
# Candidate Access Policy
|
||||||
|
#
|
||||||
|
# Only Recruiters and Admins can view, create, or update, candidates
|
||||||
|
|
||||||
|
def index?
|
||||||
|
user.acts_as_recruiter?
|
||||||
|
end
|
||||||
|
|
||||||
|
def view?
|
||||||
|
user.acts_as_recruiter?
|
||||||
|
end
|
||||||
|
|
||||||
|
def create?
|
||||||
|
user.acts_as_recruiter?
|
||||||
|
end
|
||||||
|
|
||||||
|
def update?
|
||||||
|
user.acts_as_recruiter?
|
||||||
|
end
|
||||||
|
|
||||||
|
def resend_welcome?
|
||||||
|
user.acts_as_recruiter?
|
||||||
|
end
|
||||||
|
|
||||||
|
class Scope < Scope
|
||||||
|
def resolve
|
||||||
|
return scope if user.acts_as_recruiter?
|
||||||
|
raise Pundit::NotAuthorizedError, "No Access to Resource"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
14
app/policies/dashboard_policy.rb
Normal file
14
app/policies/dashboard_policy.rb
Normal file
@ -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
|
38
app/policies/question_policy.rb
Normal file
38
app/policies/question_policy.rb
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
class QuestionPolicy < ApplicationPolicy
|
||||||
|
# Question Access Policy
|
||||||
|
#
|
||||||
|
# Only Admins and Managers can create or update a quiz (and its questions)
|
||||||
|
# Reviewers can view any quiz they are linked to
|
||||||
|
# Recruiters can NOT list or view questions
|
||||||
|
|
||||||
|
def view?
|
||||||
|
return false if user.recruiter?
|
||||||
|
return true if user.acts_as_manager?
|
||||||
|
user.quizzes.include? record.quiz
|
||||||
|
end
|
||||||
|
|
||||||
|
def options?
|
||||||
|
view?
|
||||||
|
end
|
||||||
|
|
||||||
|
def create?
|
||||||
|
user.acts_as_manager?
|
||||||
|
end
|
||||||
|
|
||||||
|
def update?
|
||||||
|
user.acts_as_manager?
|
||||||
|
end
|
||||||
|
|
||||||
|
class Scope < Scope
|
||||||
|
def resolve
|
||||||
|
raise(Pundit::NotAuthorizedError, 'No Access to resource.') if user.recruiter?
|
||||||
|
|
||||||
|
if user.acts_as_manager?
|
||||||
|
scope
|
||||||
|
else
|
||||||
|
scope.where(quiz_id: user.quizzes.map(&:id))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
35
app/policies/quiz_policy.rb
Normal file
35
app/policies/quiz_policy.rb
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
class QuizPolicy < ApplicationPolicy
|
||||||
|
# Quiz Access Policy
|
||||||
|
#
|
||||||
|
# Only Admins and Managers can create or update a quiz (and its questions)
|
||||||
|
# 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.acts_as_manager?
|
||||||
|
user.quizzes.include? record
|
||||||
|
end
|
||||||
|
|
||||||
|
def create?
|
||||||
|
user.acts_as_manager?
|
||||||
|
end
|
||||||
|
|
||||||
|
def update?
|
||||||
|
user.acts_as_manager?
|
||||||
|
end
|
||||||
|
|
||||||
|
class Scope < Scope
|
||||||
|
def resolve
|
||||||
|
if user.reviewer?
|
||||||
|
scope.joins(:reviewers).where('reviewer_to_quizzes.user_id = ?', user.id)
|
||||||
|
else
|
||||||
|
scope
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
35
app/policies/user_policy.rb
Normal file
35
app/policies/user_policy.rb
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
class UserPolicy < ApplicationPolicy
|
||||||
|
# User Access Policy
|
||||||
|
#
|
||||||
|
# Only Admins can view, create, or update, users
|
||||||
|
# All other users can only access themselves (profile interface)
|
||||||
|
|
||||||
|
def index?
|
||||||
|
user.acts_as_admin?
|
||||||
|
end
|
||||||
|
|
||||||
|
def view?
|
||||||
|
user.acts_as_admin? || user == record
|
||||||
|
end
|
||||||
|
|
||||||
|
def create?
|
||||||
|
user.acts_as_admin?
|
||||||
|
end
|
||||||
|
|
||||||
|
def update?
|
||||||
|
user.acts_as_admin? || user == record
|
||||||
|
end
|
||||||
|
|
||||||
|
def permitted_attributes
|
||||||
|
return [:name, :email, :role, :password, quiz_ids: []] if user.acts_as_admin?
|
||||||
|
[:name, :email, :password, :password_confirmation]
|
||||||
|
end
|
||||||
|
|
||||||
|
class Scope < Scope
|
||||||
|
def resolve
|
||||||
|
return scope if user.acts_as_admin?
|
||||||
|
scope.where(id: user.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
9
app/views/admin/_nav.html.erb
Normal file
9
app/views/admin/_nav.html.erb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<nav>
|
||||||
|
<%= link_to("Users", admin_users_url) if policy(User).index? %>
|
||||||
|
<% #= link_to("Departments", admin_departments_url) if policy(Department).index? %>
|
||||||
|
<%= link_to("Quizzes", admin_quizzes_url) if policy(Quiz).index? %>
|
||||||
|
<%= link_to("Candidates", admin_candidates_url) if policy(Candidate).index? %>
|
||||||
|
<%= link_to("Results", admin_results_url) if policy(Quiz).index? %>
|
||||||
|
<%= link_to("Profile", admin_profile_url) %>
|
||||||
|
<%= link_to("Logout", admin_logout_url) %>
|
||||||
|
</nav>
|
6
app/views/admin/candidate/edit.html.erb
Normal file
6
app/views/admin/candidate/edit.html.erb
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<main class="intro_tpl">
|
||||||
|
<h1>Edit: <%= @candidate.name %></h1>
|
||||||
|
<p><strong>Test ID: </strong><%= @candidate.test_hash %></p>
|
||||||
|
|
||||||
|
<%= render partial: 'form', locals: { action: admin_update_candidate_path(@candidate.id), candidate: @candidate, quizzes: @quizzes } %>
|
||||||
|
</main>
|
@ -1,9 +1,10 @@
|
|||||||
|
<%
|
||||||
|
content_for :section_title, "Candidates"
|
||||||
|
%>
|
||||||
<main class="summary_tpl">
|
<main class="summary_tpl">
|
||||||
<h1>Candidates</h1>
|
<%= link_to(admin_new_candidate_path, { class: 'secondary-btn' }) do %>
|
||||||
|
|
||||||
<%= link_to(new_candidate_path, { class: 'secondary-btn' }) do %>
|
|
||||||
<button>Create New Candidate</button>
|
<button>Create New Candidate</button>
|
||||||
<% end %>
|
<% end if policy(User).create? %>
|
||||||
|
|
||||||
<table cellspacing="0" cellpadding="0">
|
<table cellspacing="0" cellpadding="0">
|
||||||
<tr>
|
<tr>
|
||||||
@ -18,12 +19,12 @@
|
|||||||
|
|
||||||
<% @candidates.each do |candidate| %>
|
<% @candidates.each do |candidate| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= link_to candidate.name, edit_candidate_path(candidate.id) %></td>
|
<td><%= link_to candidate.name, admin_edit_candidate_path(candidate.id) %></td>
|
||||||
<td><%= candidate.test_hash %></td>
|
<td><%= candidate.test_hash %></td>
|
||||||
<td>
|
<td>
|
||||||
<%= mail_to(candidate.email) %>
|
<%= mail_to(candidate.email) %>
|
||||||
<br />
|
<br />
|
||||||
<%= link_to "resend welcome email", resend_welcome_path(candidate.id), remote: true, class: '', data: { id: 'ajax-action' } %>
|
<%= link_to "resend welcome email", admin_resend_welcome_path(candidate.id), remote: true, class: '', data: { id: 'ajax-action' } %>
|
||||||
</td>
|
</td>
|
||||||
<td><%= candidate.experience %> years</td>
|
<td><%= candidate.experience %> years</td>
|
||||||
<td><%= candidate.status %></td>
|
<td><%= candidate.status %></td>
|
6
app/views/admin/candidate/new.html.erb
Normal file
6
app/views/admin/candidate/new.html.erb
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<main class="intro_tpl">
|
||||||
|
<h1>New Candidate</h1>
|
||||||
|
|
||||||
|
<%= render partial: 'form', locals:
|
||||||
|
{ action: admin_create_candidate_path, candidate: @candidate, quizzes: @quizzes } %>
|
||||||
|
</main>
|
@ -1,15 +0,0 @@
|
|||||||
<%
|
|
||||||
content_for :section_title, "Admin Dashboard"
|
|
||||||
%>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h1>Quizzes</h1>
|
|
||||||
<%= render partial: 'admin/quiz/table_list', locals: { quizzes: @quizzes } %>
|
|
||||||
<%= link_to('New Quiz', admin_new_quiz_path, { class: 'btn' }) %>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h1>Users</h1>
|
|
||||||
<%= render partial: 'admin/user/table_list', locals: { users: @users } %>
|
|
||||||
<%= link_to('New User', admin_new_user_path, { class: 'btn' }) %>
|
|
||||||
</section>
|
|
@ -2,7 +2,7 @@
|
|||||||
content_for :section_title, "Profile"
|
content_for :section_title, "Profile"
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<p>Name: <%= current_admin.name %></p>
|
<p>Name: <%= current_user.name %></p>
|
||||||
<p>email: <%= current_admin.email %></p>
|
<p>email: <%= current_user.email %></p>
|
||||||
<p>Role: <%= current_admin.role %></p>
|
<p>Role: <%= current_user.role %></p>
|
||||||
<%= link_to('Edit', admin_edit_profile_path, { class: 'btn' }) %>
|
<%= link_to('Edit', admin_edit_profile_path, { class: 'btn' }) %>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<td><%= quiz.dept %></td>
|
<td><%= quiz.dept %></td>
|
||||||
<td><%= quiz.unit %></td>
|
<td><%= quiz.unit %></td>
|
||||||
<td><%= quiz.questions.count %></td>
|
<td><%= quiz.questions.count %></td>
|
||||||
<td><%= link_to 'edit', admin_edit_quiz_path(quiz.to_i), { class: 'btn tertiary-btn' } %></td>
|
<td><%= link_to 'edit', admin_edit_quiz_path(quiz.to_i), { class: 'btn tertiary-btn' } if policy(quiz).edit? %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
<%
|
||||||
|
content_for :section_title, "Completed Tests"
|
||||||
|
%>
|
||||||
<main class="summary_tpl">
|
<main class="summary_tpl">
|
||||||
<h1>Completed Tests</h1>
|
|
||||||
|
|
||||||
<table cellspacing="0" cellpadding="0">
|
<table cellspacing="0" cellpadding="0">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Test ID</th>
|
<th>Test ID</th>
|
||||||
@ -10,7 +11,7 @@
|
|||||||
|
|
||||||
<% @candidates.each do |candidate| %>
|
<% @candidates.each do |candidate| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= link_to candidate.test_hash, review_test_path(candidate.test_hash) %></td>
|
<td><%= link_to candidate.test_hash, admin_result_path(candidate.test_hash) %></td>
|
||||||
<td><%= candidate.experience %> years</td>
|
<td><%= candidate.experience %> years</td>
|
||||||
<td><%= mail_to(candidate.recruiter.email) %></td>
|
<td><%= mail_to(candidate.recruiter.email) %></td>
|
||||||
</tr>
|
</tr>
|
@ -27,7 +27,7 @@
|
|||||||
<% end #form_tag %>
|
<% end #form_tag %>
|
||||||
<% end #questions loop %>
|
<% end #questions loop %>
|
||||||
|
|
||||||
<%= link_to(review_path, { class: 'secondary-btn' }) do %>
|
<%= link_to(admin_results_path, { class: 'secondary-btn' }) do %>
|
||||||
<button>Back to list</button>
|
<button>Back to list</button>
|
||||||
<% end %>
|
<% end %>
|
||||||
</main>
|
</main>
|
@ -11,7 +11,7 @@
|
|||||||
<td><%= link_to user.name, admin_user_path(user.to_i) %></td>
|
<td><%= link_to user.name, admin_user_path(user.to_i) %></td>
|
||||||
<td><%= mail_to(user.email) %></td>
|
<td><%= mail_to(user.email) %></td>
|
||||||
<td><%= user.role %></td>
|
<td><%= user.role %></td>
|
||||||
<td><%= link_to 'edit', admin_edit_user_path(user.to_i), { class: 'btn tertiary-btn' } %></td>
|
<td><%= link_to 'edit', admin_edit_user_path(user.to_i), { class: 'btn tertiary-btn' } if policy(user).edit? %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</table>
|
</table>
|
||||||
|
@ -4,4 +4,4 @@
|
|||||||
|
|
||||||
<h1>Users</h1>
|
<h1>Users</h1>
|
||||||
<%= render partial: 'admin/user/table_list', locals: { users: @users } %>
|
<%= render partial: 'admin/user/table_list', locals: { users: @users } %>
|
||||||
<%= link_to('New User', admin_new_user_path, { class: 'btn' }) %>
|
<%= link_to('New User', admin_new_user_path, { class: 'btn' }) if policy(User).create? %>
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
|
|
||||||
<header class="no-progressbar">
|
<header class="no-progressbar admin">
|
||||||
|
<%= render partial: "admin/nav" if current_user %>
|
||||||
<div class="page-title slash-left">
|
<div class="page-title slash-left">
|
||||||
<% if content_for?(:section_title) %>
|
<% if content_for?(:section_title) %>
|
||||||
<div><%= yield(:section_title) %></div>
|
<div><%= yield(:section_title) %></div>
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
<main class="intro_tpl">
|
|
||||||
<h1>Edit: <%= @candidate.name %></h1>
|
|
||||||
<p><strong>Test ID: </strong><%= @candidate.test_hash %></p>
|
|
||||||
|
|
||||||
<%= render partial: 'form', locals: { action: update_candidate_path(@candidate.id), candidate: @candidate, quizzes: @quizzes } %>
|
|
||||||
</main>
|
|
@ -1,21 +0,0 @@
|
|||||||
<main class="intro_tpl">
|
|
||||||
<h1>Recruiter Login</h1>
|
|
||||||
|
|
||||||
<% if flash[:error].present? %>
|
|
||||||
<div class="error"><%= flash[:error] %></div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= form_for :auth, url: recruiter_login_path do |form| %>
|
|
||||||
<div class="form-group">
|
|
||||||
<%= form.label :email %>
|
|
||||||
<%= form.email_field :email %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<%= form.label :password %>
|
|
||||||
<%= form.password_field :password %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<%= submit_tag "Log in" %>
|
|
||||||
<% end %>
|
|
||||||
</main>
|
|
@ -1,6 +0,0 @@
|
|||||||
<main class="intro_tpl">
|
|
||||||
<h1>New Candidate</h1>
|
|
||||||
|
|
||||||
<%= render partial: 'form', locals:
|
|
||||||
{ action: create_candidate_path, candidate: @candidate, quizzes: @quizzes } %>
|
|
||||||
</main>
|
|
@ -1,21 +0,0 @@
|
|||||||
<main class="intro_tpl">
|
|
||||||
<h1>Reviewer Login</h1>
|
|
||||||
|
|
||||||
<% if flash[:error].present? %>
|
|
||||||
<div class="error"><%= flash[:error] %></div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= form_for :auth, url: review_login_path do |form| %>
|
|
||||||
<div class="form-group">
|
|
||||||
<%= form.label :email %>
|
|
||||||
<%= form.email_field :email %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<%= form.label :password %>
|
|
||||||
<%= form.password_field :password %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<%= submit_tag "Login" %>
|
|
||||||
<% end %>
|
|
||||||
</main>
|
|
@ -1,6 +1,6 @@
|
|||||||
<row>
|
<row>
|
||||||
<columns class="email-body">
|
<columns class="email-body">
|
||||||
<p>Candidate <strong><%= @candidate.test_hash %></strong> has completed the Skills Assessment Test.</p>
|
<p>Candidate <strong><%= @candidate.test_hash %></strong> has completed the Skills Assessment Test.</p>
|
||||||
<p>You can view the results here: <%= link_to nil, review_test_url(@candidate.test_hash) %>.</p>
|
<p>You can view the results here: <%= link_to nil, admin_result_url(@candidate.test_hash) %>.</p>
|
||||||
</columns>
|
</columns>
|
||||||
</row>
|
</row>
|
@ -2,4 +2,4 @@ PERFICIENT/digital SKILLS ASSESSMENT RESULTS
|
|||||||
|
|
||||||
Candidate <%= @candidate.test_hash %> has completed the Skills Assessment Test.
|
Candidate <%= @candidate.test_hash %> has completed the Skills Assessment Test.
|
||||||
|
|
||||||
You can view the results here: <%= review_test_url(@candidate.test_hash) %>.
|
You can view the results here: <%= admin_result_url(@candidate.test_hash) %>.
|
||||||
|
10
config/brakeman.ignore
Normal file
10
config/brakeman.ignore
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"ignored_warnings": [
|
||||||
|
{
|
||||||
|
"fingerprint": "da17225c940987e6239cc4ecfe27bcb1e5da2db1134435dc3e1025d97927e0ba",
|
||||||
|
"note": "false positive"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": "2016-09-19 09:06:25 -0500",
|
||||||
|
"brakeman_version": "3.4.0"
|
||||||
|
}
|
@ -1,5 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
|
get "/styleguide", to: "application#styleguide", as: :styleguide
|
||||||
|
get "/admin/styleguide", to: "application#styleguide"
|
||||||
|
|
||||||
post "/admin/login", to: "admin/auth#auth", as: :admin_auth
|
post "/admin/login", to: "admin/auth#auth", as: :admin_auth
|
||||||
get "/admin/login", to: "admin/auth#login", as: :admin_login
|
get "/admin/login", to: "admin/auth#login", as: :admin_login
|
||||||
get "/admin/logout", to: "admin/auth#logout", as: :admin_logout
|
get "/admin/logout", to: "admin/auth#logout", as: :admin_logout
|
||||||
@ -33,46 +36,36 @@ Rails.application.routes.draw do
|
|||||||
post "/admin/question/:question_id/edit", to: "admin/question#update", as: :admin_update_question
|
post "/admin/question/:question_id/edit", to: "admin/question#update", as: :admin_update_question
|
||||||
patch "/admin/question/:question_id/edit", to: "admin/question#update"
|
patch "/admin/question/:question_id/edit", to: "admin/question#update"
|
||||||
|
|
||||||
get "/admin/profile", to: "admin/profile#view", as: :admin_profile
|
get "/admin/profile", to: "admin/profile#view", as: :admin_profile
|
||||||
post "/admin/profile", to: "admin/profile#update", as: :admin_update_profile
|
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/profile/edit", to: "admin/profile#edit", as: :admin_edit_profile
|
||||||
|
|
||||||
get "/admin", to: "admin#dashboard", as: :admin
|
get "/admin/candidates", to: "admin/candidate#index", as: :admin_candidates
|
||||||
|
get "/admin/candidate/new", to: "admin/candidate#new", as: :admin_new_candidate
|
||||||
|
post "/admin/candidate/new", to: "admin/candidate#create", as: :admin_create_candidate
|
||||||
|
get "/admin/candidate/:id", to: "admin/candidate#edit", as: :admin_edit_candidate
|
||||||
|
post "/admin/candidate/:id", to: "admin/candidate#update", as: :admin_update_candidate
|
||||||
|
get "/admin/candidate/:id/resend", to: "admin/candidate#resend_welcome", as: :admin_resend_welcome
|
||||||
|
|
||||||
|
get "/admin/results", to: "admin/result#index", as: :admin_results
|
||||||
|
get "/admin/result/:test_hash", to: "admin/result#view", as: :admin_result
|
||||||
|
|
||||||
|
get "/admin", to: "admin/dashboard#show", as: :admin
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
|
|
||||||
post "/validate", to: "candidate#validate", as: :validate_candidate
|
post "/validate", to: "candidate#validate", as: :validate_candidate
|
||||||
get "/login(/:test_id)", to: "candidate#login", as: :login
|
get "/login(/:test_id)", to: "candidate#login", as: :login
|
||||||
get "/welcome", to: "candidate#welcome", as: :welcome
|
get "/welcome", to: "candidate#welcome", as: :welcome
|
||||||
get "/saved", to: "candidate#saved", as: :saved
|
get "/saved", to: "candidate#saved", as: :saved
|
||||||
get "/thankyou", to: "candidate#thankyou", as: :thankyou
|
get "/thankyou", to: "candidate#thankyou", as: :thankyou
|
||||||
|
get "/oops", to: "candidate#oops", as: :oops
|
||||||
get "/oops", to: "candidate#oops", as: :oops
|
|
||||||
|
|
||||||
post "/question(/:answer_id)", to: "quiz#update_answer", as: :post_answer
|
post "/question(/:answer_id)", to: "quiz#update_answer", as: :post_answer
|
||||||
get "/question(/:question_id)", to: "quiz#question", as: :question
|
get "/question(/:question_id)", to: "quiz#question", as: :question
|
||||||
post "/summary", to: "quiz#submit_summary", as: :post_summary
|
post "/summary", to: "quiz#submit_summary", as: :post_summary
|
||||||
get "/summary", to: "quiz#summary", as: :summary
|
get "/summary", to: "quiz#summary", as: :summary
|
||||||
|
|
||||||
get "/review/logout", to: "review#logout", as: :review_logout
|
|
||||||
post "/review/login", to: "review#auth", as: :review_auth
|
|
||||||
get "/review/login", to: "review#login", as: :review_login
|
|
||||||
get "/review", to: "review#index", as: :review
|
|
||||||
get "/review/:test_hash", to: "review#view", as: :review_test
|
|
||||||
|
|
||||||
get "/resend/welcome/:id", to: "recruiter#resend_welcome", as: :resend_welcome
|
|
||||||
|
|
||||||
get "/recruiter", to: "recruiter#index", as: :recruiter
|
|
||||||
get "/recruiter/candidate", to: "recruiter#new", as: :new_candidate
|
|
||||||
post "/recruiter/candidate", to: "recruiter#create", as: :create_candidate
|
|
||||||
get "/recruiter/candidate/:id", to: "recruiter#edit", as: :edit_candidate
|
|
||||||
post "/recruiter/candidate/:id", to: "recruiter#update", as: :update_candidate
|
|
||||||
get "/recruiter/logout", to: "recruiter#logout", as: :recruiter_logout
|
|
||||||
get "/recruiter/login", to: "recruiter#login", as: :recruiter_login
|
|
||||||
post "/recruiter/login", to: "recruiter#auth", as: :recruiter_auth
|
|
||||||
|
|
||||||
get "/styleguide", to: "application#styleguide", as: :styleguide
|
|
||||||
|
|
||||||
root to: "candidate#login"
|
root to: "candidate#login"
|
||||||
|
|
||||||
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
|
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
|
||||||
|
@ -26,18 +26,16 @@ module Admin
|
|||||||
assert_redirected_to admin_url
|
assert_redirected_to admin_url
|
||||||
end
|
end
|
||||||
|
|
||||||
test "recruiter should not admin auth" do
|
test "recruiter should auth to dashboard" do
|
||||||
post admin_auth_url, params: { auth:
|
post admin_auth_url, params: { auth:
|
||||||
{ email: 'pdr.recruiter@mailinator.com', password: 'password' } }
|
{ email: 'pdr.recruiter@mailinator.com', password: 'password' } }
|
||||||
assert_redirected_to admin_login_url
|
assert_redirected_to admin_url
|
||||||
assert_match(/incorrect.*email/, flash[:error])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "reviewer should not admin auth" do
|
test "reviewer should auth to dashboard" do
|
||||||
post admin_auth_url, params: { auth:
|
post admin_auth_url, params: { auth:
|
||||||
{ email: 'fed.reviewer@mailinator.com', password: 'password' } }
|
{ email: 'fed.reviewer@mailinator.com', password: 'password' } }
|
||||||
assert_redirected_to admin_login_url
|
assert_redirected_to admin_url
|
||||||
assert_match(/incorrect.*email/, flash[:error])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "should get reset_request" do
|
test "should get reset_request" do
|
||||||
|
31
test/controllers/admin/candidate_controller/index_test.rb
Normal file
31
test/controllers/admin/candidate_controller/index_test.rb
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class CandidateControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
test "should require auth or redirect" do
|
||||||
|
get admin_candidates_url
|
||||||
|
assert_redirected_to admin_login_url
|
||||||
|
|
||||||
|
get admin_new_candidate_url
|
||||||
|
assert_redirected_to admin_login_url
|
||||||
|
|
||||||
|
post admin_create_candidate_url, params: { candidate: { name: 'foo', email: 'bar', experience: 'baz' } }
|
||||||
|
assert_redirected_to admin_login_url
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should get candidate list" do
|
||||||
|
auth_recruiter
|
||||||
|
get admin_candidates_url
|
||||||
|
assert_response :success
|
||||||
|
assert assigns(:candidates), "@candidates not present"
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should have edit links' do
|
||||||
|
auth_recruiter
|
||||||
|
get admin_candidates_url
|
||||||
|
assert_response :success
|
||||||
|
assert_select "a[href='#{admin_edit_candidate_path(candidates(:martha))}']"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,73 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class CandidateControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
include ActiveJob::TestHelper
|
||||||
|
|
||||||
|
test "should get new" do
|
||||||
|
auth_recruiter
|
||||||
|
get admin_new_candidate_url
|
||||||
|
assert_response :success
|
||||||
|
assert assigns(:candidate), "@candidate not present"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should get create" do
|
||||||
|
auth_recruiter
|
||||||
|
get admin_create_candidate_url
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should create new candidate" do
|
||||||
|
auth_recruiter
|
||||||
|
|
||||||
|
assert_enqueued_jobs 2 do
|
||||||
|
assert_difference("Candidate.count") do
|
||||||
|
post admin_create_candidate_path, params: { candidate:
|
||||||
|
{ name: 'new name', email: 'test@mailinator.com', experience: '0-3', quiz_id: quizzes(:fed).id } }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_redirected_to admin_candidates_path
|
||||||
|
assert flash[:success]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should fail creation with improper email format" do
|
||||||
|
auth_recruiter
|
||||||
|
|
||||||
|
assert_enqueued_jobs 0 do
|
||||||
|
assert_difference("Candidate.count", 0) do
|
||||||
|
post admin_create_candidate_path, params: { candidate:
|
||||||
|
{ name: 'new name', email: 'test@mailinatorcom', experience: '0-3', quiz_id: quizzes(:fed).id } }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert :success
|
||||||
|
assert assigns(:candidate), "@candidate not present"
|
||||||
|
assert_match(/failed.*save/i, flash[:error])
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should fail creation gracefully with empty email" do
|
||||||
|
auth_recruiter
|
||||||
|
|
||||||
|
assert_enqueued_jobs 0 do
|
||||||
|
assert_difference("Candidate.count", 0) do
|
||||||
|
post admin_create_candidate_path, params: { candidate:
|
||||||
|
{ name: 'new name', email: "", experience: '0-3', quiz_id: quizzes(:fed).id } }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert :success
|
||||||
|
assert assigns(:candidate), "@candidate not present"
|
||||||
|
assert_match(/failed.*save/i, flash[:error])
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should queue up a welcome email [resend]' do
|
||||||
|
auth_recruiter
|
||||||
|
|
||||||
|
assert_enqueued_jobs 1 do
|
||||||
|
get admin_resend_welcome_path(id: candidates(:peggy)), xhr: true
|
||||||
|
end
|
||||||
|
assert_response :success
|
||||||
|
data = JSON.parse(response.body)
|
||||||
|
assert_match 'queued', data["message"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,36 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class CandidateControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
test 'should edit candidate' do
|
||||||
|
auth_recruiter
|
||||||
|
candidate = candidates(:martha)
|
||||||
|
|
||||||
|
get admin_edit_candidate_path(candidate.id)
|
||||||
|
assert_response :success
|
||||||
|
assert_select 'form'
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should update candidate, but NOT test_hash' do
|
||||||
|
auth_recruiter
|
||||||
|
candidate = candidates(:martha)
|
||||||
|
post admin_update_candidate_url(id: candidate.id), params:
|
||||||
|
{ candidate: { name: 'new name', email: "mail@martha.me", test_hash: 'SOMENEWSTRING' } }
|
||||||
|
|
||||||
|
refute_equal candidate.name, Candidate.find_by(id: candidate.id).name
|
||||||
|
assert_equal candidate.test_hash, Candidate.find_by(id: candidate.id).test_hash
|
||||||
|
assert_redirected_to admin_candidates_url
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should redirect to form on fail' do
|
||||||
|
auth_recruiter
|
||||||
|
candidate = candidates(:martha)
|
||||||
|
post admin_update_candidate_url(id: candidate.id), params:
|
||||||
|
{ candidate: { name: 'new name', email: "mail@martha" } }
|
||||||
|
|
||||||
|
assert :success
|
||||||
|
assert_match(/failed.*save/i, flash[:error])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
18
test/controllers/admin/dashboard_controller_test.rb
Normal file
18
test/controllers/admin/dashboard_controller_test.rb
Normal file
@ -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_users_url
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
23
test/controllers/admin/result_controller_test.rb
Normal file
23
test/controllers/admin/result_controller_test.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
class ResultControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
test "should get results list" do
|
||||||
|
auth_reviewer
|
||||||
|
get admin_results_url
|
||||||
|
assert_response :success
|
||||||
|
assert assigns(:candidates), '@candidates not present'
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should get view" do
|
||||||
|
auth_reviewer
|
||||||
|
|
||||||
|
get admin_result_url(candidates(:richard).test_hash)
|
||||||
|
assert_response :success
|
||||||
|
assert assigns(:candidate), "@candidate not present"
|
||||||
|
assert assigns(:quiz), "@quiz not present"
|
||||||
|
assert assigns(:status), "@status not present"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -2,15 +2,4 @@
|
|||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class AdminControllerTest < ActionDispatch::IntegrationTest
|
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
|
end
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class RecruiterControllerTest < ActionDispatch::IntegrationTest
|
|
||||||
test "should get login" do
|
|
||||||
get recruiter_login_url
|
|
||||||
assert_response :success
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should logout and reset session' do
|
|
||||||
auth_recruiter
|
|
||||||
get recruiter_logout_path
|
|
||||||
|
|
||||||
assert :success
|
|
||||||
assert session[:user].nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should require auth or redirect" do
|
|
||||||
get recruiter_url
|
|
||||||
assert_redirected_to recruiter_login_path
|
|
||||||
|
|
||||||
get new_candidate_url
|
|
||||||
assert_redirected_to recruiter_login_path
|
|
||||||
|
|
||||||
post create_candidate_url, params: { candidate: { name: 'foo', email: 'bar', experience: 'baz' } }
|
|
||||||
assert_redirected_to recruiter_login_path
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should auth to index" do
|
|
||||||
auth_recruiter
|
|
||||||
assert_redirected_to recruiter_path
|
|
||||||
assert session[:user].present?
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should fail auth with flash" do
|
|
||||||
post recruiter_auth_url, params: { auth:
|
|
||||||
{ email: 'pdr.recruiter@mailinator.com', password: 'bad-password' } }
|
|
||||||
|
|
||||||
assert_redirected_to recruiter_login_path
|
|
||||||
assert flash[:error]
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should get candidate list" do
|
|
||||||
auth_recruiter
|
|
||||||
get recruiter_url
|
|
||||||
assert_response :success
|
|
||||||
assert assigns(:candidates), "@candidates not present"
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should have edit links' do
|
|
||||||
auth_recruiter
|
|
||||||
get recruiter_url
|
|
||||||
assert_response :success
|
|
||||||
assert_select "a[href='#{edit_candidate_path(candidates(:martha))}']"
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,71 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class RecruiterControllerTest < ActionDispatch::IntegrationTest
|
|
||||||
include ActiveJob::TestHelper
|
|
||||||
|
|
||||||
test "should get new" do
|
|
||||||
auth_recruiter
|
|
||||||
get new_candidate_url
|
|
||||||
assert_response :success
|
|
||||||
assert assigns(:candidate), "@candidate not present"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should get create" do
|
|
||||||
auth_recruiter
|
|
||||||
get create_candidate_url
|
|
||||||
assert_response :success
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should create new candidate" do
|
|
||||||
auth_recruiter
|
|
||||||
|
|
||||||
assert_enqueued_jobs 2 do
|
|
||||||
assert_difference("Candidate.count") do
|
|
||||||
post create_candidate_path, params: { candidate:
|
|
||||||
{ name: 'new name', email: 'test@mailinator.com', experience: '0-3', quiz_id: quizzes(:fed).id } }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
assert_redirected_to recruiter_path
|
|
||||||
assert flash[:success]
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should fail creation with improper email format" do
|
|
||||||
auth_recruiter
|
|
||||||
|
|
||||||
assert_enqueued_jobs 0 do
|
|
||||||
assert_difference("Candidate.count", 0) do
|
|
||||||
post create_candidate_path, params: { candidate:
|
|
||||||
{ name: 'new name', email: 'test@mailinatorcom', experience: '0-3', quiz_id: quizzes(:fed).id } }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
assert :success
|
|
||||||
assert assigns(:candidate), "@candidate not present"
|
|
||||||
assert_match(/failed.*save/i, flash[:error])
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should fail creation gracefully with empty email" do
|
|
||||||
auth_recruiter
|
|
||||||
|
|
||||||
assert_enqueued_jobs 0 do
|
|
||||||
assert_difference("Candidate.count", 0) do
|
|
||||||
post create_candidate_path, params: { candidate:
|
|
||||||
{ name: 'new name', email: "", experience: '0-3', quiz_id: quizzes(:fed).id } }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
assert :success
|
|
||||||
assert assigns(:candidate), "@candidate not present"
|
|
||||||
assert_match(/failed.*save/i, flash[:error])
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should queue up a welcome email [resend]' do
|
|
||||||
auth_recruiter
|
|
||||||
|
|
||||||
assert_enqueued_jobs 1 do
|
|
||||||
get resend_welcome_path(id: candidates(:peggy)), xhr: true
|
|
||||||
end
|
|
||||||
assert_response :success
|
|
||||||
data = JSON.parse(response.body)
|
|
||||||
assert_match 'queued', data["message"]
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,34 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class RecruiterControllerTest < ActionDispatch::IntegrationTest
|
|
||||||
test 'should edit candidate' do
|
|
||||||
auth_recruiter
|
|
||||||
candidate = candidates(:martha)
|
|
||||||
|
|
||||||
get edit_candidate_path(candidate.id)
|
|
||||||
assert_response :success
|
|
||||||
assert_select 'form'
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should update candidate, but NOT test_hash' do
|
|
||||||
auth_recruiter
|
|
||||||
candidate = candidates(:martha)
|
|
||||||
post update_candidate_url(id: candidate.id), params:
|
|
||||||
{ candidate: { name: 'new name', email: "mail@martha.me", test_hash: 'SOMENEWSTRING' } }
|
|
||||||
|
|
||||||
refute_equal candidate.name, Candidate.find_by(id: candidate.id).name
|
|
||||||
assert_equal candidate.test_hash, Candidate.find_by(id: candidate.id).test_hash
|
|
||||||
assert_redirected_to recruiter_url
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should redirect to form on fail' do
|
|
||||||
auth_recruiter
|
|
||||||
candidate = candidates(:martha)
|
|
||||||
post update_candidate_url(id: candidate.id), params:
|
|
||||||
{ candidate: { name: 'new name', email: "mail@martha" } }
|
|
||||||
|
|
||||||
assert :success
|
|
||||||
assert_match(/failed.*save/i, flash[:error])
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,63 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class ReviewControllerTest < ActionDispatch::IntegrationTest
|
|
||||||
test "should get login" do
|
|
||||||
get review_login_url
|
|
||||||
assert_response :success
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should require auth or redirect" do
|
|
||||||
get review_url
|
|
||||||
assert_redirected_to review_login_path
|
|
||||||
|
|
||||||
get review_test_url(candidates(:richard).test_hash)
|
|
||||||
assert_redirected_to review_login_path
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should auth to index" do
|
|
||||||
auth_reviewer
|
|
||||||
assert_redirected_to review_path
|
|
||||||
assert session[:user].present?
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should fail auth with flash" do
|
|
||||||
post review_auth_url, params: { auth:
|
|
||||||
{ email: 'fed.review@mailinator.com', password: 'bad-password' } }
|
|
||||||
|
|
||||||
assert_redirected_to review_login_path
|
|
||||||
assert flash[:error]
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should get review list" do
|
|
||||||
auth_reviewer
|
|
||||||
get review_url
|
|
||||||
assert_response :success
|
|
||||||
assert assigns(:candidates), '@candidates not present'
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should get index" do
|
|
||||||
auth_reviewer
|
|
||||||
|
|
||||||
get review_url
|
|
||||||
assert_response :success
|
|
||||||
end
|
|
||||||
|
|
||||||
test "should get view" do
|
|
||||||
auth_reviewer
|
|
||||||
|
|
||||||
get review_test_url(candidates(:richard).test_hash)
|
|
||||||
assert_response :success
|
|
||||||
assert assigns(:candidate), "@candidate not present"
|
|
||||||
assert assigns(:quiz), "@quiz not present"
|
|
||||||
assert assigns(:status), "@status not present"
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should logout and reset session' do
|
|
||||||
auth_reviewer
|
|
||||||
get review_logout_path
|
|
||||||
|
|
||||||
assert :success
|
|
||||||
assert session[:user].nil?
|
|
||||||
end
|
|
||||||
end
|
|
10
test/fixtures/questions.yml
vendored
10
test/fixtures/questions.yml
vendored
@ -111,3 +111,13 @@ fed10:
|
|||||||
- "wibbly wobbly, timey wimey"
|
- "wibbly wobbly, timey wimey"
|
||||||
sort: 9
|
sort: 9
|
||||||
active: true
|
active: true
|
||||||
|
|
||||||
|
admin1:
|
||||||
|
quiz: admin
|
||||||
|
question: 'You have a question you want to ask.'
|
||||||
|
category: Admin
|
||||||
|
input_type: text
|
||||||
|
input_options:
|
||||||
|
sort: 0
|
||||||
|
active: true
|
||||||
|
|
||||||
|
5
test/fixtures/quizzes.yml
vendored
5
test/fixtures/quizzes.yml
vendored
@ -4,3 +4,8 @@ fed:
|
|||||||
name: PDR Standard FED Screening
|
name: PDR Standard FED Screening
|
||||||
unit: PDR
|
unit: PDR
|
||||||
dept: FED
|
dept: FED
|
||||||
|
|
||||||
|
admin:
|
||||||
|
name: An extra quiz not assigned to anyone
|
||||||
|
unit: PDR
|
||||||
|
dept: NOPE
|
||||||
|
6
test/fixtures/users.yml
vendored
6
test/fixtures/users.yml
vendored
@ -18,6 +18,12 @@ reviewer2:
|
|||||||
password_digest: <%= BCrypt::Password.create("password", cost: 4) %>
|
password_digest: <%= BCrypt::Password.create("password", cost: 4) %>
|
||||||
role: reviewer
|
role: reviewer
|
||||||
|
|
||||||
|
manager:
|
||||||
|
name: Mary Manager
|
||||||
|
email: mary.manager@mailinator.com
|
||||||
|
password_digest: <%= BCrypt::Password.create("password", cost: 4) %>
|
||||||
|
role: manager
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
name: Alan Admin
|
name: Alan Admin
|
||||||
email: alan.admin@mailinator.com
|
email: alan.admin@mailinator.com
|
||||||
|
@ -20,10 +20,9 @@ class QuestionAttachmentsTest < ActionDispatch::IntegrationTest
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "should show attachments on review" do
|
test "should show attachments on review" do
|
||||||
user = users :reviewer
|
auth_reviewer
|
||||||
post review_auth_url, params: { auth: { email: user.email, password: 'password' } }
|
|
||||||
|
|
||||||
get review_test_path(candidates(:richard).test_hash)
|
get admin_result_path(candidates(:richard).test_hash)
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert_select "img[src=\"#{questions(:fed6).attachment}\"]"
|
assert_select "img[src=\"#{questions(:fed6).attachment}\"]"
|
||||||
end
|
end
|
||||||
|
10
test/policies/admin_policy_test.rb
Normal file
10
test/policies/admin_policy_test.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
# TODO: How the heck to you test a headless policy?...
|
||||||
|
#
|
||||||
|
# class AdminPolicyTest < PolicyAssertions::Test
|
||||||
|
# def test_dashboard
|
||||||
|
# assert_permit users(:recruiter), Admin
|
||||||
|
# end
|
||||||
|
# end
|
30
test/policies/application_policy_test.rb
Normal file
30
test/policies/application_policy_test.rb
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ApplicationPolicyTest < PolicyAssertions::Test
|
||||||
|
# Verify default policies are most restrictive
|
||||||
|
|
||||||
|
test 'should require a user' do
|
||||||
|
assert_raise Pundit::NotAuthorizedError do
|
||||||
|
ApplicationPolicy.new(nil, User.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should not allow collections' do
|
||||||
|
assert_raise Pundit::NotAuthorizedError do
|
||||||
|
ApplicationPolicy::Scope.new(users(:admin), User).resolve
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should not permit by default' do
|
||||||
|
admin = users(:admin)
|
||||||
|
refute ApplicationPolicy.new(admin, User.new).view?
|
||||||
|
refute ApplicationPolicy.new(admin, User.new).show?
|
||||||
|
refute ApplicationPolicy.new(admin, nil).index?
|
||||||
|
refute ApplicationPolicy.new(admin, nil).create?
|
||||||
|
refute ApplicationPolicy.new(admin, nil).new?
|
||||||
|
refute ApplicationPolicy.new(admin, nil).update?
|
||||||
|
refute ApplicationPolicy.new(admin, nil).edit?
|
||||||
|
refute ApplicationPolicy.new(admin, nil).destroy?
|
||||||
|
end
|
||||||
|
end
|
48
test/policies/candidate_policy_test.rb
Normal file
48
test/policies/candidate_policy_test.rb
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class CandidatePolicyTest < PolicyAssertions::Test
|
||||||
|
test 'should require current_user' do
|
||||||
|
assert_raise Pundit::NotAuthorizedError do
|
||||||
|
CandidatePolicy.new(nil, Candidate.first).view?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should allow admin to scope' do
|
||||||
|
scope = CandidatePolicy::Scope.new(users(:admin), Candidate).resolve
|
||||||
|
assert_equal Candidate.count, scope.count
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should allow recruiter to scope' do
|
||||||
|
scope = CandidatePolicy::Scope.new(users(:recruiter), Candidate).resolve
|
||||||
|
assert_equal Candidate.count, scope.count
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'reviewer CAN NOT scope candidates' do
|
||||||
|
assert_raise Pundit::NotAuthorizedError do
|
||||||
|
CandidatePolicy::Scope.new(users(:reviewer), Candidate).resolve
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'manager CAN NOT scope candidates' do
|
||||||
|
assert_raise Pundit::NotAuthorizedError do
|
||||||
|
CandidatePolicy::Scope.new(users(:manager), Candidate).resolve
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_view_and_update
|
||||||
|
assert_permit users(:admin), candidates(:roy)
|
||||||
|
assert_permit users(:recruiter), candidates(:roy)
|
||||||
|
|
||||||
|
refute_permit users(:manager), candidates(:roy)
|
||||||
|
refute_permit users(:reviewer), candidates(:roy)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create
|
||||||
|
assert_permit users(:admin), Candidate
|
||||||
|
assert_permit users(:recruiter), Candidate
|
||||||
|
|
||||||
|
refute_permit users(:manager), Candidate
|
||||||
|
refute_permit users(:reviewer), Candidate
|
||||||
|
end
|
||||||
|
end
|
50
test/policies/question_policy_test.rb
Normal file
50
test/policies/question_policy_test.rb
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class QuestionPolicyTest < PolicyAssertions::Test
|
||||||
|
test 'should require current_user' do
|
||||||
|
assert_raise Pundit::NotAuthorizedError do
|
||||||
|
QuestionPolicy.new(nil, Question.first).view?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should allow admin to scope' do
|
||||||
|
scope = QuestionPolicy::Scope.new(users(:admin), Question).resolve
|
||||||
|
assert_equal Question.count, scope.count
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should allow manager to scope' do
|
||||||
|
scope = QuestionPolicy::Scope.new(users(:manager), Question).resolve
|
||||||
|
assert_equal Question.count, scope.count
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should allow reviewer to scope' do
|
||||||
|
quiz_ids = users(:reviewer).quizzes.map(&:id)
|
||||||
|
|
||||||
|
scope = QuestionPolicy::Scope.new(users(:reviewer), Question).resolve
|
||||||
|
assert_equal Question.where(quiz_id: quiz_ids).count, scope.count
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should NOT allow recruiter to scope' do
|
||||||
|
assert_raise Pundit::NotAuthorizedError do
|
||||||
|
QuestionPolicy::Scope.new(users(:recruiter), Question).resolve
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_view_and_options
|
||||||
|
assert_permit users(:admin), questions(:fed1)
|
||||||
|
assert_permit users(:manager), questions(:fed1)
|
||||||
|
assert_permit users(:reviewer), questions(:fed1)
|
||||||
|
|
||||||
|
refute_permit users(:reviewer), questions(:admin1)
|
||||||
|
refute_permit users(:recruiter), questions(:fed1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_and_update
|
||||||
|
assert_permit users(:admin), Question
|
||||||
|
assert_permit users(:manager), Question
|
||||||
|
|
||||||
|
refute_permit users(:recruiter), Question
|
||||||
|
refute_permit users(:reviewer), Question
|
||||||
|
end
|
||||||
|
end
|
47
test/policies/quiz_policy_test.rb
Normal file
47
test/policies/quiz_policy_test.rb
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class QuizPolicyTest < PolicyAssertions::Test
|
||||||
|
test 'should require current_user' do
|
||||||
|
assert_raise Pundit::NotAuthorizedError do
|
||||||
|
QuizPolicy.new(nil, Quiz.first).view?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should allow admin to scope' do
|
||||||
|
scope = QuizPolicy::Scope.new(users(:admin), Quiz).resolve
|
||||||
|
assert_equal Quiz.count, scope.count
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should allow manager to scope' do
|
||||||
|
scope = QuizPolicy::Scope.new(users(:manager), Quiz).resolve
|
||||||
|
assert_equal Quiz.count, scope.count
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should allow reviewer to scope' do
|
||||||
|
scope = QuizPolicy::Scope.new(users(:reviewer), Quiz).resolve
|
||||||
|
assert_equal users(:reviewer).quizzes.count, scope.count
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should allow recruiter to scope' do
|
||||||
|
scope = QuizPolicy::Scope.new(users(:recruiter), Quiz).resolve
|
||||||
|
assert_equal Quiz.count, scope.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_view
|
||||||
|
assert_permit users(:admin), quizzes(:fed)
|
||||||
|
assert_permit users(:manager), quizzes(:fed)
|
||||||
|
assert_permit users(:reviewer), quizzes(:fed)
|
||||||
|
|
||||||
|
refute_permit users(:reviewer), quizzes(:admin)
|
||||||
|
refute_permit users(:recruiter), quizzes(:fed)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_and_update
|
||||||
|
assert_permit users(:admin), Quiz
|
||||||
|
assert_permit users(:manager), Quiz
|
||||||
|
|
||||||
|
refute_permit users(:recruiter), Quiz
|
||||||
|
refute_permit users(:reviewer), Quiz
|
||||||
|
end
|
||||||
|
end
|
96
test/policies/user_policy_test.rb
Normal file
96
test/policies/user_policy_test.rb
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class UserPolicyTest < PolicyAssertions::Test
|
||||||
|
test 'should require current_user' do
|
||||||
|
assert_raise Pundit::NotAuthorizedError do
|
||||||
|
UserPolicy.new(nil, User.first).view?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'should allow admin to scope' do
|
||||||
|
scope = UserPolicy::Scope.new(users(:admin), User).resolve
|
||||||
|
assert_equal User.count, scope.count
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'non admins can only scope themselves' do
|
||||||
|
%i(manager reviewer recruiter).each do |role|
|
||||||
|
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
|
||||||
|
|
||||||
|
# view?
|
||||||
|
test 'admin can view any user role' do
|
||||||
|
assert_permit users(:admin), users(:admin), 'view?'
|
||||||
|
assert_permit users(:admin), users(:manager), 'view?'
|
||||||
|
assert_permit users(:admin), users(:reviewer), 'view?'
|
||||||
|
assert_permit users(:admin), users(:recruiter), 'view?'
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'manager can only view herself' do
|
||||||
|
assert_permit users(:manager), users(:manager), 'view?'
|
||||||
|
|
||||||
|
refute_permit users(:manager), users(:admin), 'view?'
|
||||||
|
refute_permit users(:manager), users(:reviewer), 'view?'
|
||||||
|
refute_permit users(:manager), users(:recruiter), 'view?'
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'reviewer can only view herself' do
|
||||||
|
assert_permit users(:reviewer), users(:reviewer), 'view?'
|
||||||
|
|
||||||
|
refute_permit users(:reviewer), users(:admin), 'view?'
|
||||||
|
refute_permit users(:reviewer), users(:manager), 'view?'
|
||||||
|
refute_permit users(:reviewer), users(:recruiter), 'view?'
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'recruiter can only view herself' do
|
||||||
|
assert_permit users(:recruiter), users(:recruiter), 'view?'
|
||||||
|
|
||||||
|
refute_permit users(:recruiter), users(:admin), 'view?'
|
||||||
|
refute_permit users(:recruiter), users(:manager), 'view?'
|
||||||
|
refute_permit users(:recruiter), users(:reviewer), 'view?'
|
||||||
|
end
|
||||||
|
|
||||||
|
# update?
|
||||||
|
test 'admin can update any user role' do
|
||||||
|
assert_permit users(:admin), users(:admin), 'update?'
|
||||||
|
assert_permit users(:admin), users(:manager), 'update?'
|
||||||
|
assert_permit users(:admin), users(:reviewer), 'update?'
|
||||||
|
assert_permit users(:admin), users(:recruiter), 'update?'
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'manager can only update herself' do
|
||||||
|
assert_permit users(:manager), users(:manager), 'update?'
|
||||||
|
|
||||||
|
refute_permit users(:manager), users(:admin), 'update?'
|
||||||
|
refute_permit users(:manager), users(:reviewer), 'update?'
|
||||||
|
refute_permit users(:manager), users(:recruiter), 'update?'
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'reupdateer can only update herself' do
|
||||||
|
assert_permit users(:reviewer), users(:reviewer), 'update?'
|
||||||
|
|
||||||
|
refute_permit users(:reviewer), users(:admin), 'update?'
|
||||||
|
refute_permit users(:reviewer), users(:manager), 'update?'
|
||||||
|
refute_permit users(:reviewer), users(:recruiter), 'update?'
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'recruiter can only update herself' do
|
||||||
|
assert_permit users(:recruiter), users(:recruiter), 'update?'
|
||||||
|
|
||||||
|
refute_permit users(:recruiter), users(:admin), 'update?'
|
||||||
|
refute_permit users(:recruiter), users(:manager), 'update?'
|
||||||
|
refute_permit users(:recruiter), users(:reviewer), 'update?'
|
||||||
|
end
|
||||||
|
|
||||||
|
# create
|
||||||
|
test 'only admin can create users' do
|
||||||
|
assert_permit users(:admin), User, 'create?'
|
||||||
|
|
||||||
|
refute_permit users(:manager), User, 'create?'
|
||||||
|
refute_permit users(:reviewer), User, 'create?'
|
||||||
|
refute_permit users(:recruiter), User, 'create?'
|
||||||
|
end
|
||||||
|
end
|
@ -7,12 +7,13 @@ SimpleCov.start 'rails' do
|
|||||||
add_group 'Models', %w(app/models app/validators)
|
add_group 'Models', %w(app/models app/validators)
|
||||||
add_group 'Services & Workers', %w(app/workers app/services)
|
add_group 'Services & Workers', %w(app/workers app/services)
|
||||||
add_group "Jobs", 'app/jobs'
|
add_group "Jobs", 'app/jobs'
|
||||||
|
add_group "Policies", 'app/policies'
|
||||||
end
|
end
|
||||||
|
|
||||||
require File.expand_path('../../config/environment', __FILE__)
|
require File.expand_path('../../config/environment', __FILE__)
|
||||||
require 'rails/test_help'
|
require 'rails/test_help'
|
||||||
require "minitest/autorun"
|
|
||||||
require 'minitest/reporters'
|
require 'minitest/reporters'
|
||||||
|
require 'policy_assertions'
|
||||||
Dir[Rails.root.join("test/test_helpers/**/*.rb")].each { |f| require f }
|
Dir[Rails.root.join("test/test_helpers/**/*.rb")].each { |f| require f }
|
||||||
|
|
||||||
Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(color: true)]
|
Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(color: true)]
|
||||||
|
@ -4,13 +4,28 @@ module AuthTestHelper
|
|||||||
post validate_candidate_url, params: { test_id: candidate.test_hash }
|
post validate_candidate_url, params: { test_id: candidate.test_hash }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def auth_user user
|
||||||
|
post admin_auth_url, params: { auth:
|
||||||
|
{ email: user.email, password: 'password' } }
|
||||||
|
end
|
||||||
|
|
||||||
|
def auth_admin
|
||||||
|
post admin_auth_url, params: { auth:
|
||||||
|
{ email: 'alan.admin@mailinator.com', password: 'password' } }
|
||||||
|
end
|
||||||
|
|
||||||
|
def auth_manager
|
||||||
|
post admin_auth_url, params: { auth:
|
||||||
|
{ email: 'mary.manager@mailinator.com', password: 'password' } }
|
||||||
|
end
|
||||||
|
|
||||||
def auth_recruiter
|
def auth_recruiter
|
||||||
post recruiter_auth_url, params: { auth:
|
post admin_auth_url, params: { auth:
|
||||||
{ email: 'pdr.recruiter@mailinator.com', password: 'password' } }
|
{ email: 'pdr.recruiter@mailinator.com', password: 'password' } }
|
||||||
end
|
end
|
||||||
|
|
||||||
def auth_reviewer
|
def auth_reviewer
|
||||||
post review_auth_url, params: { auth:
|
post admin_auth_url, params: { auth:
|
||||||
{ email: 'fed.reviewer@mailinator.com', password: 'password' } }
|
{ email: 'fed.reviewer@mailinator.com', password: 'password' } }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user