diff --git a/app/controllers/admin/track_types_controller.rb b/app/controllers/admin/track_types_controller.rb new file mode 100644 index 00000000..5a61e70d --- /dev/null +++ b/app/controllers/admin/track_types_controller.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Admin + class TrackTypesController < Admin::BaseController + load_and_authorize_resource :conference, find_by: :short_title + load_and_authorize_resource :program, through: :conference, singleton: true + load_and_authorize_resource :track_type, through: :program + + def index; end + + def edit; end + + def new + @track_type = @conference.program.track_types.new + end + + def create + @track_type = @conference.program.track_types.new(track_type_params) + if @track_type.save + redirect_to admin_conference_program_track_types_path(conference_id: @conference), + notice: 'Track type successfully created.' + else + flash.now[:error] = "Creating track type failed: #{@track_type.errors.full_messages.join('. ')}." + render :new + end + end + + def update + if @track_type.update_attributes(track_type_params) + redirect_to admin_conference_program_track_types_path(conference_id: @conference), + notice: 'Track type successfully updated.' + else + flash.now[:error] = "Update track type failed: #{@track_type.errors.full_messages.join('. ')}." + render :edit + end + end + + def destroy + if @track_type.destroy + redirect_to admin_conference_program_track_types_path(conference_id: @conference), + notice: 'Track type successfully deleted.' + else + redirect_to admin_conference_program_track_types_path(conference_id: @conference), + error: 'Destroying track type failed! '\ + "#{@track_type.errors.full_messages.join('. ')}." + end + end + + private + + def track_type_params + params.require(:track_type).permit(:title, :description) + end + end +end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 19d6c4d3..dfdfcdf1 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -102,6 +102,7 @@ class AdminAbility signed_in_with_organizer_role(user, conf_ids_for_organization_admin) end + # rubocop:disable Metrics/AbcSize def signed_in_with_organizer_role(user, conf_ids_for_organization_admin = []) # ids of all the conferences for which the user has the 'organizer' role and # conferences that belong to organizations for which user is 'organization_admin' @@ -131,6 +132,7 @@ class AdminAbility can :manage, Cfp, program: { conference_id: conf_ids } can :manage, Event, program: { conference_id: conf_ids } can :manage, EventType, program: { conference_id: conf_ids } + can :manage, TrackType, program: { conference_id: conf_ids } can :manage, Track, program: { conference_id: conf_ids } can :manage, DifficultyLevel, program: { conference_id: conf_ids } can :manage, Commercial, commercialable_type: 'Event', @@ -163,6 +165,7 @@ class AdminAbility can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'User' can [:index, :revert_object, :revert_attribute], PaperTrail::Version, conference_id: conf_ids end + # rubocop:enable Metrics/AbcSize def signed_in_with_cfp_role(user) # ids of all the conferences for which the user has the 'cfp' role @@ -175,6 +178,7 @@ class AdminAbility can :manage, Booth, conference_id: conf_ids_for_cfp can :manage, Event, program: { conference_id: conf_ids_for_cfp } can :manage, EventType, program: { conference_id: conf_ids_for_cfp } + can :manage, TrackType, program: { conference_id: conf_ids_for_cfp } can :manage, Track, program: { conference_id: conf_ids_for_cfp } can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_cfp } can :manage, EmailSettings, conference_id: conf_ids_for_cfp @@ -201,7 +205,7 @@ class AdminAbility end can [:index, :revert_object, :revert_attribute], PaperTrail::Version, - item_type: %w[Event EventType Track DifficultyLevel EmailSettings Room Cfp Program Comment], conference_id: conf_ids_for_cfp + item_type: %w[Event EventType Track TrackType DifficultyLevel EmailSettings Room Cfp Program Comment], conference_id: conf_ids_for_cfp can [:index, :revert_object, :revert_attribute], PaperTrail::Version, ["item_type = 'Commercial' AND conference_id IN (?) AND (object LIKE '%Event%' OR object_changes LIKE '%Event%')", conf_ids_for_cfp] do |version| version.item_type == 'Commercial' && conf_ids_for_cfp.include?(version.conference_id) && diff --git a/app/models/conference.rb b/app/models/conference.rb index be3c36ad..e280c4c2 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -52,6 +52,7 @@ class Conference < ApplicationRecord through: :program, source: :events has_many :event_types, through: :program + has_many :track_types, through: :program has_many :surveys, as: :surveyable, dependent: :destroy do def for_registration diff --git a/app/models/program.rb b/app/models/program.rb index 8db24c6c..ff3fd068 100644 --- a/app/models/program.rb +++ b/app/models/program.rb @@ -10,6 +10,7 @@ class Program < ApplicationRecord has_many :cfps, dependent: :destroy has_many :event_types, dependent: :destroy has_many :tracks, dependent: :destroy + has_many :track_types, dependent: :destroy has_many :difficulty_levels, dependent: :destroy has_many :schedules, dependent: :destroy has_many :event_schedules, through: :schedules diff --git a/app/models/track_type.rb b/app/models/track_type.rb new file mode 100644 index 00000000..bc04bdf9 --- /dev/null +++ b/app/models/track_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class TrackType < ApplicationRecord + belongs_to :program, touch: true + + has_paper_trail meta: { conference_id: :conference_id }, + ignore: %i[updated_at] + + validates :title, presence: true + + private + + def conference_id + program.conference_id + end +end diff --git a/app/views/admin/track_types/_form.html.haml b/app/views/admin/track_types/_form.html.haml new file mode 100644 index 00000000..3ccc83f6 --- /dev/null +++ b/app/views/admin/track_types/_form.html.haml @@ -0,0 +1,17 @@ +.row + .col-md-12 + .page-header + %h1 + - if track_type.new_record? + New + Track Type + = track_type.title +.row + .col-md-12 + = semantic_form_for(track_type, + url: (track_type.new_record? ? admin_conference_program_track_types_path : admin_conference_program_track_type_path(conference, + track_type))) do |f| + = f.input :title, input_html: { autofocus: true } + = f.input :description + %p.text-right + = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/track_types/edit.html.haml b/app/views/admin/track_types/edit.html.haml new file mode 100644 index 00000000..0d48440d --- /dev/null +++ b/app/views/admin/track_types/edit.html.haml @@ -0,0 +1 @@ += render 'form', track_type: @track_type, conference: @conference diff --git a/app/views/admin/track_types/index.html.haml b/app/views/admin/track_types/index.html.haml new file mode 100644 index 00000000..2c3185d3 --- /dev/null +++ b/app/views/admin/track_types/index.html.haml @@ -0,0 +1,29 @@ +.row + .col-md-12 + .page-header + %h1 Track Types + %p.text-muted + The different types of tracks in your conference +.row + .col-md-12 + %table.table.table-hover#track-types + %thead + %th Title + %th Description + %th Actions + %tbody + - @conference.program.track_types.each do |track_type| + %tr + %td + = track_type.title + %td + = track_type.description + %td + .btn-group{ role: 'group' } + = link_to 'Edit', edit_admin_conference_program_track_type_path(@conference.short_title, track_type.id), + method: :get, class: 'btn btn-primary' + = link_to 'Delete', admin_conference_program_track_type_path(@conference.short_title, track_type.id), + method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete #{track_type.title}?" } +.row + .col-md-12.text-right + = link_to 'Add Track Type', new_admin_conference_program_track_type_path(@conference.short_title), class: 'btn btn-primary' diff --git a/app/views/admin/track_types/new.html.haml b/app/views/admin/track_types/new.html.haml new file mode 100644 index 00000000..0d48440d --- /dev/null +++ b/app/views/admin/track_types/new.html.haml @@ -0,0 +1 @@ += render 'form', track_type: @track_type, conference: @conference diff --git a/app/views/layouts/_admin_sidebar.html.haml b/app/views/layouts/_admin_sidebar.html.haml index c6da29b0..fbd64214 100644 --- a/app/views/layouts/_admin_sidebar.html.haml +++ b/app/views/layouts/_admin_sidebar.html.haml @@ -78,6 +78,9 @@ - if can? :update, @conference.program.event_types.build %li{class: active_nav_li(admin_conference_program_event_types_path(@conference.short_title))} = link_to 'Event Types', admin_conference_program_event_types_path(@conference.short_title) + - if can? :update, @conference.program.track_types.build + %li{class: active_nav_li(admin_conference_program_track_types_path(@conference))} + = link_to 'Track Types', admin_conference_program_track_types_path(@conference.short_title) - if can? :update, @conference.program.difficulty_levels.build, conference_id: @conference.id %li{class: active_nav_li(admin_conference_program_difficulty_levels_path(@conference.short_title))} = link_to 'Difficulty Levels', admin_conference_program_difficulty_levels_path(@conference.short_title) diff --git a/config/routes.rb b/config/routes.rb index 57bfa630..bd7246d2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -95,6 +95,7 @@ Osem::Application.routes.draw do end end resources :event_types + resources :track_types resources :difficulty_levels post 'mass_upload_commercials' => 'commercials#mass_upload' resources :events do diff --git a/db/migrate/20190622061319_create_track_types.rb b/db/migrate/20190622061319_create_track_types.rb new file mode 100644 index 00000000..4a7b2f8f --- /dev/null +++ b/db/migrate/20190622061319_create_track_types.rb @@ -0,0 +1,11 @@ +class CreateTrackTypes < ActiveRecord::Migration[5.1] + def change + create_table :track_types do |t| + t.references :program + t.string :title, null: false + t.string :description + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index b199367e..b5418627 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_06_03_143107) do +ActiveRecord::Schema.define(version: 20190622061319) do create_table "answers", force: :cascade do |t| t.string "title" @@ -532,6 +532,15 @@ ActiveRecord::Schema.define(version: 2019_06_03_143107) do t.datetime "updated_at" end + create_table "track_types", force: :cascade do |t| + t.integer "program_id" + t.string "title", null: false + t.string "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["program_id"], name: "index_track_types_on_program_id" + end + create_table "tracks", force: :cascade do |t| t.string "guid", null: false t.string "name", null: false diff --git a/spec/factories/track_types.rb b/spec/factories/track_types.rb new file mode 100644 index 00000000..5689c1e4 --- /dev/null +++ b/spec/factories/track_types.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :track_type do + title { 'Example Track Type' } + description { 'test description' } + program + end +end diff --git a/spec/features/organization_admin_ability_spec.rb b/spec/features/organization_admin_ability_spec.rb index 5765d97f..e43719aa 100644 --- a/spec/features/organization_admin_ability_spec.rb +++ b/spec/features/organization_admin_ability_spec.rb @@ -42,6 +42,7 @@ feature 'Has correct abilities' do expect(page).to have_link('Events', href: "/admin/conferences/#{conference.short_title}/program/events") expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference.short_title}/program/tracks") expect(page).to have_link('Event Types', href: "/admin/conferences/#{conference.short_title}/program/event_types") + expect(page).to have_link('Track Types', href: "/admin/conferences/#{conference.short_title}/program/track_types") expect(page).to have_link('Difficulty Levels', href: "/admin/conferences/#{conference.short_title}/program/difficulty_levels") expect(page).to have_link('Schedules', href: "/admin/conferences/#{conference.short_title}/schedules") expect(page).to have_link('Reports', href: "/admin/conferences/#{conference.short_title}/program/reports") @@ -167,6 +168,16 @@ feature 'Has correct abilities' do visit edit_admin_conference_program_event_type_path(conference.short_title, conference.program.event_types.first) expect(current_path).to eq(edit_admin_conference_program_event_type_path(conference.short_title, conference.program.event_types.first)) + visit admin_conference_program_track_types_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_track_types_path(conference.short_title)) + + visit new_admin_conference_program_track_type_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_track_type_path(conference.short_title)) + + create(:track_type, program: conference.program) + visit edit_admin_conference_program_track_type_path(conference.short_title, conference.program.track_types.first) + expect(current_path).to eq(edit_admin_conference_program_track_type_path(conference.short_title, conference.program.track_types.first)) + visit admin_conference_program_difficulty_levels_path(conference.short_title) expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference.short_title)) diff --git a/spec/features/organizer_ability_spec.rb b/spec/features/organizer_ability_spec.rb index 6339b6fa..4cea16c0 100644 --- a/spec/features/organizer_ability_spec.rb +++ b/spec/features/organizer_ability_spec.rb @@ -45,6 +45,7 @@ feature 'Has correct abilities' do expect(page).to have_link('Events', href: "/admin/conferences/#{conference.short_title}/program/events") expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference.short_title}/program/tracks") expect(page).to have_link('Event Types', href: "/admin/conferences/#{conference.short_title}/program/event_types") + expect(page).to have_link('Track Types', href: "/admin/conferences/#{conference.short_title}/program/track_types") expect(page).to have_link('Difficulty Levels', href: "/admin/conferences/#{conference.short_title}/program/difficulty_levels") expect(page).to have_link('Schedules', href: "/admin/conferences/#{conference.short_title}/schedules") expect(page).to have_link('Reports', href: "/admin/conferences/#{conference.short_title}/program/reports") @@ -173,6 +174,16 @@ feature 'Has correct abilities' do visit edit_admin_conference_program_event_type_path(conference.short_title, conference.program.event_types.first) expect(current_path).to eq(edit_admin_conference_program_event_type_path(conference.short_title, conference.program.event_types.first)) + visit admin_conference_program_track_types_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_track_types_path(conference.short_title)) + + visit new_admin_conference_program_track_type_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_track_type_path(conference.short_title)) + + create(:track_type, program: conference.program) + visit edit_admin_conference_program_track_type_path(conference.short_title, conference.program.track_types.first) + expect(current_path).to eq(edit_admin_conference_program_track_type_path(conference.short_title, conference.program.track_types.first)) + visit admin_conference_program_difficulty_levels_path(conference.short_title) expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference.short_title)) diff --git a/spec/features/track_types_spec.rb b/spec/features/track_types_spec.rb new file mode 100644 index 00000000..c62a4659 --- /dev/null +++ b/spec/features/track_types_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require 'spec_helper' + +feature TrackType do + let!(:conference) { create(:conference) } + let!(:organizer) { create(:organizer, resource: conference) } + + shared_examples 'track types' do + scenario 'adds and updates track type', feature: true do + + sign_in organizer + visit admin_conference_program_track_types_path( + conference_id: conference.short_title) + + # Add event type + click_link 'Add Track Type' + + fill_in 'track_type_title', with: '2 day devroom' + fill_in 'track_type_description', with: 'Devroom that spans two days' + + click_button 'Create Track type' + page.find('#flash') + # Validations + expect(flash).to eq('Track type successfully created.') + within('table#track-types') do + expect(page.has_content?('2 day devroom')).to be true + expect(page.has_content?('Devroom that spans two days')).to be true + expect(page.assert_selector('tr', count: 1)).to be true + end + + # Remove track type + within('tr', text: '2 day devroom') do + click_link 'Delete' + end + page.find('#flash') + expect(flash).to eq('Track type successfully deleted.') + + within('table#track-types') do + expect(page.assert_selector('tr', count: 0)).to be true + expect(page.has_content?('2 day devroom')).to be false + end + end + end + + describe 'organizer' do + it_behaves_like 'track types' + end +end diff --git a/spec/models/track_type_spec.rb b/spec/models/track_type_spec.rb new file mode 100644 index 00000000..475ad985 --- /dev/null +++ b/spec/models/track_type_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe TrackType do + let(:conference) { create(:conference) } + let(:track_type) { create(:track_type, program: conference.program) } + + describe 'association' do + it { is_expected.to belong_to :program } + end + + describe 'validation' do + it 'has a valid factory' do + expect(build(:track_type)).to be_valid + end + + it { is_expected.to validate_presence_of(:title) } + + end +end