add in scaffold admin interface

completes #65
Merge branch 'feature/admin-interface' into develop
This commit is contained in:
Mark Moser 2016-08-22 16:31:47 -05:00
commit 393fd15ab5
61 changed files with 1202 additions and 104 deletions

View File

@ -3,7 +3,7 @@ source 'https://rubygems.org'
gem 'figaro', '~> 1.1.1' gem 'figaro', '~> 1.1.1'
gem 'bcrypt', '~> 3.1.7' gem 'bcrypt', '~> 3.1.7'
gem 'mysql2', '>= 0.3.18', '< 0.5' gem 'mysql2', '>= 0.3.18', '< 0.5'
gem 'rails', '~> 5.0.0' gem 'rails', '~> 5.0', '>= 5.0.0.1'
gem 'jbuilder', '~> 2.6' gem 'jbuilder', '~> 2.6'
gem 'jquery-rails' gem 'jquery-rails'

View File

@ -1,46 +1,46 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (5.0.0) actioncable (5.0.0.1)
actionpack (= 5.0.0) actionpack (= 5.0.0.1)
nio4r (~> 1.2) nio4r (~> 1.2)
websocket-driver (~> 0.6.1) websocket-driver (~> 0.6.1)
actionmailer (5.0.0) actionmailer (5.0.0.1)
actionpack (= 5.0.0) actionpack (= 5.0.0.1)
actionview (= 5.0.0) actionview (= 5.0.0.1)
activejob (= 5.0.0) activejob (= 5.0.0.1)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
actionpack (5.0.0) actionpack (5.0.0.1)
actionview (= 5.0.0) actionview (= 5.0.0.1)
activesupport (= 5.0.0) activesupport (= 5.0.0.1)
rack (~> 2.0) rack (~> 2.0)
rack-test (~> 0.6.3) rack-test (~> 0.6.3)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.0.0) actionview (5.0.0.1)
activesupport (= 5.0.0) activesupport (= 5.0.0.1)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubis (~> 2.7.0)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (5.0.0) activejob (5.0.0.1)
activesupport (= 5.0.0) activesupport (= 5.0.0.1)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (5.0.0) activemodel (5.0.0.1)
activesupport (= 5.0.0) activesupport (= 5.0.0.1)
activerecord (5.0.0) activerecord (5.0.0.1)
activemodel (= 5.0.0) activemodel (= 5.0.0.1)
activesupport (= 5.0.0) activesupport (= 5.0.0.1)
arel (~> 7.0) arel (~> 7.0)
activesupport (5.0.0) activesupport (5.0.0.1)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7) i18n (~> 0.7)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
addressable (2.4.0) addressable (2.4.0)
ansi (1.5.0) ansi (1.5.0)
arel (7.1.0) arel (7.1.1)
ast (2.3.0) ast (2.3.0)
awesome_print (1.7.0) awesome_print (1.7.0)
bcrypt (3.1.11) bcrypt (3.1.11)
@ -75,7 +75,7 @@ GEM
thor (~> 0.14) thor (~> 0.14)
formatador (0.2.5) formatador (0.2.5)
foundation_emails (2.2.0.0) foundation_emails (2.2.0.0)
globalid (0.3.6) globalid (0.3.7)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
guard (2.14.0) guard (2.14.0)
formatador (>= 0.2.4) formatador (>= 0.2.4)
@ -92,7 +92,7 @@ GEM
guard (~> 2.8) guard (~> 2.8)
guard-compat (~> 1.0) guard-compat (~> 1.0)
multi_json (~> 1.8) multi_json (~> 1.8)
guard-minitest (2.4.5) guard-minitest (2.4.6)
guard-compat (~> 1.2) guard-compat (~> 1.2)
minitest (>= 3.0) minitest (>= 3.0)
guard-rubocop (1.2.0) guard-rubocop (1.2.0)
@ -111,7 +111,7 @@ GEM
jbuilder (2.6.0) jbuilder (2.6.0)
activesupport (>= 3.0.0, < 5.1) activesupport (>= 3.0.0, < 5.1)
multi_json (~> 1.2) multi_json (~> 1.2)
jquery-rails (4.1.1) jquery-rails (4.2.1)
rails-dom-testing (>= 1, < 3) rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
@ -135,7 +135,7 @@ GEM
mime-types-data (3.2016.0521) mime-types-data (3.2016.0521)
mini_portile2 (2.1.0) mini_portile2 (2.1.0)
minitest (5.9.0) minitest (5.9.0)
minitest-reporters (1.1.10) minitest-reporters (1.1.11)
ansi ansi
builder builder
minitest (>= 5.0) minitest (>= 5.0)
@ -151,7 +151,7 @@ GEM
nokogiri (1.6.8) nokogiri (1.6.8)
mini_portile2 (~> 2.1.0) mini_portile2 (~> 2.1.0)
pkg-config (~> 1.1.7) pkg-config (~> 1.1.7)
notiffany (0.1.0) notiffany (0.1.1)
nenv (~> 0.1) nenv (~> 0.1)
shellany (~> 0.0) shellany (~> 0.0)
parser (2.3.1.2) parser (2.3.1.2)
@ -179,17 +179,17 @@ GEM
rack rack
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rails (5.0.0) rails (5.0.0.1)
actioncable (= 5.0.0) actioncable (= 5.0.0.1)
actionmailer (= 5.0.0) actionmailer (= 5.0.0.1)
actionpack (= 5.0.0) actionpack (= 5.0.0.1)
actionview (= 5.0.0) actionview (= 5.0.0.1)
activejob (= 5.0.0) activejob (= 5.0.0.1)
activemodel (= 5.0.0) activemodel (= 5.0.0.1)
activerecord (= 5.0.0) activerecord (= 5.0.0.1)
activesupport (= 5.0.0) activesupport (= 5.0.0.1)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 5.0.0) railties (= 5.0.0.1)
sprockets-rails (>= 2.0.0) sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.1) rails-controller-testing (1.0.1)
actionpack (~> 5.x) actionpack (~> 5.x)
@ -198,16 +198,16 @@ GEM
rails-dom-testing (2.0.1) rails-dom-testing (2.0.1)
activesupport (>= 4.2.0, < 6.0) activesupport (>= 4.2.0, < 6.0)
nokogiri (~> 1.6.0) nokogiri (~> 1.6.0)
rails-erd (1.4.7) rails-erd (1.5.0)
activerecord (>= 3.2) activerecord (>= 3.2)
activesupport (>= 3.2) activesupport (>= 3.2)
choice (~> 0.2.0) choice (~> 0.2.0)
ruby-graphviz (~> 1.2) ruby-graphviz (~> 1.2)
rails-html-sanitizer (1.0.3) rails-html-sanitizer (1.0.3)
loofah (~> 2.0) loofah (~> 2.0)
railties (5.0.0) railties (5.0.0.1)
actionpack (= 5.0.0) actionpack (= 5.0.0.1)
activesupport (= 5.0.0) activesupport (= 5.0.0.1)
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
@ -228,7 +228,7 @@ GEM
unicode-display_width (~> 1.0, >= 1.0.1) unicode-display_width (~> 1.0, >= 1.0.1)
ruby-graphviz (1.2.2) ruby-graphviz (1.2.2)
ruby-progressbar (1.8.1) ruby-progressbar (1.8.1)
ruby_dep (1.3.1) ruby_dep (1.4.0)
sass (3.4.22) sass (3.4.22)
sass-rails (5.0.6) sass-rails (5.0.6)
railties (>= 4.0.0, < 6) railties (>= 4.0.0, < 6)
@ -258,12 +258,12 @@ GEM
thor (0.19.1) thor (0.19.1)
thread_safe (0.3.5) thread_safe (0.3.5)
tilt (2.0.5) tilt (2.0.5)
turbolinks (5.0.0) turbolinks (5.0.1)
turbolinks-source (~> 5) turbolinks-source (~> 5)
turbolinks-source (5.0.0) turbolinks-source (5.0.0)
tzinfo (1.2.2) tzinfo (1.2.2)
thread_safe (~> 0.1) thread_safe (~> 0.1)
uglifier (3.0.0) uglifier (3.0.2)
execjs (>= 0.3.0, < 3) execjs (>= 0.3.0, < 3)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
@ -308,7 +308,7 @@ DEPENDENCIES
pry-rails pry-rails
puma (~> 3.0) puma (~> 3.0)
rack-livereload rack-livereload
rails (~> 5.0.0) rails (~> 5.0, >= 5.0.0.1)
rails-controller-testing rails-controller-testing
rails-erd rails-erd
rubocop (~> 0.42.0) rubocop (~> 0.42.0)

View File

@ -15,7 +15,21 @@
# #
# and, you'll have to watch "config/Guardfile" instead of "Guardfile" # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
guard :minitest, spring: true, all_after_pass: true, all_on_start: false do guard 'livereload' do
watch(%r{app/assets/.+\.(scss|css|js|erb)})
watch(%r{app/views/.+\.(erb|haml|slim)$})
watch(%r{app/controllers/.+\.rb})
watch(%r{app/helpers/.+\.rb})
watch(%r{public/.+\.(css|js|html)})
watch(%r{config/locales/.+\.yml})
# Rails Assets Pipeline
watch(%r{(app|vendor)(/assets/\w+/(.+\.(scss|css|js|erb|html|png|jpg))).*}) do |m|
"/assets/#{m[3]}"
end
end
guard :minitest, spring: true, all_after_pass: true do
watch(%r{^test/test_helper\.rb$}) { 'test' } watch(%r{^test/test_helper\.rb$}) { 'test' }
watch(%r{^test/(.*)\/?(.*)_test\.rb$}) watch(%r{^test/(.*)\/?(.*)_test\.rb$})
@ -32,20 +46,6 @@ guard :minitest, spring: true, all_after_pass: true, all_on_start: false do
watch(%r{^app/views/(.*_mailer/)?([^/]+)\.erb$}) { ["test/mailers", "test/integration"] } watch(%r{^app/views/(.*_mailer/)?([^/]+)\.erb$}) { ["test/mailers", "test/integration"] }
end end
guard 'livereload' do
watch(%r{app/assets/.+\.(scss|css|js|erb)})
watch(%r{app/views/.+\.(erb|haml|slim)$})
watch(%r{app/controllers/.+\.rb})
watch(%r{app/helpers/.+\.rb})
watch(%r{public/.+\.(css|js|html)})
watch(%r{config/locales/.+\.yml})
# Rails Assets Pipeline
watch(%r{(app|vendor)(/assets/\w+/(.+\.(scss|css|js|erb|html|png|jpg))).*}) do |m|
"/assets/#{m[3]}"
end
end
guard :rubocop do guard :rubocop do
watch(/.+\.rb$/) watch(/.+\.rb$/)
watch(/Rakefile/) watch(/Rakefile/)

View File

@ -0,0 +1,16 @@
$(function(){
$("form").on('click', "[data-id=input_option_adder]", function(){
var $new_li = $(this).siblings('li').clone();
$new_li.attr('style', '');
$("[data-id=input_option_list]").append($new_li);
$new_li.find('input').focus();
});
$("#question_input_type").on('change', function(){
var qid = $(this).attr('data-qid') === undefined ? '' : "/" + $(this).attr('data-qid');
// /admin/question(/:question_id)/options/:input_type
$("[data-id=input-options-wrapper]").load("/admin/question" + qid + "/options/" + $(this).val());
});
});

View File

@ -21,3 +21,6 @@
//= require summary-edit //= require summary-edit
//= require textarea-limit //= require textarea-limit
//= require live-coder //= require live-coder
//= require admin

View File

@ -0,0 +1,25 @@
module Admin
class AuthController < AdminController
skip_before_action :authorize_admin
def login
end
def auth
admin = User.find_by(email: auth_params[:email], role: 'admin')
if admin && admin.authenticate(auth_params[:password])
session[:user] = admin.to_i
redirect_to admin_path
else
redirect_to admin_login_path,
flash: { error: "Sorry, incorrect email or password. Please try again." }
end
end
def logout
reset_session
redirect_to admin_login_path
end
end
end

View File

@ -0,0 +1,69 @@
module Admin
class QuestionController < AdminController
def index
@questions = Question.includes(:quiz).order("quizzes.name", { active: :desc }, :sort)
end
def new
@question = Question.new(active: true)
@quizzes = Quiz.all
end
def create
@quizzes = Quiz.all
@question = Question.create(process_question_params)
if @question.persisted?
redirect_to admin_questions_path, flash: { notice: "Sucessfully created question" }
else
flash[:error] = "Failed to save question."
render :new
end
end
def view
@question = Question.includes(:quiz).find(params[:question_id])
end
def edit
@quizzes = Quiz.all
@question = Question.includes(:quiz).find(params[:question_id])
end
def update
@quizzes = Quiz.all
@question = Question.find(params[:question_id])
if @question.update_attributes(process_question_params)
redirect_to admin_question_path(@question.to_i),
flash: { notice: "Sucessfully updated question" }
else
flash[:error] = "Failed to update question."
render :edit
end
end
def options
@question = params[:question_id].present? ? Question.find(params[:question_id]) : Question.new
render layout: false
end
private
def question_params
params.require(:question).permit(
:quiz_id, :question, :category, :input_type, :sort, :active, :input_options,
multi_choice: [], live_code: [:later, :html, :css, :js, :text]
)
end
def process_question_params
question = question_params
question[:input_options] = question_params[:multi_choice] unless question_params[:multi_choice].nil?
question[:input_options] = question_params[:live_coder] unless question_params[:live_coder].nil?
question.delete(:multi_choice)
question.delete(:live_coder)
question
end
end
end

View File

@ -0,0 +1,48 @@
module Admin
class QuizController < AdminController
def index
@quizzes = Quiz.all
end
def new
@quiz = Quiz.new
end
def create
@quiz = Quiz.create(quiz_params)
if @quiz.persisted?
redirect_to admin_quizzes_path, flash: { notice: "Sucessfully created quiz" }
else
flash[:error] = "Failed to save quiz."
render :new
end
end
def view
@quiz = Quiz.find(params[:quiz_id])
end
def edit
@quiz = Quiz.find(params[:quiz_id])
end
def update
@quiz = Quiz.find(params[:quiz_id])
if @quiz.update_attributes(quiz_params)
redirect_to admin_quiz_path(@quiz.to_i),
flash: { notice: "Sucessfully updated quiz" }
else
flash[:error] = "Failed to update quiz."
render :edit
end
end
private
def quiz_params
params.require(:quiz).permit(:name, :dept, :unit)
end
end
end

View File

@ -0,0 +1,50 @@
module Admin
class UserController < AdminController
def index
@users = User.order(:name)
end
def new
@user = User.new
end
def create
default_passwd = SecureRandom.urlsafe_base64(12)
@user = User.create({ password: default_passwd }.merge(user_params.to_h))
if @user.persisted?
# TODO: UserMailer.welcome(@user, default_passwd).deliver_now
redirect_to admin_users_path, flash: { notice: "Sucessfully created user #{@user.name}" }
else
flash[:error] = "Failed to save user."
render :new
end
end
def view
@user = User.find(params[:user_id])
end
def edit
@user = User.find(params[:user_id])
end
def update
@user = User.find(params[:user_id])
if @user.update_attributes(user_params)
redirect_to admin_user_path(@user.to_i),
flash: { notice: "Sucessfully updated #{@user.name}" }
else
flash[:error] = "Failed to update user."
render :edit
end
end
private
def user_params
params.require(:user).permit(:name, :email, :role, :password)
end
end
end

View File

@ -0,0 +1,21 @@
class AdminController < ApplicationController
layout 'admin'
before_action :authorize_admin
def dashboard
@quizzes = Quiz.includes(:questions).all
@users = User.order(:role, :name)
end
def current_admin
user_args = { id: session[:user], role: 'admin' }
@current_admin ||= User.find_by(user_args) if session[:user]
end
helper_method :current_admin
private
def authorize_admin
redirect_to admin_login_path unless current_admin
end
end

View File

@ -86,6 +86,7 @@ class QuizController < ApplicationController
end end
end end
# TODO: maybe a better way to do this. See Admin/QuestionController#process_question_params
def process_text def process_text
@answer.update(answer: answer_params[:text], @answer.update(answer: answer_params[:text],
saved: params.key?(:save), saved: params.key?(:save),

View File

@ -9,4 +9,21 @@ module ApplicationHelper
["15+ Years", "15+"] ["15+ Years", "15+"]
], disabled: "-", selected: (val.blank? ? '' : val)) ], disabled: "-", selected: (val.blank? ? '' : val))
end end
def admin_role_options val
options_for_select([
%w(Reviewer reviewer),
%w(Recruiter recruiter),
%w(Admin admin)
], disabled: "-", selected: (val.blank? ? '' : val))
end
def question_type_options val
options_for_select([
%w(Text text),
%w(Radio radio),
%w(Checkbox checkbox),
%w(Coder live_code)
], selected: (val.blank? ? '' : val))
end
end end

View File

@ -3,4 +3,18 @@ class Question < ApplicationRecord
has_many :answers has_many :answers
belongs_to :quiz belongs_to :quiz
before_validation :compact_input_options
validates :quiz_id, presence: true
validates :question, presence: true
validates :category, presence: true
validates :input_type, presence: true
validates :input_options, input_options_presence: true
private
def compact_input_options
self.input_options = input_options.reject(&:blank?)
end
end end

View File

@ -1,4 +1,8 @@
class Quiz < ApplicationRecord class Quiz < ApplicationRecord
has_many :questions, -> { order(:sort) } has_many :questions, -> { order(:sort) }
has_many :candidates has_many :candidates
validates_presence_of :name
validates_presence_of :dept
validates_presence_of :unit
end end

View File

@ -1,4 +1,8 @@
class User < ApplicationRecord class User < ApplicationRecord
has_secure_password has_secure_password
has_many :candidates, foreign_key: "recruiter_id" has_many :candidates, foreign_key: "recruiter_id"
validates_presence_of :email
validates_presence_of :name
validates_presence_of :role
end end

View File

@ -0,0 +1,11 @@
class InputOptionsPresenceValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return true unless record.input_type =~ /radio|check/i
return true if value.present? && value.count > 0
record.errors[attribute] << (options[:message] ||
"You must provide answer options for the selected input type.")
false
end
end

View File

@ -0,0 +1,21 @@
<main class="intro_tpl">
<h1>Admin Login</h1>
<% if flash[:error].present? %>
<div class="error"><%= flash[:error] %></div>
<% end %>
<%= form_for :auth, url: admin_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>

View File

@ -0,0 +1,18 @@
<%
content_for :section_title, "Admin Dashboard"
%>
<main class="admin_tpl">
<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>
</main>

View File

@ -0,0 +1,18 @@
<strong>Checkbox Options</strong>
<ul data-id="input_option_list">
<% question.input_options.each do | option | %>
<li>
<%= text_field_tag 'question[multi_choice][]', option, { disabled: (disable ||= false), data: { last: option } } %>
</li>
<% end %>
</ul>
<% unless (disable ||= false) %>
<div class="form-group">
<div class="btn tertiary-btn" data-id="input_option_adder"> Add option </div>
<li style="display: none;">
<%= text_field_tag 'question[multi_choice][]', nil, { disabled: (disable ||= false), data: { last: nil } } %>
</li>
</div>
<% end %>

View File

@ -0,0 +1,41 @@
<%= render partial: 'shared/form_model_errors', locals: { obj: question} %>
<%= form_for question, url: action do |form| %>
<div class="form-group">
<%= form.label :quiz_id, 'Quiz' %>
<%= form.select :quiz_id, options_for_select(@quizzes.map{ |q| [q.name, q.id] }, question.quiz_id), include_blank: (@quizzes.size > 1) %>
</div>
<div class="form-group">
<%= form.label :category, 'Category' %>
<%= form.text_field :category %>
</div>
<div class="form-group">
<%= form.label :sort, 'Sort' %>
<%= form.text_field :sort %>
</div>
<div class="form-group">
<%= form.check_box :active %>
<%= form.label :active, 'Active' %>
</div>
<div class="form-group">
<%= form.label :question, "Question" %>
<%= form.text_area :question %>
</div>
<div class="form-group">
<%= form.label :input_type, 'Input Type' %>
<%= form.select :input_type, question_type_options(question.input_type), { include_blank: false }, { data: { qid: question.id } } %>
</div>
<div class="form-group" data-id="input-options-wrapper">
<%= fields_for @question do |fields| %>
<% partial = question.input_type.blank? ? 'admin/question/text' : "admin/question/#{question.input_type}" %>
<%= render partial: partial, locals: {question: question, fields: fields } %>
<% end %>
</div>
<%= form.submit %>
<% end %>

View File

@ -0,0 +1,29 @@
<%
return nil
# don't load this partial yet. Will finish in issue #16
# https://gitlab.perficientxd.com/pdr/skill-assessment-app/issues/16
options = { 'text' => '', 'html' => '', 'css' => '', 'js' => '' }
%>
<div data-id="live-coder-answer">
<div class="code-input">
<label for="question_input_options_html">HTML</label>
<%= text_area_tag 'question[live_code][html]', options['html'], { data: {id: 'code-html', last: options['html']}, class: 'code-answer code-html' } %>
</div>
<div class="code-input">
<label for="question_input_options_css">CSS</label>
<%= text_area_tag 'question[live_code][css]', options['css'], { data: {id: 'code-css', last: options['css']}, class: 'code-answer code-css' } %>
</div>
<div class="code-input">
<label for="question_input_options_js">JS</label>
<%= text_area_tag 'question[live_code][js]', options['js'], { data: {id: 'code-js', last: options['js']}, class: 'code-answer code-js' } %>
</div>
<div class="results" data-id="results"></div>
</div>

View File

@ -0,0 +1,18 @@
<strong>Radio Options</strong>
<ul data-id="input_option_list">
<% question.input_options.each do | option | %>
<li>
<%= text_field_tag 'question[multi_choice][]', option, { disabled: (disable ||= false), data: { last: option } } %>
</li>
<% end %>
</ul>
<% unless (disable ||= false) %>
<div class="form-group">
<div class="btn tertiary-btn" data-id="input_option_adder"> Add option </div>
<li style="display: none;">
<%= text_field_tag 'question[multi_choice][]', nil, { disabled: (disable ||= false), data: { last: nil } } %>
</li>
</div>
<% end %>

View File

@ -0,0 +1,21 @@
<table cellspacing="0" cellpadding="0">
<tr>
<th>Sort</th>
<th>Question</th>
<th>Type</th>
<th>Category</th>
<th>Active</th>
<th></th>
</tr>
<% questions.each do |question| %>
<tr>
<td><%= question.sort %></td>
<td><%= question.question %></td>
<td><%= question.input_type %></td>
<td><%= question.category %></td>
<td><%= question.active unless question.active? %></td>
<td><%= link_to 'Edit', admin_edit_question_path(question.to_i), { class: 'btn tertiary-btn' } %></td>
</tr>
<% end %>
</table>

View File

View File

@ -0,0 +1,9 @@
<%
content_for :section_title, "Questions"
%>
<main class="admin_tpl">
<h1><%= @question.quiz.name %></h1>
<%= render partial: 'form', locals: {question: @question, action: admin_update_question_path } %>
</main>

View File

@ -0,0 +1,12 @@
<%
content_for :section_title, "Questions"
%>
<main class="admin_tpl">
<% quizzes = @questions.group_by{ |q| q.quiz.name } %>
<% quizzes.each do |quiz, questions| %>
<h1><%= quiz %></h1>
<%= render partial: 'admin/question/table_list', locals: { questions: questions } %>
<%= link_to('Edit Quiz', admin_quiz_path(questions.first.quiz.to_i), { class: 'btn' }) %>
<% end %>
</main>

View File

@ -0,0 +1,7 @@
<%
content_for :section_title, "New Question"
%>
<main class="admin_tpl">
<%= render partial: 'form', locals: {question: @question, action: admin_create_question_path } %>
</main>

View File

@ -0,0 +1,5 @@
<%
if lookup_context.exists?(params[:input_type], 'admin/question', true)
%><%= render partial: "admin/question/#{params[:input_type]}", locals: { question: @question } %><%
end
%>

View File

@ -0,0 +1,38 @@
<%
content_for :section_title, "Question for #{@question.quiz.name}"
%>
<main class="admin_tpl">
<table cellspacing="0" cellpadding="0">
<tr>
<th>Category</th>
<td><%= @question.category %></td>
</tr>
<tr>
<th>Type</th>
<td><%= @question.input_type %></td>
</tr>
<tr>
<th>Sort</th>
<td><%= @question.sort %></td>
</tr>
<tr>
<th></th>
<td>
<%= check_box_tag 'question_active', nil, @question.active?, {disabled: true} %>
<%= label_tag 'question_active', 'Active' %>
</td>
</tr>
</table>
<strong>Question</strong>
<p><%= @question.question %></p>
<%= fields_for @question do |fields| %>
<%= render partial: "admin/question/#{@question.input_type}", locals: {question: @question, disable: true, fields: fields } %>
<% end %>
<%= link_to('Edit', admin_edit_question_path(@question.to_i), { class: 'btn' }) %>
<%= link_to('View Quiz', admin_quiz_path(@question.quiz_id), { class: 'btn' }) %>
</main>

View File

@ -0,0 +1,19 @@
<%= render partial: 'shared/form_model_errors', locals: { obj: quiz} %>
<%= form_for quiz, url: action do |form| %>
<div class="form-group">
<%= form.label :name, "Quiz Description" %>
<%= form.text_field :name %>
</div>
<div class="form-group">
<%= form.label :dept, 'Department' %>
<%= form.text_field :dept %>
</div>
<div class="form-group">
<%= form.label :unit, 'Unit' %>
<%= form.text_field :unit %>
</div>
<%= form.submit %>
<% end %>

View File

@ -0,0 +1,19 @@
<table cellspacing="0" cellpadding="0">
<tr>
<th>Name</th>
<th>Dept</th>
<th>Unit</th>
<th>Questions</th>
<th></th>
</tr>
<% quizzes.each do |quiz| %>
<tr>
<td><%= link_to quiz.name, admin_quiz_path(quiz.to_i) %></td>
<td><%= quiz.dept %></td>
<td><%= quiz.unit %></td>
<td><%= quiz.questions.count %></td>
<td><%= link_to 'edit', admin_edit_quiz_path(quiz.to_i), { class: 'btn tertiary-btn' } %></td>
</tr>
<% end %>
</table>

View File

@ -0,0 +1,7 @@
<%
content_for :section_title, "Edit: #{@quiz.name}"
%>
<main class="admin_tpl">
<%= render partial: 'form', locals: { quiz: @quiz, action: admin_update_quiz_path } %>
</main>

View File

@ -0,0 +1,8 @@
<%
content_for :section_title, "Quizzes"
%>
<main class="admin_tpl">
<%= render partial: 'admin/quiz/table_list', locals: { quizzes: @quizzes } %>
<%= link_to('New Quiz', admin_new_quiz_path, { class: 'btn' }) %>
</main>

View File

@ -0,0 +1,7 @@
<%
content_for :section_title, "New Quiz"
%>
<main class="admin_tpl">
<%= render partial: 'form', locals: { quiz: @quiz, action: admin_create_quiz_path } %>
</main>

View File

@ -0,0 +1,15 @@
<%
content_for :section_title, "#{@quiz.name}"
%>
<main class="admin_tpl">
<p><%= @quiz.name %></p>
<p><%= @quiz.dept %></p>
<p><%= @quiz.unit %></p>
<%= link_to('Edit', admin_edit_quiz_path(@quiz.to_i), { class: 'btn' }) %>
</main>
<main class="summary_tpl">
<%= render partial: 'admin/question/table_list', locals: { questions: @quiz.questions, disable: true } %>
<%= link_to('New Question', admin_new_question_path, { class: 'btn' }) %>
</main>

View File

@ -0,0 +1,19 @@
<%= render partial: 'shared/form_model_errors', locals: { obj: user} %>
<%= form_for user, url: action do |form| %>
<div class="form-group">
<%= form.label :name, "Full Name" %>
<%= form.text_field :name %>
</div>
<div class="form-group">
<%= form.label :email, "eMail" %>
<%= form.email_field :email %>
</div>
<div class="form-group">
<%= form.label :role, "Role" %>
<%= form.select :role, admin_role_options(user.role), include_blank: false %>
</div>
<%= form.submit %>
<% end %>

View File

@ -0,0 +1,17 @@
<table cellspacing="0" cellpadding="0">
<tr>
<th>User</th>
<th>Email</th>
<th>Role</th>
<th></th>
</tr>
<% users.each do |user| %>
<tr>
<td><%= link_to user.name, admin_user_path(user.to_i) %></td>
<td><%= mail_to(user.email) %></td>
<td><%= user.role %></td>
<td><%= link_to 'edit', admin_edit_user_path(user.to_i), { class: 'btn tertiary-btn' } %></td>
</tr>
<% end %>
</table>

View File

@ -0,0 +1,7 @@
<%
content_for :section_title, "Edit: #{@user.name}"
%>
<main class="admin_tpl">
<%= render partial: 'form', locals: {user: @user, action: admin_update_user_path } %>
</main>

View File

@ -0,0 +1,9 @@
<%
content_for :section_title, "Users"
%>
<main class="admin_tpl">
<h1>Users</h1>
<%= render partial: 'admin/user/table_list', locals: { users: @users } %>
<%= link_to('New User', admin_new_user_path, { class: 'btn' }) %>
</main>

View File

@ -0,0 +1,7 @@
<%
content_for :section_title, "New User"
%>
<main class="admin_tpl">
<%= render partial: 'form', locals: {user: @user, action: admin_create_user_path } %>
</main>

View File

@ -0,0 +1,10 @@
<%
content_for :section_title, "#{@user.name}"
%>
<main class="admin_tpl">
<p><%= @user.name %></p>
<p><%= mail_to(@user.email) %></p>
<p><%= @user.role %></p>
<%= link_to('Edit', admin_edit_user_path(@user.to_i), { class: 'btn' }) %>
</main>

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<%= csrf_meta_tags %>
<title><%= yield(:title) %></title>
<!--[if ! lte IE 8]><!-->
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<!--<![endif]-->
<!--[if lt IE 9]>
<%= javascript_include_tag 'ie9' %>
<![endif]-->
</head>
<body>
<div class="layout">
<header class="no-progressbar">
<div class="page-title slash-left">
<% if content_for?(:section_title) %>
<div><%= yield(:section_title) %></div>
<% else %>
<div>Skills Assessment Admin</div>
<% end %>
</div>
</header>
<%= yield %>
</div>
<footer>
<div class="footer_title">&nbsp;</div>
<div class="pd_logo"><%= image_tag("perficientdigital.png", alt:"Perficient Digital") %></div>
<div class="footer_yellow-bar slantleft slantright">&nbsp;</div>
</footer>
<!--[if ! lte IE 8]><!-->
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<!--<![endif]-->
</body>
</html>

View File

@ -37,7 +37,7 @@
</div> </div>
<div id="answer<%= question.question_id %>" data-id="live-coder-answer" style="display: none;"> <div id="answer<%= question.question_id %>" data-id="live-coder-answer" style="display: none;">
<label for="answer_live_code">Enter answer here</label> <label for="answer_live_code_text">Enter answer here</label>
<%= text_area_tag 'answer[live_code][text]', (answers['text']), { disabled: true, data: {last: answers['text']}} %> <%= text_area_tag 'answer[live_code][text]', (answers['text']), { disabled: true, data: {last: answers['text']}} %>
<div class="code-input"> <div class="code-input">

View File

@ -1,2 +0,0 @@
<h1>Recruiter#create</h1>
<p>Find me in app/views/recruiter/create.html.erb</p>

View File

@ -1,17 +1,7 @@
<main class="intro_tpl"> <main class="intro_tpl">
<h1>New Candidate</h1> <h1>New Candidate</h1>
<% if flash[:error].present? %> <%= render partial: 'shared/form_model_errors', locals: { obj: @candidate } %>
<div class="error">
<%= flash[:error] %>
<p>
<% @candidate.errors.messages.each do |k,v| %>
<%= "#{k.to_s} #{v.join(' and ')}" %><br />
<% end %>
</p>
</div>
<% end %>
<%= form_for @candidate, url: create_candidate_path do |form| %> <%= form_for @candidate, url: create_candidate_path do |form| %>
<div class="form-group"> <div class="form-group">
<%= form.label :name, "Candidate name" %> <%= form.label :name, "Candidate name" %>

View File

@ -0,0 +1,10 @@
<% if flash[:error].present? %>
<div class="error">
<%= flash[:error] %>
<p>
<% obj.errors.messages.each do |k,v| %>
<%= "#{k.to_s} #{v.join(' and ')}" %><br />
<% end %>
</p>
</div>
<% end %>

View File

@ -23,5 +23,11 @@ module SkillAssessmentApp
config.action_mailer.delivery_method = :mailjet config.action_mailer.delivery_method = :mailjet
config.action_mailer.default_url_options = { host: ENV['full_app_url'] } config.action_mailer.default_url_options = { host: ENV['full_app_url'] }
config.generators do |g|
g.assets false
g.helper false
g.routes false
end
end end
end end

View File

@ -1,29 +1,62 @@
Rails.application.routes.draw do Rails.application.routes.draw do
post "/validate", to: "candidate#validate", as: :validate_candidate post "/admin/login", to: "admin/auth#auth", as: :admin_auth
get "/login(/:test_id)", to: "candidate#login", as: :login get "/admin/login", to: "admin/auth#login", as: :admin_login
get "/welcome", to: "candidate#welcome", as: :welcome get "/admin/logout", to: "admin/auth#logout", as: :admin_logout
get "/saved", to: "candidate#saved", as: :saved
get "/thankyou", to: "candidate#thankyou", as: :thankyou
get "/oops", to: "candidate#oops", as: :oops get "/admin", to: "admin#dashboard", as: :admin
post "/question(/:answer_id)", to: "quiz#update_answer", as: :post_answer get "/admin/quizzes", to: "admin/quiz#index", as: :admin_quizzes
get "/question(/:question_id)", to: "quiz#question", as: :question get "/admin/quiz/new", to: "admin/quiz#new", as: :admin_new_quiz
post "/summary", to: "quiz#submit_summary", as: :post_summary post "/admin/quiz/new", to: "admin/quiz#create", as: :admin_create_quiz
get "/summary", to: "quiz#summary", as: :summary get "/admin/quiz/:quiz_id", to: "admin/quiz#view", as: :admin_quiz
get "/admin/quiz/:quiz_id/edit", to: "admin/quiz#edit", as: :admin_edit_quiz
post "/admin/quiz/:quiz_id/edit", to: "admin/quiz#update", as: :admin_update_quiz
patch "/admin/quiz/:quiz_id/edit", to: "admin/quiz#update"
get "/review/logout", to: "review#logout", as: :review_logout get "/admin/users", to: "admin/user#index", as: :admin_users
post "/review/login", to: "review#auth", as: :review_auth get "/admin/user/new", to: "admin/user#new", as: :admin_new_user
get "/review/login", to: "review#login", as: :review_login post "/admin/user/new", to: "admin/user#create", as: :admin_create_user
get "/review", to: "review#index", as: :review get "/admin/user/:user_id", to: "admin/user#view", as: :admin_user
get "/review/:test_hash", to: "review#view", as: :review_test get "/admin/user/:user_id/edit", to: "admin/user#edit", as: :admin_edit_user
post "/admin/user/:user_id/edit", to: "admin/user#update", as: :admin_update_user
patch "/admin/user/:user_id/edit", to: "admin/user#update"
get "/recruiter", to: "recruiter#index", as: :recruiter get "/admin/questions", to: "admin/question#index", as: :admin_questions
get "/recruiter/new-candidate", to: "recruiter#new", as: :new_candidate get "/admin/question/new", to: "admin/question#new", as: :admin_new_question
post "/recruiter/new-candidate", to: "recruiter#create", as: :create_candidate post "/admin/question/new", to: "admin/question#create", as: :admin_create_question
get "/recruiter/logout", to: "recruiter#logout", as: :recruiter_logout get "/admin/question(/:question_id)/options/:input_type", to: "admin/question#options", as: :admin_question_option_form
get "/recruiter/login", to: "recruiter#login", as: :recruiter_login get "/admin/question/:question_id", to: "admin/question#view", as: :admin_question
post "/recruiter/login", to: "recruiter#auth", as: :recruiter_auth get "/admin/question/:question_id/edit", to: "admin/question#edit", as: :admin_edit_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"
#########################################################################################
post "/validate", to: "candidate#validate", as: :validate_candidate
get "/login(/:test_id)", to: "candidate#login", as: :login
get "/welcome", to: "candidate#welcome", as: :welcome
get "/saved", to: "candidate#saved", as: :saved
get "/thankyou", to: "candidate#thankyou", as: :thankyou
get "/oops", to: "candidate#oops", as: :oops
post "/question(/:answer_id)", to: "quiz#update_answer", as: :post_answer
get "/question(/:question_id)", to: "quiz#question", as: :question
post "/summary", to: "quiz#submit_summary", as: :post_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 "/recruiter", to: "recruiter#index", as: :recruiter
get "/recruiter/new-candidate", to: "recruiter#new", as: :new_candidate
post "/recruiter/new-candidate", to: "recruiter#create", as: :create_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
root to: "candidate#login" root to: "candidate#login"

View File

@ -0,0 +1,5 @@
class AddNameToQuiz < ActiveRecord::Migration[5.0]
def change
add_column :quizzes, :name, :string, after: :id
end
end

View File

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160803003932) do ActiveRecord::Schema.define(version: 20160818225721) do
create_table "answers", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t| create_table "answers", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.integer "candidate_id" t.integer "candidate_id"
@ -62,6 +62,7 @@ ActiveRecord::Schema.define(version: 20160803003932) do
t.string "dept" t.string "dept"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.string "name"
end end
create_table "users", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t| create_table "users", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|

View File

@ -0,0 +1,40 @@
require 'test_helper'
module Admin
class AuthControllerTest < ActionDispatch::IntegrationTest
test "should get login" do
get admin_login_url
assert_response :success
assert_template 'admin/auth/login'
end
test "should get logout" do
post admin_auth_url, params: { auth:
{ email: 'alan.admin@mailinator.com', password: 'password' } }
get admin_logout_url
assert_redirected_to admin_login_url
assert session[:user].nil?
end
test "should auth to dashboard" do
post admin_auth_url, params: { auth:
{ email: 'alan.admin@mailinator.com', password: 'password' } }
assert_redirected_to admin_url
end
test "recruiter should not admin auth" do
post admin_auth_url, params: { auth:
{ email: 'pdr.recruiter@mailinator.com', password: 'password' } }
assert_redirected_to admin_login_url
assert_match(/incorrect.*email/, flash[:error])
end
test "reviewer should not admin auth" do
post admin_auth_url, params: { auth:
{ email: 'fed.reviewer@mailinator.com', password: 'password' } }
assert_redirected_to admin_login_url
assert_match(/incorrect.*email/, flash[:error])
end
end
end

View File

@ -0,0 +1,91 @@
require 'test_helper'
module Admin
class QuestionControllerTest < ActionDispatch::IntegrationTest
def setup
post admin_auth_url, params: { auth:
{ email: 'alan.admin@mailinator.com', password: 'password' } }
end
test "should get index" do
get admin_questions_url
assert_response :success
assert assigns :questions
end
test "should get new" do
get admin_new_question_url
assert_response :success
assert assigns :question
end
test "should fail create" do
assert_difference("Question.count", 0) do
post admin_create_question_url, params: { question: { question: 'foo bar baz' } }
end
assert :success
assert_match(/failed/i, session[:flash].values.join)
end
test "should fail to create without quiz id" do
assert_difference("Question.count", 0) do
post admin_create_question_url, params: { question:
{ question: 'foo bar baz', category: 'ops', input_type: 'text' } }
end
assert :success
assert_match(/failed/i, session[:flash].values.join)
end
test "should post create" do
assert_difference("Question.count", 1) do
post admin_create_question_url, params: { question:
{ quiz_id: quizzes(:fed).to_i, question: 'foo bar baz', category: 'ops', input_type: 'text' } }
end
assert_redirected_to admin_questions_url
end
test "should get view" do
get admin_question_url questions(:fed5).to_i
assert_response :success
assert assigns :question
end
test "should get edit" do
get admin_edit_question_url questions(:fed5).to_i
assert_response :success
assert assigns :question
end
test "should post update quiz" do
question = questions(:fed9)
post admin_update_question_url(question.to_i), params: { question:
{ quiz_id: quizzes(:fed).to_i, question: 'foo bar baz', category: 'ops', input_type: 'text' } }
assert_redirected_to admin_question_path(question.to_i)
get admin_question_path question.to_i
assert_select 'p', 'foo bar baz'
end
test "should fail to update question" do
question = questions(:fed9)
post admin_update_question_url(question.to_i), params: { question: { question: nil } }
assert :success
assert_match(/failed/i, session[:flash].values.join)
end
test "should gracefully fail input_type" do
get admin_question_option_form_url(input_type: 'fooBarBaz')
assert :success
assigns :locals
end
test "should return partial for new radio" do
get admin_question_option_form_url(input_type: 'radio')
assert :success
assigns :locals
assert_select "input[id^=question_multi_choice_]"
end
end
end

View File

@ -0,0 +1,68 @@
require 'test_helper'
module Admin
class QuizControllerTest < ActionDispatch::IntegrationTest
def setup
post admin_auth_url, params: { auth:
{ email: 'alan.admin@mailinator.com', password: 'password' } }
end
test "should get index" do
get admin_quizzes_url
assert_response :success
assert assigns :quizzes
end
test "should get new" do
get admin_new_quiz_url
assert_response :success
assert assigns :quiz
end
test "should fail create" do
assert_difference("Quiz.count", 0) do
post admin_create_quiz_url, params: { quiz: { dept: nil } }
end
assert :success
assert_match(/failed/i, session[:flash].values.join)
end
test "should post create" do
assert_difference("Quiz.count", 1) do
post admin_create_quiz_url, params: { quiz:
{ name: 'PDW Mobile team screening', unit: 'PDW', dept: 'MBL' } }
end
assert_redirected_to admin_quizzes_url
end
test "should get view" do
quiz = quizzes :fed
get admin_quiz_url quiz.to_i
assert_response :success
assert_select 'p', quiz.dept
end
test "should get edit" do
quiz = quizzes :fed
get admin_edit_quiz_url quiz.to_i
assert_response :success
assert_select "[value=?]", quiz.dept
end
test "should post update quiz" do
quiz = quizzes(:fed)
post admin_update_quiz_url(quiz.to_i), params: { quiz: { dept: 'new', unit: 'another' } }
assert_redirected_to admin_quiz_path(quiz.to_i)
get admin_quiz_path quiz.to_i
assert_select 'p', 'another'
end
test "should fail to update quiz" do
quiz = quizzes(:fed)
post admin_update_quiz_url(quiz.to_i), params: { quiz: { dept: nil } }
assert :success
assert_match(/failed/i, session[:flash].values.join)
end
end
end

View File

@ -0,0 +1,68 @@
require 'test_helper'
module Admin
class UserControllerTest < ActionDispatch::IntegrationTest
def setup
post admin_auth_url, params: { auth:
{ email: 'alan.admin@mailinator.com', password: 'password' } }
end
test "should get index" do
get admin_users_url
assert_response :success
assert assigns :users
end
test "should get new" do
get admin_new_user_url
assert_response :success
assert assigns :user
end
test "should fail create" do
assert_difference("User.count", 0) do
post admin_create_user_url, params: { user: { name: 'New User' } }
end
assert :success
assert_match(/failed/i, session[:flash].values.join)
end
test "should post create" do
assert_difference("User.count", 1) do
post admin_create_user_url, params: { user:
{ email: 'new.user@mailinator.com', name: 'New User', role: 'reviewer' } }
end
assert_redirected_to admin_users_url
end
test "should get view" do
user = users(:recruiter)
get admin_user_url user.to_i
assert_response :success
assert_select 'p', user.name
end
test "should get edit" do
user = users(:recruiter)
get admin_edit_user_url user.to_i
assert_response :success
assert_select "[value=?]", user.name
end
test "should post update user" do
user = users(:recruiter)
post admin_update_user_url(user.to_i), params: { user: { name: 'new name' } }
assert_redirected_to admin_user_path(user.to_i)
get admin_user_url user.to_i
assert_select 'p', 'new name'
end
test "should fail to update user" do
user = users(:recruiter)
post admin_update_user_url(user.to_i), params: { user: { name: nil } }
assert :success
assert_match(/failed/i, session[:flash].values.join)
end
end
end

View File

@ -0,0 +1,15 @@
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

View File

@ -1,5 +1,6 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
fed: fed:
name: PDR Standard FED Screening
unit: PDR unit: PDR
dept: FED dept: FED

View File

@ -1,7 +1,14 @@
require 'test_helper' require 'test_helper'
class QuestionTest < ActiveSupport::TestCase class QuestionTest < ActiveSupport::TestCase
# test "the truth" do test 'should compact arrays for input_options' do
# assert true question = Question.new(quiz_id: quizzes(:fed).to_i,
# end question: 'foo',
category: 'bar',
input_type: 'radio',
input_options: ['one', 'two', '', ' ', nil])
question.validate
assert_equal 2, question.input_options.count
end
end end

View File

@ -0,0 +1,5 @@
class EmailValidatable
include ActiveModel::Validations
attr_accessor :email
validates :email, email_format: true
end

View File

@ -0,0 +1,6 @@
class InputOptionsValidatable
include ActiveModel::Validations
attr_accessor :input_type
attr_accessor :input_options
validates :input_options, input_options_presence: true
end

View File

@ -1,11 +1,5 @@
require 'test_helper' require 'test_helper'
class EmailValidatable
include ActiveModel::Validations
attr_accessor :email
validates :email, email_format: true
end
class EmailFormatValidatorTest < ActiveSupport::TestCase class EmailFormatValidatorTest < ActiveSupport::TestCase
test "tld length" do test "tld length" do
obj = EmailValidatable.new obj = EmailValidatable.new

View File

@ -0,0 +1,49 @@
require 'test_helper'
class InputOptionsPresenceValidatorTest < ActiveSupport::TestCase
test "should pass when inpute type not radio or checkbox" do
obj = InputOptionsValidatable.new
obj.input_type = "text"
assert obj.valid?
assert_equal 0, obj.errors.messages[:input_options].count
end
test "should fail when missing options for radio" do
obj = InputOptionsValidatable.new
obj.input_type = "radio"
obj.input_options = nil
obj.valid?
refute obj.errors.messages.empty?, 'needs an error message'
assert_match(/provide.*option/i, obj.errors.messages[:input_options].join)
end
test "should pass when provided options for radio" do
obj = InputOptionsValidatable.new
obj.input_type = "radio"
obj.input_options = ['one', 'two', nil]
assert obj.valid?
assert_equal 0, obj.errors.messages[:input_options].count
end
test "should fail when missing options for checkbox" do
obj = InputOptionsValidatable.new
obj.input_type = "checkbox"
obj.input_options = nil
obj.valid?
refute obj.errors.messages.empty?, 'needs an error message'
assert_match(/provide.*option/i, obj.errors.messages[:input_options].join)
end
test "should pass when provided options for checkbox" do
obj = InputOptionsValidatable.new
obj.input_type = "checkbox"
obj.input_options = ['one', 'two', nil]
assert obj.valid?
assert_equal 0, obj.errors.messages[:input_options].count
end
end