diff --git a/Gemfile b/Gemfile index 667035c..8c9a143 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' gem 'figaro', '~> 1.1.1' gem 'bcrypt', '~> 3.1.7' 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 'jquery-rails' diff --git a/Gemfile.lock b/Gemfile.lock index 31a7bcb..c9cce22 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,46 +1,46 @@ GEM remote: https://rubygems.org/ specs: - actioncable (5.0.0) - actionpack (= 5.0.0) + actioncable (5.0.0.1) + actionpack (= 5.0.0.1) nio4r (~> 1.2) websocket-driver (~> 0.6.1) - actionmailer (5.0.0) - actionpack (= 5.0.0) - actionview (= 5.0.0) - activejob (= 5.0.0) + actionmailer (5.0.0.1) + actionpack (= 5.0.0.1) + actionview (= 5.0.0.1) + activejob (= 5.0.0.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.0.0) - actionview (= 5.0.0) - activesupport (= 5.0.0) + actionpack (5.0.0.1) + actionview (= 5.0.0.1) + activesupport (= 5.0.0.1) rack (~> 2.0) rack-test (~> 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.0.0) - activesupport (= 5.0.0) + actionview (5.0.0.1) + activesupport (= 5.0.0.1) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (5.0.0) - activesupport (= 5.0.0) + activejob (5.0.0.1) + activesupport (= 5.0.0.1) globalid (>= 0.3.6) - activemodel (5.0.0) - activesupport (= 5.0.0) - activerecord (5.0.0) - activemodel (= 5.0.0) - activesupport (= 5.0.0) + activemodel (5.0.0.1) + activesupport (= 5.0.0.1) + activerecord (5.0.0.1) + activemodel (= 5.0.0.1) + activesupport (= 5.0.0.1) arel (~> 7.0) - activesupport (5.0.0) + activesupport (5.0.0.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (~> 0.7) minitest (~> 5.1) tzinfo (~> 1.1) addressable (2.4.0) ansi (1.5.0) - arel (7.1.0) + arel (7.1.1) ast (2.3.0) awesome_print (1.7.0) bcrypt (3.1.11) @@ -75,7 +75,7 @@ GEM thor (~> 0.14) formatador (0.2.5) foundation_emails (2.2.0.0) - globalid (0.3.6) + globalid (0.3.7) activesupport (>= 4.1.0) guard (2.14.0) formatador (>= 0.2.4) @@ -92,7 +92,7 @@ GEM guard (~> 2.8) guard-compat (~> 1.0) multi_json (~> 1.8) - guard-minitest (2.4.5) + guard-minitest (2.4.6) guard-compat (~> 1.2) minitest (>= 3.0) guard-rubocop (1.2.0) @@ -111,7 +111,7 @@ GEM jbuilder (2.6.0) activesupport (>= 3.0.0, < 5.1) multi_json (~> 1.2) - jquery-rails (4.1.1) + jquery-rails (4.2.1) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) @@ -135,7 +135,7 @@ GEM mime-types-data (3.2016.0521) mini_portile2 (2.1.0) minitest (5.9.0) - minitest-reporters (1.1.10) + minitest-reporters (1.1.11) ansi builder minitest (>= 5.0) @@ -151,7 +151,7 @@ GEM nokogiri (1.6.8) mini_portile2 (~> 2.1.0) pkg-config (~> 1.1.7) - notiffany (0.1.0) + notiffany (0.1.1) nenv (~> 0.1) shellany (~> 0.0) parser (2.3.1.2) @@ -179,17 +179,17 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rails (5.0.0) - actioncable (= 5.0.0) - actionmailer (= 5.0.0) - actionpack (= 5.0.0) - actionview (= 5.0.0) - activejob (= 5.0.0) - activemodel (= 5.0.0) - activerecord (= 5.0.0) - activesupport (= 5.0.0) + rails (5.0.0.1) + actioncable (= 5.0.0.1) + actionmailer (= 5.0.0.1) + actionpack (= 5.0.0.1) + actionview (= 5.0.0.1) + activejob (= 5.0.0.1) + activemodel (= 5.0.0.1) + activerecord (= 5.0.0.1) + activesupport (= 5.0.0.1) bundler (>= 1.3.0, < 2.0) - railties (= 5.0.0) + railties (= 5.0.0.1) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.1) actionpack (~> 5.x) @@ -198,16 +198,16 @@ GEM rails-dom-testing (2.0.1) activesupport (>= 4.2.0, < 6.0) nokogiri (~> 1.6.0) - rails-erd (1.4.7) + rails-erd (1.5.0) activerecord (>= 3.2) activesupport (>= 3.2) choice (~> 0.2.0) ruby-graphviz (~> 1.2) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (5.0.0) - actionpack (= 5.0.0) - activesupport (= 5.0.0) + railties (5.0.0.1) + actionpack (= 5.0.0.1) + activesupport (= 5.0.0.1) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) @@ -228,7 +228,7 @@ GEM unicode-display_width (~> 1.0, >= 1.0.1) ruby-graphviz (1.2.2) ruby-progressbar (1.8.1) - ruby_dep (1.3.1) + ruby_dep (1.4.0) sass (3.4.22) sass-rails (5.0.6) railties (>= 4.0.0, < 6) @@ -258,12 +258,12 @@ GEM thor (0.19.1) thread_safe (0.3.5) tilt (2.0.5) - turbolinks (5.0.0) + turbolinks (5.0.1) turbolinks-source (~> 5) turbolinks-source (5.0.0) tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (3.0.0) + uglifier (3.0.2) execjs (>= 0.3.0, < 3) unf (0.1.4) unf_ext @@ -308,7 +308,7 @@ DEPENDENCIES pry-rails puma (~> 3.0) rack-livereload - rails (~> 5.0.0) + rails (~> 5.0, >= 5.0.0.1) rails-controller-testing rails-erd rubocop (~> 0.42.0) diff --git a/Guardfile b/Guardfile index e686215..0b31b2e 100644 --- a/Guardfile +++ b/Guardfile @@ -15,7 +15,21 @@ # # 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\.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"] } 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 watch(/.+\.rb$/) watch(/Rakefile/) diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js new file mode 100644 index 0000000..7633280 --- /dev/null +++ b/app/assets/javascripts/admin.js @@ -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()); + }); + +}); diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e716f6f..3cfbc1b 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -21,3 +21,6 @@ //= require summary-edit //= require textarea-limit //= require live-coder + + +//= require admin diff --git a/app/controllers/admin/auth_controller.rb b/app/controllers/admin/auth_controller.rb new file mode 100644 index 0000000..a6db502 --- /dev/null +++ b/app/controllers/admin/auth_controller.rb @@ -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 diff --git a/app/controllers/admin/question_controller.rb b/app/controllers/admin/question_controller.rb new file mode 100644 index 0000000..c066353 --- /dev/null +++ b/app/controllers/admin/question_controller.rb @@ -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 diff --git a/app/controllers/admin/quiz_controller.rb b/app/controllers/admin/quiz_controller.rb new file mode 100644 index 0000000..82c2de4 --- /dev/null +++ b/app/controllers/admin/quiz_controller.rb @@ -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 diff --git a/app/controllers/admin/user_controller.rb b/app/controllers/admin/user_controller.rb new file mode 100644 index 0000000..23c11dd --- /dev/null +++ b/app/controllers/admin/user_controller.rb @@ -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 diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb new file mode 100644 index 0000000..37a79b4 --- /dev/null +++ b/app/controllers/admin_controller.rb @@ -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 diff --git a/app/controllers/quiz_controller.rb b/app/controllers/quiz_controller.rb index d604fed..016bd76 100644 --- a/app/controllers/quiz_controller.rb +++ b/app/controllers/quiz_controller.rb @@ -86,6 +86,7 @@ class QuizController < ApplicationController end end + # TODO: maybe a better way to do this. See Admin/QuestionController#process_question_params def process_text @answer.update(answer: answer_params[:text], saved: params.key?(:save), diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index feaaee8..876a05c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -9,4 +9,21 @@ module ApplicationHelper ["15+ Years", "15+"] ], disabled: "-", selected: (val.blank? ? '' : val)) 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 diff --git a/app/models/question.rb b/app/models/question.rb index 3abd437..cdcdb3e 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -3,4 +3,18 @@ class Question < ApplicationRecord has_many :answers 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 diff --git a/app/models/quiz.rb b/app/models/quiz.rb index b92a063..bf967e4 100644 --- a/app/models/quiz.rb +++ b/app/models/quiz.rb @@ -1,4 +1,8 @@ class Quiz < ApplicationRecord has_many :questions, -> { order(:sort) } has_many :candidates + + validates_presence_of :name + validates_presence_of :dept + validates_presence_of :unit end diff --git a/app/models/user.rb b/app/models/user.rb index e1b1ee7..1da0679 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,4 +1,8 @@ class User < ApplicationRecord has_secure_password has_many :candidates, foreign_key: "recruiter_id" + + validates_presence_of :email + validates_presence_of :name + validates_presence_of :role end diff --git a/app/validators/input_options_presence_validator.rb b/app/validators/input_options_presence_validator.rb new file mode 100644 index 0000000..0bb6284 --- /dev/null +++ b/app/validators/input_options_presence_validator.rb @@ -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 diff --git a/app/views/admin/auth/login.html.erb b/app/views/admin/auth/login.html.erb new file mode 100644 index 0000000..b54def1 --- /dev/null +++ b/app/views/admin/auth/login.html.erb @@ -0,0 +1,21 @@ +
+

Admin Login

+ + <% if flash[:error].present? %> +
<%= flash[:error] %>
+ <% end %> + + <%= form_for :auth, url: admin_login_path do |form| %> +
+ <%= form.label :email %> + <%= form.email_field :email %> +
+ +
+ <%= form.label :password %> + <%= form.password_field :password %> +
+ + <%= submit_tag "Log in" %> + <% end %> +
diff --git a/app/views/admin/dashboard.html.erb b/app/views/admin/dashboard.html.erb new file mode 100644 index 0000000..c19052d --- /dev/null +++ b/app/views/admin/dashboard.html.erb @@ -0,0 +1,18 @@ +<% + content_for :section_title, "Admin Dashboard" +%> + +
+
+

Quizzes

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

Users

+ <%= render partial: 'admin/user/table_list', locals: { users: @users } %> + <%= link_to('New User', admin_new_user_path, { class: 'btn' }) %> +
+ +
diff --git a/app/views/admin/question/_checkbox.html.erb b/app/views/admin/question/_checkbox.html.erb new file mode 100644 index 0000000..2bba6bb --- /dev/null +++ b/app/views/admin/question/_checkbox.html.erb @@ -0,0 +1,18 @@ +Checkbox Options + + + +<% unless (disable ||= false) %> +
+
Add option
+
  • + <%= text_field_tag 'question[multi_choice][]', nil, { disabled: (disable ||= false), data: { last: nil } } %> +
  • +
    +<% end %> diff --git a/app/views/admin/question/_form.html.erb b/app/views/admin/question/_form.html.erb new file mode 100644 index 0000000..20a6cdf --- /dev/null +++ b/app/views/admin/question/_form.html.erb @@ -0,0 +1,41 @@ +<%= render partial: 'shared/form_model_errors', locals: { obj: question} %> +<%= form_for question, url: action do |form| %> +
    + <%= 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) %> +
    + +
    + <%= form.label :category, 'Category' %> + <%= form.text_field :category %> +
    + +
    + <%= form.label :sort, 'Sort' %> + <%= form.text_field :sort %> +
    + +
    + <%= form.check_box :active %> + <%= form.label :active, 'Active' %> +
    + +
    + <%= form.label :question, "Question" %> + <%= form.text_area :question %> +
    + +
    + <%= form.label :input_type, 'Input Type' %> + <%= form.select :input_type, question_type_options(question.input_type), { include_blank: false }, { data: { qid: question.id } } %> +
    + +
    + <%= 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 %> +
    + + <%= form.submit %> +<% end %> diff --git a/app/views/admin/question/_live_code.html.erb b/app/views/admin/question/_live_code.html.erb new file mode 100644 index 0000000..04af9e6 --- /dev/null +++ b/app/views/admin/question/_live_code.html.erb @@ -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' => '' } +%> + + +
    +
    + + <%= text_area_tag 'question[live_code][html]', options['html'], { data: {id: 'code-html', last: options['html']}, class: 'code-answer code-html' } %> +
    + +
    + + <%= text_area_tag 'question[live_code][css]', options['css'], { data: {id: 'code-css', last: options['css']}, class: 'code-answer code-css' } %> +
    + +
    + + <%= text_area_tag 'question[live_code][js]', options['js'], { data: {id: 'code-js', last: options['js']}, class: 'code-answer code-js' } %> +
    + +
    +
    + diff --git a/app/views/admin/question/_radio.html.erb b/app/views/admin/question/_radio.html.erb new file mode 100644 index 0000000..b918fc7 --- /dev/null +++ b/app/views/admin/question/_radio.html.erb @@ -0,0 +1,18 @@ +Radio Options + + + +<% unless (disable ||= false) %> +
    +
    Add option
    +
  • + <%= text_field_tag 'question[multi_choice][]', nil, { disabled: (disable ||= false), data: { last: nil } } %> +
  • +
    +<% end %> diff --git a/app/views/admin/question/_table_list.html.erb b/app/views/admin/question/_table_list.html.erb new file mode 100644 index 0000000..1ce0359 --- /dev/null +++ b/app/views/admin/question/_table_list.html.erb @@ -0,0 +1,21 @@ + + + + + + + + + + + <% questions.each do |question| %> + + + + + + + + + <% end %> +
    SortQuestionTypeCategoryActive
    <%= question.sort %><%= question.question %><%= question.input_type %><%= question.category %><%= question.active unless question.active? %><%= link_to 'Edit', admin_edit_question_path(question.to_i), { class: 'btn tertiary-btn' } %>
    diff --git a/app/views/admin/question/_text.html.erb b/app/views/admin/question/_text.html.erb new file mode 100644 index 0000000..e69de29 diff --git a/app/views/admin/question/edit.html.erb b/app/views/admin/question/edit.html.erb new file mode 100644 index 0000000..baea6e8 --- /dev/null +++ b/app/views/admin/question/edit.html.erb @@ -0,0 +1,9 @@ +<% + content_for :section_title, "Questions" +%> + +
    +

    <%= @question.quiz.name %>

    + + <%= render partial: 'form', locals: {question: @question, action: admin_update_question_path } %> +
    diff --git a/app/views/admin/question/index.html.erb b/app/views/admin/question/index.html.erb new file mode 100644 index 0000000..8ec115b --- /dev/null +++ b/app/views/admin/question/index.html.erb @@ -0,0 +1,12 @@ +<% + content_for :section_title, "Questions" +%> + +
    + <% quizzes = @questions.group_by{ |q| q.quiz.name } %> + <% quizzes.each do |quiz, questions| %> +

    <%= quiz %>

    + <%= render partial: 'admin/question/table_list', locals: { questions: questions } %> + <%= link_to('Edit Quiz', admin_quiz_path(questions.first.quiz.to_i), { class: 'btn' }) %> + <% end %> +
    diff --git a/app/views/admin/question/new.html.erb b/app/views/admin/question/new.html.erb new file mode 100644 index 0000000..8bc7a68 --- /dev/null +++ b/app/views/admin/question/new.html.erb @@ -0,0 +1,7 @@ +<% + content_for :section_title, "New Question" +%> + +
    + <%= render partial: 'form', locals: {question: @question, action: admin_create_question_path } %> +
    diff --git a/app/views/admin/question/options.html.erb b/app/views/admin/question/options.html.erb new file mode 100644 index 0000000..352995a --- /dev/null +++ b/app/views/admin/question/options.html.erb @@ -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 +%> diff --git a/app/views/admin/question/view.html.erb b/app/views/admin/question/view.html.erb new file mode 100644 index 0000000..24bba3e --- /dev/null +++ b/app/views/admin/question/view.html.erb @@ -0,0 +1,38 @@ +<% + content_for :section_title, "Question for #{@question.quiz.name}" +%> + +
    + + + + + + + + + + + + + + + + + +
    Category<%= @question.category %>
    Type<%= @question.input_type %>
    Sort<%= @question.sort %>
    + <%= check_box_tag 'question_active', nil, @question.active?, {disabled: true} %> + <%= label_tag 'question_active', 'Active' %> +
    + + Question +

    <%= @question.question %>

    + + <%= 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' }) %> +
    diff --git a/app/views/admin/quiz/_form.html.erb b/app/views/admin/quiz/_form.html.erb new file mode 100644 index 0000000..5815161 --- /dev/null +++ b/app/views/admin/quiz/_form.html.erb @@ -0,0 +1,19 @@ +<%= render partial: 'shared/form_model_errors', locals: { obj: quiz} %> +<%= form_for quiz, url: action do |form| %> +
    + <%= form.label :name, "Quiz Description" %> + <%= form.text_field :name %> +
    + +
    + <%= form.label :dept, 'Department' %> + <%= form.text_field :dept %> +
    + +
    + <%= form.label :unit, 'Unit' %> + <%= form.text_field :unit %> +
    + + <%= form.submit %> +<% end %> diff --git a/app/views/admin/quiz/_table_list.html.erb b/app/views/admin/quiz/_table_list.html.erb new file mode 100644 index 0000000..98fbd79 --- /dev/null +++ b/app/views/admin/quiz/_table_list.html.erb @@ -0,0 +1,19 @@ + + + + + + + + + + <% quizzes.each do |quiz| %> + + + + + + + + <% end %> +
    NameDeptUnitQuestions
    <%= link_to quiz.name, admin_quiz_path(quiz.to_i) %><%= quiz.dept %><%= quiz.unit %><%= quiz.questions.count %><%= link_to 'edit', admin_edit_quiz_path(quiz.to_i), { class: 'btn tertiary-btn' } %>
    diff --git a/app/views/admin/quiz/edit.html.erb b/app/views/admin/quiz/edit.html.erb new file mode 100644 index 0000000..a67e234 --- /dev/null +++ b/app/views/admin/quiz/edit.html.erb @@ -0,0 +1,7 @@ +<% + content_for :section_title, "Edit: #{@quiz.name}" +%> + +
    + <%= render partial: 'form', locals: { quiz: @quiz, action: admin_update_quiz_path } %> +
    diff --git a/app/views/admin/quiz/index.html.erb b/app/views/admin/quiz/index.html.erb new file mode 100644 index 0000000..70b8cf2 --- /dev/null +++ b/app/views/admin/quiz/index.html.erb @@ -0,0 +1,8 @@ +<% + content_for :section_title, "Quizzes" +%> + +
    + <%= render partial: 'admin/quiz/table_list', locals: { quizzes: @quizzes } %> + <%= link_to('New Quiz', admin_new_quiz_path, { class: 'btn' }) %> +
    diff --git a/app/views/admin/quiz/new.html.erb b/app/views/admin/quiz/new.html.erb new file mode 100644 index 0000000..2d0dd11 --- /dev/null +++ b/app/views/admin/quiz/new.html.erb @@ -0,0 +1,7 @@ +<% + content_for :section_title, "New Quiz" +%> + +
    + <%= render partial: 'form', locals: { quiz: @quiz, action: admin_create_quiz_path } %> +
    diff --git a/app/views/admin/quiz/view.html.erb b/app/views/admin/quiz/view.html.erb new file mode 100644 index 0000000..21eb321 --- /dev/null +++ b/app/views/admin/quiz/view.html.erb @@ -0,0 +1,15 @@ +<% + content_for :section_title, "#{@quiz.name}" +%> + +
    +

    <%= @quiz.name %>

    +

    <%= @quiz.dept %>

    +

    <%= @quiz.unit %>

    + <%= link_to('Edit', admin_edit_quiz_path(@quiz.to_i), { class: 'btn' }) %> +
    + +
    + <%= render partial: 'admin/question/table_list', locals: { questions: @quiz.questions, disable: true } %> + <%= link_to('New Question', admin_new_question_path, { class: 'btn' }) %> +
    diff --git a/app/views/admin/user/_form.html.erb b/app/views/admin/user/_form.html.erb new file mode 100644 index 0000000..7b254c0 --- /dev/null +++ b/app/views/admin/user/_form.html.erb @@ -0,0 +1,19 @@ +<%= render partial: 'shared/form_model_errors', locals: { obj: user} %> +<%= form_for user, url: action do |form| %> +
    + <%= form.label :name, "Full Name" %> + <%= form.text_field :name %> +
    + +
    + <%= form.label :email, "eMail" %> + <%= form.email_field :email %> +
    + +
    + <%= form.label :role, "Role" %> + <%= form.select :role, admin_role_options(user.role), include_blank: false %> +
    + + <%= form.submit %> +<% end %> diff --git a/app/views/admin/user/_table_list.html.erb b/app/views/admin/user/_table_list.html.erb new file mode 100644 index 0000000..bcce061 --- /dev/null +++ b/app/views/admin/user/_table_list.html.erb @@ -0,0 +1,17 @@ + + + + + + + + + <% users.each do |user| %> + + + + + + + <% end %> +
    UserEmailRole
    <%= link_to user.name, admin_user_path(user.to_i) %><%= mail_to(user.email) %><%= user.role %><%= link_to 'edit', admin_edit_user_path(user.to_i), { class: 'btn tertiary-btn' } %>
    diff --git a/app/views/admin/user/edit.html.erb b/app/views/admin/user/edit.html.erb new file mode 100644 index 0000000..0ccc724 --- /dev/null +++ b/app/views/admin/user/edit.html.erb @@ -0,0 +1,7 @@ +<% + content_for :section_title, "Edit: #{@user.name}" +%> + +
    + <%= render partial: 'form', locals: {user: @user, action: admin_update_user_path } %> +
    diff --git a/app/views/admin/user/index.html.erb b/app/views/admin/user/index.html.erb new file mode 100644 index 0000000..3092e28 --- /dev/null +++ b/app/views/admin/user/index.html.erb @@ -0,0 +1,9 @@ +<% + content_for :section_title, "Users" +%> + +
    +

    Users

    + <%= render partial: 'admin/user/table_list', locals: { users: @users } %> + <%= link_to('New User', admin_new_user_path, { class: 'btn' }) %> +
    diff --git a/app/views/admin/user/new.html.erb b/app/views/admin/user/new.html.erb new file mode 100644 index 0000000..dc70d47 --- /dev/null +++ b/app/views/admin/user/new.html.erb @@ -0,0 +1,7 @@ +<% + content_for :section_title, "New User" +%> + +
    + <%= render partial: 'form', locals: {user: @user, action: admin_create_user_path } %> +
    diff --git a/app/views/admin/user/view.html.erb b/app/views/admin/user/view.html.erb new file mode 100644 index 0000000..caf2c25 --- /dev/null +++ b/app/views/admin/user/view.html.erb @@ -0,0 +1,10 @@ +<% + content_for :section_title, "#{@user.name}" +%> + +
    +

    <%= @user.name %>

    +

    <%= mail_to(@user.email) %>

    +

    <%= @user.role %>

    + <%= link_to('Edit', admin_edit_user_path(@user.to_i), { class: 'btn' }) %> +
    diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb new file mode 100644 index 0000000..0beec5b --- /dev/null +++ b/app/views/layouts/admin.html.erb @@ -0,0 +1,47 @@ + + + + + + <%= csrf_meta_tags %> + + <%= yield(:title) %> + + + <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> + + + + + + + +
    + +
    +
    + <% if content_for?(:section_title) %> +
    <%= yield(:section_title) %>
    + <% else %> +
    Skills Assessment Admin
    + <% end %> +
    +
    + + <%= yield %> + +
    + + + + + <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> + + + diff --git a/app/views/quiz/_live_code.html.erb b/app/views/quiz/_live_code.html.erb index 5e76e3a..9a3a344 100644 --- a/app/views/quiz/_live_code.html.erb +++ b/app/views/quiz/_live_code.html.erb @@ -37,7 +37,7 @@