From 02d75ec7294e99464ef6be0a05bdfad7f87032f4 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Sat, 27 May 2017 11:23:03 +0200 Subject: [PATCH 001/237] Fix registration sorting Sort the 'Actions' column by registration.attended --- app/views/admin/registrations/index.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/registrations/index.html.haml b/app/views/admin/registrations/index.html.haml index 0e7035c0..a51d41fc 100644 --- a/app/views/admin/registrations/index.html.haml +++ b/app/views/admin/registrations/index.html.haml @@ -56,7 +56,7 @@ -if @conference.questions.any? %td = link_to 'Questions','#', class: 'btn btn-success question-btn', 'data-id' => index, 'data-name' => registration.name - %td + %td{ 'data-order' => registration.attended.to_s } = check_box_tag "#{@conference.short_title}_#{registration.id}", registration.id, registration.attended, class: 'switch-checkbox', method: :patch, url: toggle_attendance_admin_conference_registration_path(@conference.short_title, id: registration.id)+"?attended=", From 5bb52f24a5d7ca5525579e830a0e443e68e566b8 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Sun, 4 Jun 2017 12:54:15 +0300 Subject: [PATCH 002/237] Ignore html_safe in application helper --- .rubocop_todo.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index e0c6dd97..bc17a090 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -183,6 +183,7 @@ Rails/OutputSafety: Exclude: - 'app/helpers/format_helper.rb' - 'app/models/commercial.rb' + - 'app/helpers/application_helper.rb' # Offense count: 10 # Cop supports --auto-correct. From 6cb11ff2f3dc02dd30dbbaadbe4f94d4ad63a123 Mon Sep 17 00:00:00 2001 From: nasia Date: Sat, 3 Jun 2017 13:48:49 +0300 Subject: [PATCH 003/237] Add Style/WordArray at rubocop.yml #1463 --- .rubocop.yml | 4 ++++ .rubocop_todo.yml | 8 -------- app/models/event_user.rb | 2 +- lib/tasks/version.rake | 2 +- spec/helpers/users_helper_spec.rb | 2 +- spec/models/user_spec.rb | 2 +- 6 files changed, 8 insertions(+), 12 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index c333e43a..de234a2a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -104,6 +104,10 @@ Style/TrailingBlankLines: Style/TrailingWhitespace: Enabled: true +# Check for array literals made up of word-like strings, that are not using the %w() syntax +Style/WordArray: + Enabled: true + # This cop checks for numeric comparisons that can be replaced by a predicate method. Style/ZeroLengthPredicate: Enabled: true diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index bc17a090..a7ea415b 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -928,11 +928,3 @@ Style/UnneededInterpolation: Style/VariableNumber: Exclude: - 'spec/models/ticket_purchase_spec.rb' - -# Offense count: 6 -# Cop supports --auto-correct. -# Configuration parameters: SupportedStyles, WordRegex. -# SupportedStyles: percent, brackets -Style/WordArray: - EnforcedStyle: percent - MinSize: 3 diff --git a/app/models/event_user.rb b/app/models/event_user.rb index 64952a28..58adadad 100644 --- a/app/models/event_user.rb +++ b/app/models/event_user.rb @@ -1,6 +1,6 @@ class EventUser < ActiveRecord::Base # TODO Do we need these roles? - ROLES = [['Speaker', 'speaker'], ['Submitter', 'submitter'], ['Moderator', 'moderator']] + ROLES = [%w[Speaker speaker], %w[Submitter submitter], %w[Moderator moderator]] belongs_to :event belongs_to :user diff --git a/lib/tasks/version.rake b/lib/tasks/version.rake index 084ff181..e4005c15 100644 --- a/lib/tasks/version.rake +++ b/lib/tasks/version.rake @@ -2,7 +2,7 @@ namespace :data do desc 'Sets conference_id in all pre-existing PaperTrail::Version objects' task set_conference_in_versions: :environment do - PaperTrail::Version.where(conference_id: nil, item_type: ['Conference', 'Event']).each do |version| + PaperTrail::Version.where(conference_id: nil, item_type: %w[Conference Event]).each do |version| # All pre-existing versions are either of Conference or Event if version.item_type == 'Conference' version.update_attributes(conference_id: version.item_id) diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb index dfc337e6..e0c2d3fd 100644 --- a/spec/helpers/users_helper_spec.rb +++ b/spec/helpers/users_helper_spec.rb @@ -4,7 +4,7 @@ describe UsersHelper, type: :helper do describe 'show_roles' do it 'formats the hash passed' do - roles = { 'organizer' => ['oSC16', 'oSC15'], 'cfp' => ['oSC16'] } + roles = { 'organizer' => %w[oSC16 oSC15], 'cfp' => ['oSC16'] } expect(show_roles(roles)).to eq 'Organizer (oSC16, oSC15), Cfp (oSC16)' end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index d0517212..e742b993 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -282,7 +282,7 @@ describe User do it 'returns hash of role and conference' do expected_hash = { - 'organizer' => ['oSC16', 'oSC15'], + 'organizer' => %w[oSC16 oSC15], 'cfp' => ['oSC16'] } From 7a7fcced487de914c9bd2bfc9e4e51839413aa8e Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Tue, 6 Jun 2017 19:03:23 +0300 Subject: [PATCH 004/237] Replace .today with .current in program spec The cfp_open? method uses Date.current, so it should also be tested with Date.current and not Date.today Also, build was replaced with create to fix a false negative This is a partial fix for #1522 --- spec/models/program_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/models/program_spec.rb b/spec/models/program_spec.rb index ac720def..a2106791 100644 --- a/spec/models/program_spec.rb +++ b/spec/models/program_spec.rb @@ -141,7 +141,7 @@ describe Program do describe '#cfp_open?' do describe 'returns true' do it 'when there is an open Call for Papers for the conference' do - create(:cfp, start_date: Date.today - 2, end_date: Date.today, program_id: program.id) + create(:cfp, start_date: Date.current - 2, end_date: Date.current, program_id: program.id) expect(program.cfp_open?).to be true end end @@ -152,7 +152,7 @@ describe Program do end it 'when the Call for Papers period is over' do - build(:cfp, start_date: Date.today - 2, end_date: Date.today - 1, program_id: program.id) + create(:cfp, start_date: Date.current - 2, end_date: Date.current - 1, program_id: program.id) expect(program.cfp_open?).to be false end end From 5acb4a93392c613f3a43bbec04b5aae2e849d957 Mon Sep 17 00:00:00 2001 From: mdeniz Date: Fri, 9 Jun 2017 14:41:44 +0200 Subject: [PATCH 005/237] Split in 2 jobs Travis build --- .travis.yml | 9 ++++++--- travis_script.sh | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) create mode 100755 travis_script.sh diff --git a/.travis.yml b/.travis.yml index 0be912e1..6c83258b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,9 @@ before_script: - mysql -u root -e 'create database osem_test;' - RAILS_ENV=test bundle exec rake db:migrate --trace script: - - 'bundle exec rubocop -Dc .rubocop.yml' - - 'bundle exec haml-lint app/views' - - 'bundle exec rspec --color --format documentation' + - "./travis_script.sh $TEST_SUITE" +env: + - TEST_SUITE=rspec + - TEST_SUITE=linters +matrix: + fast_finish: true diff --git a/travis_script.sh b/travis_script.sh new file mode 100755 index 00000000..77ca2329 --- /dev/null +++ b/travis_script.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# This script runs the test suites for the CI build + +# Be verbose and fail script on the first error +set -xe + +# By default: all test runs +if [ -z $1 ]; then + TEST_SUITE="all" +else + TEST_SUITE="$1" +fi + +case $TEST_SUITE in + linters) + bundle exec rubocop -Dc .rubocop.yml + bundle exec haml-lint app/views + ;; + rspec) + bundle exec rspec --color --format documentation + ;; + *) + bundle exec rubocop -Dc .rubocop.yml + bundle exec haml-lint app/views + bundle exec rspec --color --format documentation + ;; +esac From ebe1ca374da3366e29efe1e63a65d618cdfe9fe5 Mon Sep 17 00:00:00 2001 From: mdeniz Date: Fri, 9 Jun 2017 14:41:51 +0200 Subject: [PATCH 006/237] Fix the Travis failure in the last PR about axlsx dependencies --- Gemfile | 3 ++- Gemfile.lock | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 497c56b1..76c49ce3 100644 --- a/Gemfile +++ b/Gemfile @@ -128,6 +128,7 @@ gem 'country_select' gem 'prawn_rails' # to render XLS spreadsheets +gem 'axlsx', git: 'https://github.com/randym/axlsx.git' gem 'axlsx_rails' # as error catcher @@ -178,7 +179,7 @@ gem 'cloudinary' # for setting app configuration in the environment gem 'dotenv-rails' -# For countable.js +# For countable.js gem "countable-rails", "~> 0.0.1" # Both are not in a group as we use it also for rake data:demo diff --git a/Gemfile.lock b/Gemfile.lock index 90ae82f0..e1c8218f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,13 @@ +GIT + remote: https://github.com/randym/axlsx.git + revision: c8ac844572b25fda358cc01d2104720c4c42f450 + specs: + axlsx (2.1.0.pre) + htmlentities (~> 4.3.4) + mimemagic (~> 0.3) + nokogiri (>= 1.6.6) + rubyzip (>= 1.2.1) + GEM remote: https://rubygems.org/ remote: https://rails-assets.org/ @@ -65,10 +75,6 @@ GEM awesome_nested_set (3.0.0.rc.5) activerecord (>= 4.0.0, < 5) aws_cf_signer (0.1.3) - axlsx (2.0.1) - htmlentities (~> 4.3.1) - nokogiri (>= 1.4.1) - rubyzip (~> 1.2.1) axlsx_rails (0.2.0) axlsx (>= 2.0.1) rails (>= 3.1) @@ -262,6 +268,7 @@ GEM mime-types (>= 1.16, < 3) method_source (0.8.2) mime-types (2.99.1) + mimemagic (0.3.2) mina (0.3.8) open4 (~> 1.3.4) rake @@ -551,6 +558,7 @@ DEPENDENCIES ahoy_matey autoprefixer-rails awesome_nested_set (~> 3.0.0.rc.5) + axlsx! axlsx_rails bootstrap-sass (~> 3.3.4.1) bootstrap-switch-rails (~> 3.0.0) From 0d01ed08b0351ef7839c7e8ef53d03ac24ed7c72 Mon Sep 17 00:00:00 2001 From: divyanshumehta Date: Mon, 29 May 2017 09:32:57 +0530 Subject: [PATCH 007/237] Added Style/SpaceInsideBrackets Rubocop cop --- .rubocop.yml | 4 ++++ .rubocop_todo.yml | 7 ------- app/models/conference.rb | 2 +- app/models/user.rb | 4 ++-- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index de234a2a..9f7f0d00 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -88,6 +88,10 @@ Style/RedundantSelf: Style/SpaceAroundOperators: Enabled: true +# Checks for spaces inside square brackets. +Style/SpaceInsideBrackets: + Enabled: true + # Use single quotes unless there's string interpolation Style/StringLiterals: Enabled: true diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index a7ea415b..37164318 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -811,13 +811,6 @@ Style/SpaceInsideBlockBraces: - 'spec/models/ability_spec.rb' - 'spec/models/user_spec.rb' -# Offense count: 5 -# Cop supports --auto-correct. -Style/SpaceInsideBrackets: - Exclude: - - 'app/models/conference.rb' - - 'app/models/user.rb' - # Offense count: 25 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces. diff --git a/app/models/conference.rb b/app/models/conference.rb index 1c4ccc73..79b38be2 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -803,7 +803,7 @@ class Conference < ActiveRecord::Base hash[key] = 0 end end - Hash[ hash.sort ] + Hash[hash.sort] end ## diff --git a/app/models/user.rb b/app/models/user.rb index a63d721e..4be77fe8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -26,11 +26,11 @@ class User < ActiveRecord::Base devise_modules = [] if ENV['OSEM_ICHAIN_ENABLED'] == 'true' - devise_modules += [ :ichain_authenticatable, :ichain_registerable, :omniauthable, omniauth_providers: [] ] + devise_modules += [:ichain_authenticatable, :ichain_registerable, :omniauthable, omniauth_providers: []] else devise_modules += [:database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, - :omniauthable, omniauth_providers: [:suse, :google, :facebook, :github] ] + :omniauthable, omniauth_providers: [:suse, :google, :facebook, :github]] end devise(*devise_modules) From 1223fef87c0467ce58fab121832852e77217f0eb Mon Sep 17 00:00:00 2001 From: divyanshumehta Date: Mon, 29 May 2017 15:02:14 +0530 Subject: [PATCH 008/237] Use of rubocop compliant unescaping methods in application_helper.rb --- app/helpers/application_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index b3081f9b..e0b3b85b 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -147,7 +147,7 @@ module ApplicationHelper end def speaker_links(event) - event.speakers.map{ |speaker| link_to speaker.name, admin_user_path(speaker) }.join(', ').html_safe + safe_join(event.speakers.map{ |speaker| link_to speaker.name, admin_user_path(speaker) }, ',') end def speaker_selector_input(form) From 071ed50acb3a6f34253b8561e167ddce97794877 Mon Sep 17 00:00:00 2001 From: selini Date: Tue, 21 Mar 2017 21:08:53 +0200 Subject: [PATCH 009/237] Hide recent Registrations/Submissions when conference is over --- app/helpers/application_helper.rb | 53 +++++++++++++++++++ .../admin/conferences/_todo_list.html.haml | 18 +++---- app/views/admin/conferences/show.html.haml | 4 +- 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index b3081f9b..d1d64fbd 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -33,6 +33,50 @@ module ApplicationHelper result end + # Returns time with conference timezone + def time_with_timezone(time) + time.strftime('%F %R') + ' ' + @conference.timezone.to_s + end + + ## + # Checks if the voting has already started, or if it has already ended + # + def voting_open_or_close(program) + return if program.voting_period? + if program.voting_start_date > Time.current + return 'Voting period has not started yet!' + else # voting_end_date > Date.today because voting_start_date < voting_end_date + return 'Voting period is over!' + end + end + + ## + # Gets an EventType object, and returns its length in timestamp format (HH:MM) + # ====Gets + # * +Integer+ -> 30 + # ====Returns + # * +String+ -> "00:30" + def length_timestamp(length) + [length / 60, length % 60].map { |t| t.to_s.rjust(2, '0') }.join(':') + end + + ## + # Gets a datetime object + # ====Returns + # * +String+ -> formated datetime object + def format_datetime(obj) + return unless obj + obj.strftime('%Y-%m-%d %H:%M') + end + + ## + # ====Returns + # * +String+ -> number of registrations / max allowed registrations + def registered_text(event) + return "Registered: #{event.registrations.count}/#{event.max_attendees}" if event.max_attendees + "Registered: #{event.registrations.count}" + end + # Set resource_name for devise so that we can call the devise help links (views/devise/shared/_links) from anywhere (eg sign_up form in proposals#new) def resource_name :user @@ -168,4 +212,13 @@ module ApplicationHelper new_user_session_path end end + + ## + # ====Gets + # a conference object + # ==== Returns + # class hidden if conference is over + def hidden_if_conference_over(conference) + 'hidden' if Date.today > conference.end_date + end end diff --git a/app/views/admin/conferences/_todo_list.html.haml b/app/views/admin/conferences/_todo_list.html.haml index cd98391d..63f4e3aa 100644 --- a/app/views/admin/conferences/_todo_list.html.haml +++ b/app/views/admin/conferences/_todo_list.html.haml @@ -1,12 +1,12 @@ .list-group - %li.list-group-item + %li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)}" } %h4 Conference progress .progress .progress-bar{ 'role' => 'progressbar', 'aria-valuenow' => "#{conference_progress['process']}", 'aria-valuemin' => '0', 'aria-valuemax' => '100', 'style' => "width: #{conference_progress['process']}%;" } = conference_progress['process'] + '%' - %li{ 'class' => "list-group-item #{class_for_todo(conference_progress['registration'])}" } + %li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['registration'])}" } %span{ 'class' => icon_for_todo(conference_progress['registration']) } - if can? :update, @conference - if conference.registration_period @@ -15,13 +15,13 @@ = link_to 'Set up registration period', new_admin_conference_registration_period_path(conference_progress['short_title']) - else Set up registration period - %li{ 'class' => "list-group-item #{class_for_todo(conference_progress['cfp'])}" } + %li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['cfp'])}" } %span{ 'class' => icon_for_todo(conference_progress['cfp']) } - if can? :update, Cfp.new(program_id: @program.id) = link_to 'Set up call for papers', admin_conference_program_cfp_path(conference_progress['short_title']) - else Set up call for papers - %li{'class'=>"list-group-item #{class_for_todo(conference_progress['venue'])}"} + %li{'class'=>"list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['venue'])}"} %span{'class'=>icon_for_todo(conference_progress['venue'])} - if can? :update, Venue.new(conference: @conference) - @conference.reload @@ -32,31 +32,31 @@ - else - @conference.reload Add venue - %li{ 'class' => "list-group-item #{class_for_todo(conference_progress['rooms'])}" } + %li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['rooms'])}" } %span{ 'class' => icon_for_todo(conference_progress['rooms']) } - if @conference.venue && (can? :update, @conference.venue.rooms.build) = link_to 'Add rooms', admin_conference_venue_rooms_path(conference_progress['short_title']) - else Add rooms - %li{ 'class' => "list-group-item #{class_for_todo(conference_progress['tracks'])}" } + %li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['tracks'])}" } %span{ 'class' => icon_for_todo(conference_progress['tracks']) } - if can? :update, @conference.program.tracks.build = link_to 'Add tracks', admin_conference_program_tracks_path(conference_progress['short_title']) - else Add tracks - %li{ 'class' => "list-group-item #{class_for_todo(conference_progress['event_types'])}" } + %li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['event_types'])}" } %span{ 'class' => icon_for_todo(conference_progress['event_types']) } - if can? :update, @conference.program.event_types.build = link_to 'Add event types', admin_conference_program_event_types_path(conference_progress['short_title']) - else Add event types - %li{ 'class' => "list-group-item #{class_for_todo(conference_progress['difficulty_levels'])}" } + %li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['difficulty_levels'])}" } %span{ 'class' => icon_for_todo(conference_progress['difficulty_levels']) } - if can? :update, @conference.program.difficulty_levels.build = link_to 'Add difficulty levels', admin_conference_program_difficulty_levels_path(conference_progress['short_title']) - else Add difficulty levels - %li{ class: "list-group-item #{class_for_todo(conference_progress['splashpage'])}" } + %li{ class: "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['splashpage'])}" } %span{ 'class' => icon_for_todo(conference_progress['splashpage']) } - if can? :update, @conference = link_to 'Set up a Splashpage', admin_conference_splashpage_path(conference_progress['short_title']) diff --git a/app/views/admin/conferences/show.html.haml b/app/views/admin/conferences/show.html.haml index dec58da8..39d48f54 100644 --- a/app/views/admin/conferences/show.html.haml +++ b/app/views/admin/conferences/show.html.haml @@ -101,11 +101,11 @@ .row .col-md-8 %ul.nav.nav-tabs#recentTable - %li.active + %li{ 'class' => "active #{hidden_if_conference_over(@conference)}" } %a{ href: '#recent_reg', 'data-toggle' => 'tab' } %span.fa.fa-user Recent Registrations - %li + %li{ 'class' => "#{hidden_if_conference_over(@conference)}" } %a{ href: '#recent_submissions', 'data-toggle' => 'tab' } %span.fa.fa-file-text Recent Submissions From 9ff3601453e72a2e041b52359283152b7932291b Mon Sep 17 00:00:00 2001 From: selini Date: Sun, 11 Jun 2017 18:15:10 +0300 Subject: [PATCH 010/237] remove unnecessary functions --- app/helpers/application_helper.rb | 39 ------------------------------- 1 file changed, 39 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index d1d64fbd..0efe5321 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -38,45 +38,6 @@ module ApplicationHelper time.strftime('%F %R') + ' ' + @conference.timezone.to_s end - ## - # Checks if the voting has already started, or if it has already ended - # - def voting_open_or_close(program) - return if program.voting_period? - if program.voting_start_date > Time.current - return 'Voting period has not started yet!' - else # voting_end_date > Date.today because voting_start_date < voting_end_date - return 'Voting period is over!' - end - end - - ## - # Gets an EventType object, and returns its length in timestamp format (HH:MM) - # ====Gets - # * +Integer+ -> 30 - # ====Returns - # * +String+ -> "00:30" - def length_timestamp(length) - [length / 60, length % 60].map { |t| t.to_s.rjust(2, '0') }.join(':') - end - - ## - # Gets a datetime object - # ====Returns - # * +String+ -> formated datetime object - def format_datetime(obj) - return unless obj - obj.strftime('%Y-%m-%d %H:%M') - end - - ## - # ====Returns - # * +String+ -> number of registrations / max allowed registrations - def registered_text(event) - return "Registered: #{event.registrations.count}/#{event.max_attendees}" if event.max_attendees - "Registered: #{event.registrations.count}" - end - # Set resource_name for devise so that we can call the devise help links (views/devise/shared/_links) from anywhere (eg sign_up form in proposals#new) def resource_name :user From c2184c1c4fe4b355810032e55164c6be665d2d45 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 19 Apr 2017 16:47:59 +0300 Subject: [PATCH 011/237] Add 'week' column to TicketPurchases --- app/models/ticket_purchase.rb | 9 +++++++++ ...20170419132148_add_week_to_ticket_purchases.rb | 15 +++++++++++++++ db/schema.rb | 3 ++- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20170419132148_add_week_to_ticket_purchases.rb diff --git a/app/models/ticket_purchase.rb b/app/models/ticket_purchase.rb index 07fb7e16..d1c370c4 100644 --- a/app/models/ticket_purchase.rb +++ b/app/models/ticket_purchase.rb @@ -18,6 +18,8 @@ class TicketPurchase < ActiveRecord::Base scope :by_conference, ->(conference) { where(conference_id: conference.id) } scope :by_user, ->(user) { where(user_id: user.id) } + after_create :set_week + def self.purchase(conference, user, purchases) errors = [] ActiveRecord::Base.transaction do @@ -59,3 +61,10 @@ class TicketPurchase < ActiveRecord::Base purchase end end + +private + +def set_week + self.week = created_at.strftime('%W') + save! +end diff --git a/db/migrate/20170419132148_add_week_to_ticket_purchases.rb b/db/migrate/20170419132148_add_week_to_ticket_purchases.rb new file mode 100644 index 00000000..0862eb16 --- /dev/null +++ b/db/migrate/20170419132148_add_week_to_ticket_purchases.rb @@ -0,0 +1,15 @@ +class AddWeekToTicketPurchases < ActiveRecord::Migration + class TmpTicketPurchase < ActiveRecord::Base + self.table_name = 'ticket_purchases' + end + + def change + add_column :ticket_purchases, :week, :integer + + TmpTicketPurchase.reset_column_information + TmpTicketPurchase.find_each do |purchase| + purchase.week = purchase.created_at ? purchase.created_at.strftime('%W') : 0 + purchase.save! + end + end +end diff --git a/db/schema.rb b/db/schema.rb index ab95b4dc..5d74950a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170302145716) do +ActiveRecord::Schema.define(version: 20170419132148) do create_table "ahoy_events", force: :cascade do |t| t.uuid "visit_id", limit: 16 @@ -447,6 +447,7 @@ ActiveRecord::Schema.define(version: 20170302145716) do t.integer "quantity", default: 1 t.integer "user_id" t.integer "payment_id" + t.integer "week" end create_table "tickets", force: :cascade do |t| From 41503bb7a044ce2cc1c8285b8f846a3b1a857131 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Thu, 20 Apr 2017 09:47:19 +0300 Subject: [PATCH 012/237] Compute ticket statistics And exclude admin/ConferencesController from rubocop_todo.yml --- .rubocop_todo.yml | 2 + .../admin/conferences_controller.rb | 25 +++++ app/controllers/admin/tickets_controller.rb | 2 + app/models/conference.rb | 93 +++++++++++++++++++ 4 files changed, 122 insertions(+) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index a7ea415b..e70a8709 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -60,6 +60,8 @@ Lint/UnusedBlockArgument: # Offense count: 108 Metrics/AbcSize: Max: 75 + Exclude: + - 'app/controllers/admin/conferences_controller.rb' # Offense count: 202 # Configuration parameters: CountComments, ExcludedMethods. diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index 50360a64..f9e1177d 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -37,6 +37,9 @@ module Admin @registrations = {} @registration_weeks = [0] + @tickets = {} + @ticket_weeks = [0] + @conferences.each do |c| # Event submissions over time chart @submissions[c.short_title] = c.get_submissions_per_week @@ -45,6 +48,10 @@ module Admin # Conference registrations over time chart @registrations[c.short_title] = c.get_registrations_per_week @registration_weeks.push(@registrations[c.short_title].length) + + # Tickets sold over time chart + @tickets[c.short_title] = c.get_tickets_sold_per_week + @ticket_weeks.push(@tickets[c.short_title].length) end @cfp_weeks = @cfp_weeks.max @@ -55,6 +62,10 @@ module Admin @registrations = normalize_array_length(@registrations, @registration_weeks) @registration_weeks = @registration_weeks > 0 ? (1..@registration_weeks).to_a : 1 + @ticket_weeks = @ticket_weeks.max + @tickets = normalize_array_length(@tickets, @ticket_weeks) + @ticket_weeks = @ticket_weeks > 0 ? (1..@ticket_weeks).to_a : 1 + @event_distribution = Conference.event_distribution @user_distribution = Conference.user_distribution end @@ -133,6 +144,20 @@ module Admin @submissions_data = @submissions_data.except('Weeks') end + @tickets_data = {} + @tickets_data = @conference.get_tickets_data + @ticket_weeks = 0 + if @tickets_data['Weeks'] + @ticket_weeks = @tickets_data['Weeks'] + @tickets_data = @tickets_data.except('Weeks') + end + + # Set line color using a hash function + @tickets = [] + @tickets_data.keys.each do |title| + @tickets.append(short_title: title, color: "\##{Digest::MD5.hexdigest(title)[0..5]}") + end + # Doughnut charts @event_type_distribution = @conference.event_type_distribution @event_type_distribution_confirmed = @conference.event_type_distribution(:confirmed) diff --git a/app/controllers/admin/tickets_controller.rb b/app/controllers/admin/tickets_controller.rb index 9042297b..c7161409 100644 --- a/app/controllers/admin/tickets_controller.rb +++ b/app/controllers/admin/tickets_controller.rb @@ -5,6 +5,8 @@ module Admin def index authorize! :update, Ticket.new(conference_id: @conference.id) + @tickets_sold_distribution = @conference.tickets_sold_distribution + @tickets_turnover_distribution = @conference.tickets_turnover_distribution end def new diff --git a/app/models/conference.rb b/app/models/conference.rb index 1c4ccc73..2f623a4c 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -184,6 +184,59 @@ class Conference < ActiveRecord::Base result end + ## + # Returns an array with the summarized ticket sales per week. + # + # ====Returns + # * +Array+ -> e.g. [0, 3, 3, 5] -> first week 0, second week 3 tickets sold + def get_tickets_sold_per_week + result = [] + + if tickets && ticket_purchases && registration_period + tickets_sold = ticket_purchases.paid.group(:week).sum(:quantity) + start_week = get_registration_start_week + weeks = registration_weeks + result = calculate_items_per_week(start_week, weeks, tickets_sold) + end + result + end + + ## + # Returns an hash with ticket sales by ticket title + # per week. + # + # ====Returns + # * +Array+ -> e.g. 'Free Access' => [0, 3, 3, 5] -> first week 0 tickets sold, second week 3 tickets sold. + def get_tickets_data + result = {} + if tickets && ticket_purchases && registration_period + tickets_per_ticket_id_and_week = ticket_purchases.paid.group(:ticket_id, :week).sum(:quantity) + + start_week = get_registration_start_week + weeks = registration_weeks + + tickets_by_id_per_week = {} + + tickets.each do |ticket| + tickets_by_id_per_week[ticket.id] = {} + (start_week...(start_week + weeks)).each do |week| + tickets_by_id_per_week[ticket.id][week] = 0 + end + end + + tickets_per_ticket_id_and_week.each do |ticket_week, value| + tickets_by_id_per_week[ticket_week[0]][ticket_week[1]] = value + end + + tickets_by_id_per_week.each do |ticket, values| + result[Ticket.find(ticket).title] = pad_array_left_not_kumulative(start_week, values) + end + + result['Weeks'] = weeks > 0 ? (1..weeks).to_a : 0 + end + result + end + ## # Calculates how many weeks the registration is. # @@ -396,6 +449,46 @@ class Conference < ActiveRecord::Base calculate_user_distribution_hash(active_user, unconfirmed_user, dead_user) end + ## + # Returns a hash with per ticket sales => { "Title" => { value: number of tickets sold, + # color: generated from the title using a hash function }, ...} + # + # ====Returns + # * +hash+ -> hash + def tickets_sold_distribution + result = {} + + if tickets && ticket_purchases + tickets.each do |ticket| + result[ticket.title] = { + 'value' => ApplicationController.helpers.humanized_money(ticket.tickets_sold).delete(',').to_i, + 'color' => "\##{Digest::MD5.hexdigest(ticket.title)[0..5]}" + } + end + end + result + end + + ## + # Returns a hash with per ticket turnover => { "Title" => { value: ticket turnover, + # color: generated from the title using a hash function }, ...} + # + # ====Returns + # * +hash+ -> hash + def tickets_turnover_distribution + result = {} + + if tickets && ticket_purchases + tickets.each do |ticket| + result[ticket.title] = { + 'value' => ApplicationController.helpers.humanized_money(ticket.tickets_turnover).delete(',').to_i, + 'color' => "\##{Digest::MD5.hexdigest(ticket.title)[0..5]}" + } + end + end + result + end + ## # Calculates the overall program minutes # From 8cd3326520fb4c133e0ad30e0717fffbc0acfe48 Mon Sep 17 00:00:00 2001 From: nasia Date: Tue, 25 Apr 2017 18:22:39 +0300 Subject: [PATCH 013/237] Add charts about sold tickets --- app/views/admin/conferences/index.html.haml | 11 +++++++++++ app/views/admin/conferences/show.html.haml | 11 +++++++++++ app/views/admin/tickets/index.html.haml | 7 ++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/app/views/admin/conferences/index.html.haml b/app/views/admin/conferences/index.html.haml index 24c2d0f2..02208aeb 100644 --- a/app/views/admin/conferences/index.html.haml +++ b/app/views/admin/conferences/index.html.haml @@ -60,6 +60,17 @@ unit: 'weeks' } .col-md-4 = render partial: 'doughnut_chart', locals: { title: 'User', data: @user_distribution } +.row#tickets + .col-md-8 + = render partial: 'line_chart', locals: { title: 'Tickets sold over time', + name: 'tickets', + conferences: @conferences, + active_conferences: @active_conferences, + deactive_conferences: @deactive_conferences, + y: @tickets, + x: @ticket_weeks, + unit: 'weeks' } +%br .row .col-md-8 %ul.nav.nav-tabs#recentTable diff --git a/app/views/admin/conferences/show.html.haml b/app/views/admin/conferences/show.html.haml index 39d48f54..b425dfca 100644 --- a/app/views/admin/conferences/show.html.haml +++ b/app/views/admin/conferences/show.html.haml @@ -69,6 +69,17 @@ .col-md-4 = render partial: 'todo_list', locals: { conference_progress: @conference_progress, conference: @conference } + .row#tickets + .col-md-8 + =render partial: 'line_chart', locals: { title: 'Tickets sold over time', + name: 'tickets', + conferences: @tickets, + active_conferences: @tickets, + deactive_conferences: [], + y: @tickets_data, + x: @ticket_weeks, + unit: 'weeks' } +%br .row .col-md-12#doughnut %ul.nav.nav-tabs#doughnut_tabs diff --git a/app/views/admin/tickets/index.html.haml b/app/views/admin/tickets/index.html.haml index 7fa3e37c..6a0c7dca 100644 --- a/app/views/admin/tickets/index.html.haml +++ b/app/views/admin/tickets/index.html.haml @@ -4,6 +4,12 @@ %h1 Tickets %p.text-muted Tickets to get during registration +.row + .col-md-4 + = render partial: 'admin/conferences/doughnut_chart', locals: { title: 'Tickets sold', data: @tickets_sold_distribution,} + .col-md-4 + = render partial: 'admin/conferences/doughnut_chart', locals: { title: 'Tickets turnover', data: @tickets_turnover_distribution } +%br - if @conference.tickets.any? .row .col-md-12 @@ -36,4 +42,3 @@ .row .col-md-12 = link_to 'Add Ticket', new_admin_conference_ticket_path, class: 'btn btn-success pull-right' - From ce9d2b3c5b790d327e69e8177bd5356da7c0b000 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Mon, 12 Jun 2017 18:37:50 +0530 Subject: [PATCH 014/237] fixes failing haml-lint in admin/conference/show --- app/views/admin/conferences/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/conferences/show.html.haml b/app/views/admin/conferences/show.html.haml index b425dfca..cddae4c2 100644 --- a/app/views/admin/conferences/show.html.haml +++ b/app/views/admin/conferences/show.html.haml @@ -71,7 +71,7 @@ conference: @conference } .row#tickets .col-md-8 - =render partial: 'line_chart', locals: { title: 'Tickets sold over time', + = render partial: 'line_chart', locals: { title: 'Tickets sold over time', name: 'tickets', conferences: @tickets, active_conferences: @tickets, From 8edf896d86593bc888b9d7b39a031544bdb3eb04 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 31 May 2017 18:42:52 +0530 Subject: [PATCH 015/237] introduce organizations --- .../admin/organizations_controller.rb | 19 ++++ app/controllers/organizations_controller.rb | 50 +++++++++ app/models/conference.rb | 5 +- app/models/organization.rb | 7 ++ app/views/admin/organizations/_form.html.haml | 13 +++ app/views/admin/organizations/index.html.haml | 31 ++++++ .../layouts/_admin_sidebar_index.html.haml | 4 + app/views/layouts/_user_menu.html.haml | 4 + app/views/organizations/_form.html.haml | 13 +++ app/views/organizations/edit.html.haml | 4 + app/views/organizations/index.html.haml | 17 +++ app/views/organizations/new.html.haml | 4 + config/routes.rb | 3 +- .../20170529215453_create_organizations.rb | 9 ++ ...094817_add_organizaton_id_to_conference.rb | 5 + db/schema.rb | 9 +- .../admin/organizations_controller_spec.rb | 14 +++ .../organizations_controller_spec.rb | 104 ++++++++++++++++++ spec/factories/conferences.rb | 2 +- spec/factories/organizations.rb | 13 +++ spec/models/organization_spec.rb | 19 ++++ 21 files changed, 345 insertions(+), 4 deletions(-) create mode 100644 app/controllers/admin/organizations_controller.rb create mode 100644 app/controllers/organizations_controller.rb create mode 100644 app/models/organization.rb create mode 100644 app/views/admin/organizations/_form.html.haml create mode 100644 app/views/admin/organizations/index.html.haml create mode 100644 app/views/organizations/_form.html.haml create mode 100644 app/views/organizations/edit.html.haml create mode 100644 app/views/organizations/index.html.haml create mode 100644 app/views/organizations/new.html.haml create mode 100644 db/migrate/20170529215453_create_organizations.rb create mode 100644 db/migrate/20170531094817_add_organizaton_id_to_conference.rb create mode 100644 spec/controllers/admin/organizations_controller_spec.rb create mode 100644 spec/controllers/organizations_controller_spec.rb create mode 100644 spec/factories/organizations.rb create mode 100644 spec/models/organization_spec.rb diff --git a/app/controllers/admin/organizations_controller.rb b/app/controllers/admin/organizations_controller.rb new file mode 100644 index 00000000..1dc6bcd5 --- /dev/null +++ b/app/controllers/admin/organizations_controller.rb @@ -0,0 +1,19 @@ +module Admin + class OrganizationsController < Admin::BaseController + load_and_authorize_resource :organization + + def index + @organizations = Organization.all + end + + def destroy + if @organization.destroy + redirect_to admin_organizations_path, + notice: 'Organization successfully destroyed' + else + redirect_to admin_organizations_path, + error: 'Organization cannot be destroyed' + end + end + end +end diff --git a/app/controllers/organizations_controller.rb b/app/controllers/organizations_controller.rb new file mode 100644 index 00000000..58910526 --- /dev/null +++ b/app/controllers/organizations_controller.rb @@ -0,0 +1,50 @@ +class OrganizationsController < ApplicationController + load_and_authorize_resource :organization + + def index + @organizations = Organization.all + end + + def create + @organization = Organization.new(organization_params) + if @organization.save + redirect_to organizations_path, + notice: 'Organization successfully created' + else + redirect_to new_organization_path, + error: @organization.errors.full_messages.join(', ') + end + end + + def new + @organization = Organization.new + end + + def edit; end + + def update + if @organization.update_attributes(organization_params) + redirect_to organizations_path, + notice: 'Organization successfully updated' + else + redirect_to edit_organization_path(@organization), + error: @organization.errors.full_messages.join(', ') + end + end + + def destroy + if @organization.destroy + redirect_to organizations_path, + notice: 'Organization successfully destroyed' + else + redirect_to organizations_path, + error: 'Organization cannot be destroyed' + end + end + + private + + def organization_params + params.require(:organization).permit(:name, :description, :picture) + end +end diff --git a/app/models/conference.rb b/app/models/conference.rb index 2f623a4c..0f09d694 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -7,6 +7,8 @@ class Conference < ActiveRecord::Base default_scope { order('start_date DESC') } + belongs_to :organization + has_paper_trail ignore: %i(updated_at guid revision events_per_week), meta: { conference_id: :id } has_and_belongs_to_many :questions @@ -53,7 +55,8 @@ class Conference < ActiveRecord::Base :start_date, :end_date, :start_hour, - :end_hour, presence: true + :end_hour, + :organization, presence: true validates :short_title, uniqueness: true validates :short_title, format: { with: /\A[a-zA-Z0-9_-]*\z/ } diff --git a/app/models/organization.rb b/app/models/organization.rb new file mode 100644 index 00000000..60a83fef --- /dev/null +++ b/app/models/organization.rb @@ -0,0 +1,7 @@ +class Organization < ActiveRecord::Base + has_many :conferences, dependent: :destroy + + validates :name, presence: true + + mount_uploader :picture, PictureUploader, mount_on: :picture +end diff --git a/app/views/admin/organizations/_form.html.haml b/app/views/admin/organizations/_form.html.haml new file mode 100644 index 00000000..c41f0cff --- /dev/null +++ b/app/views/admin/organizations/_form.html.haml @@ -0,0 +1,13 @@ += semantic_form_for(@organization) do |f| + = f.inputs name: 'Organization details' do + = f.input :name, as: :string, required: true + = f.input :description, input_html: { rows: 5 }, placeholder: 'Decribe about your organization..' + = image_tag f.object.picture.thumb.url if f.object.picture? + - if @organization.picture + = image_tag(@organization.picture.thumb.url, width: '20%') + = f.input :picture + %p.text-right + - if @organization.new_record? + = f.submit 'Create Organization', class: 'btn btn-success' + - else + = f.submit 'Update Organization', class: 'btn btn-success' \ No newline at end of file diff --git a/app/views/admin/organizations/index.html.haml b/app/views/admin/organizations/index.html.haml new file mode 100644 index 00000000..0a751460 --- /dev/null +++ b/app/views/admin/organizations/index.html.haml @@ -0,0 +1,31 @@ +.row + .col-md-12 + .page-header + %h1 Organizations + .btn-group.pull-right + = link_to 'Add Organization', new_admin_organization_path, class: 'btn btn-success pull-right' + %p.text-muted + Manage organizations in OSEM + .row + .col-md-12 + %table.table.table-hover.datatable + %thead + %th Name + %th Upcoming Conferences + %th Past Conferences + %th Actions + %tbody + - @organizations.each do |organization| + %tr + %td + = organization.name + %td + = organization.conferences.count + %td + = organization.conferences.count + %td + .btn-group + = link_to 'Edit', edit_organization_path(organization), + method: :get, class: 'btn btn-primary' + = link_to 'Delete', admin_organization_path(organization), + method: :delete, class: 'btn btn-danger' diff --git a/app/views/layouts/_admin_sidebar_index.html.haml b/app/views/layouts/_admin_sidebar_index.html.haml index 4ae56dce..f1cf8b75 100644 --- a/app/views/layouts/_admin_sidebar_index.html.haml +++ b/app/views/layouts/_admin_sidebar_index.html.haml @@ -32,3 +32,7 @@ = link_to(admin_revision_history_path) do %span.fa.fa-history Revision History + %li + = link_to(admin_organizations_path) do + %span.fa.fa-group + Organizations diff --git a/app/views/layouts/_user_menu.html.haml b/app/views/layouts/_user_menu.html.haml index 3fb32273..14d32fed 100644 --- a/app/views/layouts/_user_menu.html.haml +++ b/app/views/layouts/_user_menu.html.haml @@ -49,3 +49,7 @@ = link_to(admin_revision_history_path) do %span.fa.fa-history Revision History + %li + = link_to(admin_organizations_path) do + %span.fa.fa-group + Organizations diff --git a/app/views/organizations/_form.html.haml b/app/views/organizations/_form.html.haml new file mode 100644 index 00000000..c41f0cff --- /dev/null +++ b/app/views/organizations/_form.html.haml @@ -0,0 +1,13 @@ += semantic_form_for(@organization) do |f| + = f.inputs name: 'Organization details' do + = f.input :name, as: :string, required: true + = f.input :description, input_html: { rows: 5 }, placeholder: 'Decribe about your organization..' + = image_tag f.object.picture.thumb.url if f.object.picture? + - if @organization.picture + = image_tag(@organization.picture.thumb.url, width: '20%') + = f.input :picture + %p.text-right + - if @organization.new_record? + = f.submit 'Create Organization', class: 'btn btn-success' + - else + = f.submit 'Update Organization', class: 'btn btn-success' \ No newline at end of file diff --git a/app/views/organizations/edit.html.haml b/app/views/organizations/edit.html.haml new file mode 100644 index 00000000..1f65d485 --- /dev/null +++ b/app/views/organizations/edit.html.haml @@ -0,0 +1,4 @@ +.container + .row + .col-md-12 + = render 'form' diff --git a/app/views/organizations/index.html.haml b/app/views/organizations/index.html.haml new file mode 100644 index 00000000..b87f156b --- /dev/null +++ b/app/views/organizations/index.html.haml @@ -0,0 +1,17 @@ +.container + .row + .col-md-12.page-header + %h1 + Organizations + .btn-group.pull-right + = link_to 'Add new', new_organization_path, class: 'btn btn-mini btn-success' + - @organizations.each do |organization| + .col-md-4 + .thumbnail + = image_tag(organization.picture.thumb.url, width: '20%') + .caption + %h4 + = organization.name + %button.btn.btn-success Conferences + = link_to 'Edit', edit_organization_path(organization), class: 'btn btn-mini btn-default' + diff --git a/app/views/organizations/new.html.haml b/app/views/organizations/new.html.haml new file mode 100644 index 00000000..1f65d485 --- /dev/null +++ b/app/views/organizations/new.html.haml @@ -0,0 +1,4 @@ +.container + .row + .col-md-12 + = render 'form' diff --git a/config/routes.rb b/config/routes.rb index 9fa1c29a..e2cfe7f7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,6 +18,7 @@ Osem::Application.routes.draw do resources :users, except: [:new, :index, :create, :destroy] namespace :admin do + resources :organizations resources :users do member do patch :toggle_confirmation @@ -102,7 +103,7 @@ Osem::Application.routes.draw do get '/revision_history/:id/revert_object' => 'versions#revert_object', as: 'revision_history_revert_object' get '/revision_history/:id/revert_attribute' => 'versions#revert_attribute', as: 'revision_history_revert_attribute' end - + resources :organizations resources :conferences, only: [:index, :show] do resource :program, only: [] do resources :proposals, except: :destroy do diff --git a/db/migrate/20170529215453_create_organizations.rb b/db/migrate/20170529215453_create_organizations.rb new file mode 100644 index 00000000..11caf736 --- /dev/null +++ b/db/migrate/20170529215453_create_organizations.rb @@ -0,0 +1,9 @@ +class CreateOrganizations < ActiveRecord::Migration + def change + create_table :organizations do |t| + t.string :name + t.text :description + t.string :picture + end + end +end diff --git a/db/migrate/20170531094817_add_organizaton_id_to_conference.rb b/db/migrate/20170531094817_add_organizaton_id_to_conference.rb new file mode 100644 index 00000000..4397ed7a --- /dev/null +++ b/db/migrate/20170531094817_add_organizaton_id_to_conference.rb @@ -0,0 +1,5 @@ +class AddOrganizatonIdToConference < ActiveRecord::Migration + def change + add_column :conferences, :organization_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 5d74950a..c50e6b45 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170419132148) do +ActiveRecord::Schema.define(version: 20170531094817) do create_table "ahoy_events", force: :cascade do |t| t.uuid "visit_id", limit: 16 @@ -100,6 +100,7 @@ ActiveRecord::Schema.define(version: 20170419132148) do t.string "picture" t.integer "start_hour", default: 9 t.integer "end_hour", default: 20 + t.integer "organization_id" end create_table "conferences_questions", id: false, force: :cascade do |t| @@ -266,6 +267,12 @@ ActiveRecord::Schema.define(version: 20170419132148) do t.datetime "updated_at" end + create_table "organizations", force: :cascade do |t| + t.string "name" + t.text "description" + t.string "picture" + end + create_table "payments", force: :cascade do |t| t.string "last4" t.integer "amount" diff --git a/spec/controllers/admin/organizations_controller_spec.rb b/spec/controllers/admin/organizations_controller_spec.rb new file mode 100644 index 00000000..4635dfdf --- /dev/null +++ b/spec/controllers/admin/organizations_controller_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' + +describe Admin::OrganizationsController do + let(:admin) { create(:admin) } + + describe 'GET #index' do + before :each do + sign_in admin + get :index + end + + it { expect(response).to render_template('index') } + end +end diff --git a/spec/controllers/organizations_controller_spec.rb b/spec/controllers/organizations_controller_spec.rb new file mode 100644 index 00000000..94007630 --- /dev/null +++ b/spec/controllers/organizations_controller_spec.rb @@ -0,0 +1,104 @@ +require 'spec_helper' + +describe OrganizationsController do + let!(:organization) { create(:organization) } + let!(:admin) { create(:admin, is_admin: true) } + + describe 'GET #new' do + before :each do + sign_in admin + get :new + end + + it { expect(response).to render_template('new') } + end + + describe 'GET #index' do + before :each do + sign_in admin + get :index + end + + it { expect(response).to render_template('index') } + end + + describe 'POST #create' do + before :each do + sign_in admin + end + context 'with valid attributes' do + it 'creates new organization' do + expected = expect do + post :create, organization: attributes_for(:organization) + end + expected.to change { Organization.count }.by(1) + end + + it 'redirects to index' do + post :create, organization: attributes_for(:organization) + + expect(flash[:notice]).to eq('Organization successfully created') + expect(response).to redirect_to(organizations_path) + end + end + + context 'with invalid attributes' do + it 'does not create new organization' do + expected = expect do + post :create, organization: attributes_for(:organization, name: '') + end + expected.to_not change { Organization.count } + end + + it 'redirects to new' do + post :create, organization: attributes_for(:organization, name: '') + + expect(flash[:error]).to eq("Name can't be blank") + expect(response).to redirect_to(new_organization_path) + end + end + end + + describe 'PATCH #update' do + before :each do + sign_in admin + end + + it 'saves and redirects to index when the attributes are valid' do + patch :update, id: organization.id, organization: attributes_for(:organization, name: 'changed name') + + expect(organization.name).to eq('changed name') + expect(flash).to eq('Organization successfully updated') + expect(response).to redirect_to(organizations_path) + end + + it 'redirects to edit when attributes are invalid' do + patch :update, id: organization.id, organization: attributes_for(:organization, name: '') + + expect(flash[:error]).to eq("Name can't be blank") + expect(response).to redirect_to(edit_organization_path(organization)) + end + end + + describe 'DELETE #destroy' do + before :each do + sign_in admin + end + + context 'for a valid organization' do + it 'should successfully destroy a resource' do + expected = expect do + delete :destroy, id: organization.id + end + expected.to change { Organization.count }.by(-1) + end + + it 'redirects to index' do + delete :destroy, id: organization.id + + expect(flash[:notice]).to eq('Organization successfully destroyed') + expect(response).to redirect_to(organizations_path) + end + end + end +end diff --git a/spec/factories/conferences.rb b/spec/factories/conferences.rb index 8a9186a6..e1ef7d84 100644 --- a/spec/factories/conferences.rb +++ b/spec/factories/conferences.rb @@ -11,7 +11,7 @@ FactoryGirl.define do end_hour 20 registration_limit 0 description { Faker::Hipster.paragraph } - + organization after(:create) do |conference| Role.where(name: 'organizer', resource: conference).first_or_create(description: 'For the organizers of the conference (who shall have full access)') Role.where(name: 'cfp', resource: conference).first_or_create(description: 'For the members of the CfP team') diff --git a/spec/factories/organizations.rb b/spec/factories/organizations.rb new file mode 100644 index 00000000..0ee76554 --- /dev/null +++ b/spec/factories/organizations.rb @@ -0,0 +1,13 @@ +FactoryGirl.define do + factory :organization do + name { Faker::Company.name } + description { Faker::Lorem.paragraph } + + # after(:create) do |organization| + # File.open("spec/support/logos/#{1 + rand(13)}.png") do |file| + # organization.picture = file + # end + # organization.save! + # end + end +end diff --git a/spec/models/organization_spec.rb b/spec/models/organization_spec.rb new file mode 100644 index 00000000..748205d5 --- /dev/null +++ b/spec/models/organization_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe Organization do + let(:organization) { create(:organization) } + + describe 'validation' do + it 'has a valid factory' do + expect(build(:organization)).to be_valid + end + + it 'is not valid without a name' do + should validate_presence_of(:name) + end + end + + describe 'associations' do + it { should have_many(:conferences).dependent(:destroy) } + end +end From e0d8e85808cadb8f708ed991b019a176d1a8bfbb Mon Sep 17 00:00:00 2001 From: shlok007 Date: Mon, 5 Jun 2017 11:56:47 +0530 Subject: [PATCH 016/237] suggested changes --- .../admin/organizations_controller.rb | 33 ++++++++++++++ app/controllers/organizations_controller.rb | 43 ------------------- app/models/organization.rb | 2 +- app/views/admin/organizations/_form.html.haml | 6 +-- app/views/admin/organizations/index.html.haml | 4 +- .../layouts/_admin_sidebar_index.html.haml | 9 ++-- app/views/layouts/_user_menu.html.haml | 9 ++-- app/views/organizations/_form.html.haml | 13 ------ app/views/organizations/edit.html.haml | 4 -- app/views/organizations/index.html.haml | 5 +-- app/views/organizations/new.html.haml | 4 -- 11 files changed, 51 insertions(+), 81 deletions(-) delete mode 100644 app/views/organizations/_form.html.haml delete mode 100644 app/views/organizations/edit.html.haml delete mode 100644 app/views/organizations/new.html.haml diff --git a/app/controllers/admin/organizations_controller.rb b/app/controllers/admin/organizations_controller.rb index 1dc6bcd5..087bf7f8 100644 --- a/app/controllers/admin/organizations_controller.rb +++ b/app/controllers/admin/organizations_controller.rb @@ -6,6 +6,33 @@ module Admin @organizations = Organization.all end + def create + @organization = Organization.new(organization_params) + if @organization.save + redirect_to admin_organizations_path, + notice: 'Organization successfully created' + else + redirect_to new_admin_organization_path, + error: @organization.errors.full_messages.join(', ') + end + end + + def new + @organization = Organization.new + end + + def edit; end + + def update + if @organization.update_attributes(organization_params) + redirect_to admin_organizations_path, + notice: 'Organization successfully updated' + else + redirect_to edit_admin_organization_path(@organization), + error: @organization.errors.full_messages.join(', ') + end + end + def destroy if @organization.destroy redirect_to admin_organizations_path, @@ -15,5 +42,11 @@ module Admin error: 'Organization cannot be destroyed' end end + + private + + def organization_params + params.require(:organization).permit(:name, :description, :picture) + end end end diff --git a/app/controllers/organizations_controller.rb b/app/controllers/organizations_controller.rb index 58910526..3d549dfa 100644 --- a/app/controllers/organizations_controller.rb +++ b/app/controllers/organizations_controller.rb @@ -4,47 +4,4 @@ class OrganizationsController < ApplicationController def index @organizations = Organization.all end - - def create - @organization = Organization.new(organization_params) - if @organization.save - redirect_to organizations_path, - notice: 'Organization successfully created' - else - redirect_to new_organization_path, - error: @organization.errors.full_messages.join(', ') - end - end - - def new - @organization = Organization.new - end - - def edit; end - - def update - if @organization.update_attributes(organization_params) - redirect_to organizations_path, - notice: 'Organization successfully updated' - else - redirect_to edit_organization_path(@organization), - error: @organization.errors.full_messages.join(', ') - end - end - - def destroy - if @organization.destroy - redirect_to organizations_path, - notice: 'Organization successfully destroyed' - else - redirect_to organizations_path, - error: 'Organization cannot be destroyed' - end - end - - private - - def organization_params - params.require(:organization).permit(:name, :description, :picture) - end end diff --git a/app/models/organization.rb b/app/models/organization.rb index 60a83fef..15362d7a 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -1,5 +1,5 @@ class Organization < ActiveRecord::Base - has_many :conferences, dependent: :destroy + has_many :conferences validates :name, presence: true diff --git a/app/views/admin/organizations/_form.html.haml b/app/views/admin/organizations/_form.html.haml index c41f0cff..c83facbb 100644 --- a/app/views/admin/organizations/_form.html.haml +++ b/app/views/admin/organizations/_form.html.haml @@ -1,7 +1,7 @@ -= semantic_form_for(@organization) do |f| += semantic_form_for(@organization, url: (@organization.new_record? ? admin_organizations_path : admin_organization_path(@organization))) do |f| = f.inputs name: 'Organization details' do = f.input :name, as: :string, required: true - = f.input :description, input_html: { rows: 5 }, placeholder: 'Decribe about your organization..' + = f.input :description, as: :text, input_html: { rows: 10 }, placeholder: 'Decribe about your organization..' = image_tag f.object.picture.thumb.url if f.object.picture? - if @organization.picture = image_tag(@organization.picture.thumb.url, width: '20%') @@ -10,4 +10,4 @@ - if @organization.new_record? = f.submit 'Create Organization', class: 'btn btn-success' - else - = f.submit 'Update Organization', class: 'btn btn-success' \ No newline at end of file + = f.submit 'Update Organization', class: 'btn btn-success' diff --git a/app/views/admin/organizations/index.html.haml b/app/views/admin/organizations/index.html.haml index 0a751460..f0a8c3c7 100644 --- a/app/views/admin/organizations/index.html.haml +++ b/app/views/admin/organizations/index.html.haml @@ -25,7 +25,7 @@ = organization.conferences.count %td .btn-group - = link_to 'Edit', edit_organization_path(organization), + = link_to 'Edit', edit_admin_organization_path(organization), method: :get, class: 'btn btn-primary' = link_to 'Delete', admin_organization_path(organization), - method: :delete, class: 'btn btn-danger' + method: :delete, class: 'btn btn-danger', data: { confirm: "Warning: This will delete #{organization.name} and all its data which includes data for all conferences within #{organization.name}. Do you really want to continue?" } diff --git a/app/views/layouts/_admin_sidebar_index.html.haml b/app/views/layouts/_admin_sidebar_index.html.haml index f1cf8b75..3844339b 100644 --- a/app/views/layouts/_admin_sidebar_index.html.haml +++ b/app/views/layouts/_admin_sidebar_index.html.haml @@ -32,7 +32,8 @@ = link_to(admin_revision_history_path) do %span.fa.fa-history Revision History - %li - = link_to(admin_organizations_path) do - %span.fa.fa-group - Organizations + - if ENV['ORGANIZATIONS_ENABLED'] == 'true' + %li + = link_to(admin_organizations_path) do + %span.fa.fa-group + Organizations diff --git a/app/views/layouts/_user_menu.html.haml b/app/views/layouts/_user_menu.html.haml index 14d32fed..01432b3c 100644 --- a/app/views/layouts/_user_menu.html.haml +++ b/app/views/layouts/_user_menu.html.haml @@ -49,7 +49,8 @@ = link_to(admin_revision_history_path) do %span.fa.fa-history Revision History - %li - = link_to(admin_organizations_path) do - %span.fa.fa-group - Organizations + - if ENV['ORGANIZATIONS_ENABLED'] == 'true' + %li + = link_to(admin_organizations_path) do + %span.fa.fa-group + Organizations diff --git a/app/views/organizations/_form.html.haml b/app/views/organizations/_form.html.haml deleted file mode 100644 index c41f0cff..00000000 --- a/app/views/organizations/_form.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -= semantic_form_for(@organization) do |f| - = f.inputs name: 'Organization details' do - = f.input :name, as: :string, required: true - = f.input :description, input_html: { rows: 5 }, placeholder: 'Decribe about your organization..' - = image_tag f.object.picture.thumb.url if f.object.picture? - - if @organization.picture - = image_tag(@organization.picture.thumb.url, width: '20%') - = f.input :picture - %p.text-right - - if @organization.new_record? - = f.submit 'Create Organization', class: 'btn btn-success' - - else - = f.submit 'Update Organization', class: 'btn btn-success' \ No newline at end of file diff --git a/app/views/organizations/edit.html.haml b/app/views/organizations/edit.html.haml deleted file mode 100644 index 1f65d485..00000000 --- a/app/views/organizations/edit.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -.container - .row - .col-md-12 - = render 'form' diff --git a/app/views/organizations/index.html.haml b/app/views/organizations/index.html.haml index b87f156b..b2794bd8 100644 --- a/app/views/organizations/index.html.haml +++ b/app/views/organizations/index.html.haml @@ -4,7 +4,7 @@ %h1 Organizations .btn-group.pull-right - = link_to 'Add new', new_organization_path, class: 'btn btn-mini btn-success' + / = link_to 'Add new', new_organization_path, class: 'btn btn-mini btn-success' - @organizations.each do |organization| .col-md-4 .thumbnail @@ -13,5 +13,4 @@ %h4 = organization.name %button.btn.btn-success Conferences - = link_to 'Edit', edit_organization_path(organization), class: 'btn btn-mini btn-default' - + / = link_to 'Edit', edit_organization_path(organization), class: 'btn btn-mini btn-default' diff --git a/app/views/organizations/new.html.haml b/app/views/organizations/new.html.haml deleted file mode 100644 index 1f65d485..00000000 --- a/app/views/organizations/new.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -.container - .row - .col-md-12 - = render 'form' From ac85bad9b3066f05791edf98adfdf91cda80ba37 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Mon, 5 Jun 2017 11:59:27 +0530 Subject: [PATCH 017/237] migrate conferences to organizations --- ...094817_add_organizaton_id_to_conference.rb | 5 ----- ...94819_move_conferences_to_organizations.rb | 21 +++++++++++++++++++ db/schema.rb | 4 +++- 3 files changed, 24 insertions(+), 6 deletions(-) delete mode 100644 db/migrate/20170531094817_add_organizaton_id_to_conference.rb create mode 100644 db/migrate/20170531094819_move_conferences_to_organizations.rb diff --git a/db/migrate/20170531094817_add_organizaton_id_to_conference.rb b/db/migrate/20170531094817_add_organizaton_id_to_conference.rb deleted file mode 100644 index 4397ed7a..00000000 --- a/db/migrate/20170531094817_add_organizaton_id_to_conference.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddOrganizatonIdToConference < ActiveRecord::Migration - def change - add_column :conferences, :organization_id, :integer - end -end diff --git a/db/migrate/20170531094819_move_conferences_to_organizations.rb b/db/migrate/20170531094819_move_conferences_to_organizations.rb new file mode 100644 index 00000000..80c2ebd6 --- /dev/null +++ b/db/migrate/20170531094819_move_conferences_to_organizations.rb @@ -0,0 +1,21 @@ +class MoveConferencesToOrganizations < ActiveRecord::Migration + class TempConference < ActiveRecord::Base + self.table_name = 'conferences' + end + + class TempOrganization < ActiveRecord::Base + self.table_name = 'organizations' + end + + def change + add_reference :conferences, :organization, index: true + add_foreign_key :conferences, :organizations, dependent: :delete + + TempConference.reset_column_information + organization = TempOrganization.create(name: 'organization', description: 'Default organization to migrate old conferences to the new version of OSEM') + TempConference.all.each do |conference| + conference.organization_id = organization.id + conference.save! + end + end +end diff --git a/db/schema.rb b/db/schema.rb index c50e6b45..7db5faa0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170531094817) do +ActiveRecord::Schema.define(version: 20170531094819) do create_table "ahoy_events", force: :cascade do |t| t.uuid "visit_id", limit: 16 @@ -103,6 +103,8 @@ ActiveRecord::Schema.define(version: 20170531094817) do t.integer "organization_id" end + add_index "conferences", ["organization_id"], name: "index_conferences_on_organization_id" + create_table "conferences_questions", id: false, force: :cascade do |t| t.integer "conference_id" t.integer "question_id" From 3fb316482c92d5c140c1aa0806cc02c0ddbb8a1e Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 6 Jun 2017 20:04:39 +0530 Subject: [PATCH 018/237] suggested changes --- app/models/ability.rb | 1 + app/models/organization.rb | 2 +- app/views/admin/organizations/index.html.haml | 2 +- config/routes.rb | 2 +- .../20170529215453_create_organizations.rb | 2 +- ...94819_move_conferences_to_organizations.rb | 13 +- db/schema.rb | 2 +- .../admin/organizations_controller_spec.rb | 165 +++++++++++++++++- .../organizations_controller_spec.rb | 93 +--------- spec/models/organization_spec.rb | 4 - 10 files changed, 176 insertions(+), 110 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index ff1628a1..dba29fa7 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -83,6 +83,7 @@ class Ability conference.registration_open? && !conference.registration_limit_exceeded? || conference.program.speakers.confirmed.include?(user) end + can :index, Organization can :index, Ticket can :manage, TicketPurchase, user_id: user.id can [:new, :create], Payment, user_id: user.id diff --git a/app/models/organization.rb b/app/models/organization.rb index 15362d7a..60a83fef 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -1,5 +1,5 @@ class Organization < ActiveRecord::Base - has_many :conferences + has_many :conferences, dependent: :destroy validates :name, presence: true diff --git a/app/views/admin/organizations/index.html.haml b/app/views/admin/organizations/index.html.haml index f0a8c3c7..03bf11f9 100644 --- a/app/views/admin/organizations/index.html.haml +++ b/app/views/admin/organizations/index.html.haml @@ -3,7 +3,7 @@ .page-header %h1 Organizations .btn-group.pull-right - = link_to 'Add Organization', new_admin_organization_path, class: 'btn btn-success pull-right' + = link_to 'Create Organization', new_admin_organization_path, class: 'btn btn-success pull-right' %p.text-muted Manage organizations in OSEM .row diff --git a/config/routes.rb b/config/routes.rb index e2cfe7f7..b10d5d9c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -103,7 +103,7 @@ Osem::Application.routes.draw do get '/revision_history/:id/revert_object' => 'versions#revert_object', as: 'revision_history_revert_object' get '/revision_history/:id/revert_attribute' => 'versions#revert_attribute', as: 'revision_history_revert_attribute' end - resources :organizations + resources :organizations, only: [:index] resources :conferences, only: [:index, :show] do resource :program, only: [] do resources :proposals, except: :destroy do diff --git a/db/migrate/20170529215453_create_organizations.rb b/db/migrate/20170529215453_create_organizations.rb index 11caf736..0fa5450b 100644 --- a/db/migrate/20170529215453_create_organizations.rb +++ b/db/migrate/20170529215453_create_organizations.rb @@ -1,7 +1,7 @@ class CreateOrganizations < ActiveRecord::Migration def change create_table :organizations do |t| - t.string :name + t.string :name, null: false t.text :description t.string :picture end diff --git a/db/migrate/20170531094819_move_conferences_to_organizations.rb b/db/migrate/20170531094819_move_conferences_to_organizations.rb index 80c2ebd6..12bc7580 100644 --- a/db/migrate/20170531094819_move_conferences_to_organizations.rb +++ b/db/migrate/20170531094819_move_conferences_to_organizations.rb @@ -8,14 +8,15 @@ class MoveConferencesToOrganizations < ActiveRecord::Migration end def change - add_reference :conferences, :organization, index: true - add_foreign_key :conferences, :organizations, dependent: :delete + add_reference :conferences, :organization, index: true, foreign_key: true TempConference.reset_column_information - organization = TempOrganization.create(name: 'organization', description: 'Default organization to migrate old conferences to the new version of OSEM') - TempConference.all.each do |conference| - conference.organization_id = organization.id - conference.save! + if TempConference.count != 0 + organization = TempOrganization.create(name: 'organization', description: 'Default organization') + TempConference.all.each do |conference| + conference.organization_id = organization.id + conference.save! + end end end end diff --git a/db/schema.rb b/db/schema.rb index 7db5faa0..9772066a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -270,7 +270,7 @@ ActiveRecord::Schema.define(version: 20170531094819) do end create_table "organizations", force: :cascade do |t| - t.string "name" + t.string "name", null: false t.text "description" t.string "picture" end diff --git a/spec/controllers/admin/organizations_controller_spec.rb b/spec/controllers/admin/organizations_controller_spec.rb index 4635dfdf..43f7266f 100644 --- a/spec/controllers/admin/organizations_controller_spec.rb +++ b/spec/controllers/admin/organizations_controller_spec.rb @@ -2,13 +2,170 @@ require 'spec_helper' describe Admin::OrganizationsController do let(:admin) { create(:admin) } + let(:organization) { create(:organization) } + let(:user) { create(:user) } - describe 'GET #index' do + context 'logged in as user with no role' do before :each do - sign_in admin - get :index + sign_in user end - it { expect(response).to render_template('index') } + describe 'GET #new' do + before :each do + get :new + end + + it 'redirects to root' do + expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(response).to redirect_to(root_path) + end + end + + describe 'GET #index' do + before :each do + get :index + end + + it 'redirects to root' do + expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(response).to redirect_to(root_path) + end + end + + describe 'POST #create' do + it 'does not create new organization' do + expected = expect do + post :create, organization: attributes_for(:organization) + end + expected.to_not change { Organization.count } + end + + it 'redirects to root' do + post :create, organization: attributes_for(:organization) + + expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(response).to redirect_to(root_path) + end + end + + describe 'PATCH #update' do + it 'does not update and redirects to root' do + old_name = organization.name + patch :update, id: organization.id, organization: attributes_for(:organization, name: 'new name') + + organization.reload + expect(organization.name).to eq(old_name) + expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(response).to redirect_to(root_path) + end + end + + describe 'DELETE #destroy' do + context 'for a valid organization' do + it 'does not destroy a resource' do + expected = expect do + delete :destroy, id: organization.id + end + expected.to_not change { Organization.count } + end + + it 'redirects to root' do + delete :destroy, id: organization.id + + expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(response).to redirect_to(root_path) + end + end + end + end + + context 'logged in as admin' do + before :each do + sign_in admin + end + + describe 'GET #new' do + before do + get :new + end + it { expect(response).to render_template('new') } + end + + describe 'GET #index' do + before do + get :index + end + it { expect(response).to render_template('index') } + end + + describe 'POST #create' do + context 'with valid attributes' do + it 'creates new organization' do + expected = expect do + post :create, organization: attributes_for(:organization) + end + expected.to change { Organization.count }.by(1) + end + + it 'redirects to index' do + post :create, organization: attributes_for(:organization) + + expect(flash[:notice]).to eq('Organization successfully created') + expect(response).to redirect_to(admin_organizations_path) + end + end + + context 'with invalid attributes' do + it 'does not create new organization' do + expected = expect do + post :create, organization: attributes_for(:organization, name: '') + end + expected.to_not change { Organization.count } + end + + it 'redirects to new' do + post :create, organization: attributes_for(:organization, name: '') + + expect(flash[:error]).to eq("Name can't be blank") + expect(response).to redirect_to(new_admin_organization_path) + end + end + end + + describe 'PATCH #update' do + it 'saves and redirects to index when the attributes are valid' do + patch :update, id: organization.id, organization: attributes_for(:organization, name: 'changed name') + + organization.reload + expect(organization.name).to eq('changed name') + expect(flash[:notice]).to eq('Organization successfully updated') + expect(response).to redirect_to(admin_organizations_path) + end + + it 'redirects to edit when attributes are invalid' do + patch :update, id: organization.id, organization: attributes_for(:organization, name: '') + + expect(flash[:error]).to eq("Name can't be blank") + expect(response).to redirect_to(edit_admin_organization_path(organization)) + end + end + + describe 'DELETE #destroy' do + context 'for a valid organization' do + it 'should successfully destroy a resource' do + expected = expect do + delete :destroy, id: organization.id + end + expected.to change { Organization.count }.by(-1) + end + + it 'redirects to index' do + delete :destroy, id: organization.id + + expect(flash[:notice]).to eq('Organization successfully destroyed') + expect(response).to redirect_to(admin_organizations_path) + end + end + end end end diff --git a/spec/controllers/organizations_controller_spec.rb b/spec/controllers/organizations_controller_spec.rb index 94007630..2916fdea 100644 --- a/spec/controllers/organizations_controller_spec.rb +++ b/spec/controllers/organizations_controller_spec.rb @@ -2,103 +2,14 @@ require 'spec_helper' describe OrganizationsController do let!(:organization) { create(:organization) } - let!(:admin) { create(:admin, is_admin: true) } - - describe 'GET #new' do - before :each do - sign_in admin - get :new - end - - it { expect(response).to render_template('new') } - end + let!(:user) { create(:user) } describe 'GET #index' do before :each do - sign_in admin + sign_in user get :index end it { expect(response).to render_template('index') } end - - describe 'POST #create' do - before :each do - sign_in admin - end - context 'with valid attributes' do - it 'creates new organization' do - expected = expect do - post :create, organization: attributes_for(:organization) - end - expected.to change { Organization.count }.by(1) - end - - it 'redirects to index' do - post :create, organization: attributes_for(:organization) - - expect(flash[:notice]).to eq('Organization successfully created') - expect(response).to redirect_to(organizations_path) - end - end - - context 'with invalid attributes' do - it 'does not create new organization' do - expected = expect do - post :create, organization: attributes_for(:organization, name: '') - end - expected.to_not change { Organization.count } - end - - it 'redirects to new' do - post :create, organization: attributes_for(:organization, name: '') - - expect(flash[:error]).to eq("Name can't be blank") - expect(response).to redirect_to(new_organization_path) - end - end - end - - describe 'PATCH #update' do - before :each do - sign_in admin - end - - it 'saves and redirects to index when the attributes are valid' do - patch :update, id: organization.id, organization: attributes_for(:organization, name: 'changed name') - - expect(organization.name).to eq('changed name') - expect(flash).to eq('Organization successfully updated') - expect(response).to redirect_to(organizations_path) - end - - it 'redirects to edit when attributes are invalid' do - patch :update, id: organization.id, organization: attributes_for(:organization, name: '') - - expect(flash[:error]).to eq("Name can't be blank") - expect(response).to redirect_to(edit_organization_path(organization)) - end - end - - describe 'DELETE #destroy' do - before :each do - sign_in admin - end - - context 'for a valid organization' do - it 'should successfully destroy a resource' do - expected = expect do - delete :destroy, id: organization.id - end - expected.to change { Organization.count }.by(-1) - end - - it 'redirects to index' do - delete :destroy, id: organization.id - - expect(flash[:notice]).to eq('Organization successfully destroyed') - expect(response).to redirect_to(organizations_path) - end - end - end end diff --git a/spec/models/organization_spec.rb b/spec/models/organization_spec.rb index 748205d5..ca84f532 100644 --- a/spec/models/organization_spec.rb +++ b/spec/models/organization_spec.rb @@ -4,10 +4,6 @@ describe Organization do let(:organization) { create(:organization) } describe 'validation' do - it 'has a valid factory' do - expect(build(:organization)).to be_valid - end - it 'is not valid without a name' do should validate_presence_of(:name) end From cce3ff7aea589d18d4da96acda3341afbaf024a3 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 7 Jun 2017 11:11:29 +0530 Subject: [PATCH 019/237] creating default organization while creating a conference --- app/controllers/admin/conferences_controller.rb | 14 +++++++++++--- app/views/admin/conferences/new.html.haml | 2 ++ spec/models/conference_spec.rb | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index f9e1177d..c6d54f04 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -72,11 +72,19 @@ module Admin def new @conference = Conference.new + @organizations = {} + Organization.all.each do |organization| + @organizations.store(organization.name, organization.id) if can? :create, Conference.new(organization: organization) + end end def create - @conference = Conference.new(conference_params) - + conference_params_copy = conference_params + if ENV['ORGANIZATIONS_ENABLED'] != 'true' + org = Organization.exists?(name: 'default') ? Organization.find_by(name: 'default') : Organization.create(name: 'default') + conference_params_copy[:organization_id] = org.id + end + @conference = Conference.new(conference_params_copy) if @conference.save # user that creates the conference becomes organizer of that conference current_user.add_role :organizer, @conference @@ -211,7 +219,7 @@ module Admin :vpositions_attributes, :use_volunteers, :color, :sponsorship_levels_attributes, :sponsors_attributes, :targets, :targets_attributes, - :campaigns, :campaigns_attributes, :registration_limit) + :campaigns, :campaigns_attributes, :registration_limit, :organization_id) end end end diff --git a/app/views/admin/conferences/new.html.haml b/app/views/admin/conferences/new.html.haml index 014758de..7f414563 100644 --- a/app/views/admin/conferences/new.html.haml +++ b/app/views/admin/conferences/new.html.haml @@ -6,6 +6,8 @@ input_html: { required: 'required' } = f.input :short_title, hint: "A short and unique handle for your conference, using only letters, numbers, underscores, and dashes. This will be used to identify your conference in URLs etc. Example: 'froscon2011'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' }, prepend: conferences_url + '/' + - if ENV['ORGANIZATIONS_ENABLED'] == 'true' + = f.input :organization, as: :select, collection: @organizations = f.inputs 'Scheduling' do = f.input :timezone, as: :time_zone, default: Time.zone.name, hint: 'Please select in what time zone your conference will take place.' = f.input :start_date, as: :string, input_html: { id: 'conference-start-datepicker', required: 'required' } diff --git a/spec/models/conference_spec.rb b/spec/models/conference_spec.rb index b5a6d5f0..9bdbea83 100755 --- a/spec/models/conference_spec.rb +++ b/spec/models/conference_spec.rb @@ -1630,7 +1630,7 @@ describe Conference do end describe 'after_create' do - let(:conference) { Conference.new(title: 'ABC', short_title: 'XYZ', start_date: Date.today, end_date: Date.today + 10, timezone: 'GMT') } + let(:conference) { create(:conference) } it 'calls back to create free ticket' do conference.save From 949f5cb591468e2053bdbc44f29ee659d14e915e Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 7 Jun 2017 12:37:30 +0530 Subject: [PATCH 020/237] add foreign key to conferences --- .../20170531094819_move_conferences_to_organizations.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/db/migrate/20170531094819_move_conferences_to_organizations.rb b/db/migrate/20170531094819_move_conferences_to_organizations.rb index 12bc7580..e70acf16 100644 --- a/db/migrate/20170531094819_move_conferences_to_organizations.rb +++ b/db/migrate/20170531094819_move_conferences_to_organizations.rb @@ -8,7 +8,7 @@ class MoveConferencesToOrganizations < ActiveRecord::Migration end def change - add_reference :conferences, :organization, index: true, foreign_key: true + add_reference :conferences, :organization, index: true TempConference.reset_column_information if TempConference.count != 0 @@ -18,5 +18,7 @@ class MoveConferencesToOrganizations < ActiveRecord::Migration conference.save! end end + + add_foreign_key :conferences, :organizations, null: false, on_delete: :cascade end end From b29856a1222f5158f9e4e87ccfb9d366ace260b5 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 7 Jun 2017 14:14:42 +0530 Subject: [PATCH 021/237] suggested changes --- app/controllers/admin/conferences_controller.rb | 9 +++------ app/views/admin/conferences/new.html.haml | 2 -- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index c6d54f04..0ff0289d 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -79,12 +79,9 @@ module Admin end def create - conference_params_copy = conference_params - if ENV['ORGANIZATIONS_ENABLED'] != 'true' - org = Organization.exists?(name: 'default') ? Organization.find_by(name: 'default') : Organization.create(name: 'default') - conference_params_copy[:organization_id] = org.id - end - @conference = Conference.new(conference_params_copy) + org = Organization.find_or_create_by(name: 'organization') + @conference = Conference.new(conference_params) + @conference.organization = org if @conference.save # user that creates the conference becomes organizer of that conference current_user.add_role :organizer, @conference diff --git a/app/views/admin/conferences/new.html.haml b/app/views/admin/conferences/new.html.haml index 7f414563..014758de 100644 --- a/app/views/admin/conferences/new.html.haml +++ b/app/views/admin/conferences/new.html.haml @@ -6,8 +6,6 @@ input_html: { required: 'required' } = f.input :short_title, hint: "A short and unique handle for your conference, using only letters, numbers, underscores, and dashes. This will be used to identify your conference in URLs etc. Example: 'froscon2011'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' }, prepend: conferences_url + '/' - - if ENV['ORGANIZATIONS_ENABLED'] == 'true' - = f.input :organization, as: :select, collection: @organizations = f.inputs 'Scheduling' do = f.input :timezone, as: :time_zone, default: Time.zone.name, hint: 'Please select in what time zone your conference will take place.' = f.input :start_date, as: :string, input_html: { id: 'conference-start-datepicker', required: 'required' } From 521c05af61d7533371bff03930fc145b13be045a Mon Sep 17 00:00:00 2001 From: shlok007 Date: Fri, 9 Jun 2017 04:35:16 +0530 Subject: [PATCH 022/237] skip failing tests --- .haml-lint_todo.yml | 45 +++++++------ .../admin/organizations_controller_spec.rb | 64 +++++++++---------- 2 files changed, 54 insertions(+), 55 deletions(-) diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 2c51e966..918178e2 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `haml-lint --auto-gen-config` -# on 2017-04-25 04:36:49 +0530 using Haml-Lint version 0.24.0. +# on 2017-06-09 04:02:20 +0530 using Haml-Lint version 0.24.0. # The point is for the user to remove these configuration records # one by one as the lints are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -8,7 +8,7 @@ linters: - # Offense count: 952 + # Offense count: 945 LineLength: exclude: - "app/views/admin/campaigns/_form.html.haml" @@ -49,10 +49,11 @@ linters: - "app/views/admin/events/_voting_index.html.haml" - "app/views/admin/events/index.html.haml" - "app/views/admin/events/registrations.html.haml" - - "app/views/admin/events/reports.html.haml" - "app/views/admin/events/show.html.haml" - "app/views/admin/lodgings/_form.html.haml" - "app/views/admin/lodgings/index.html.haml" + - "app/views/admin/organizations/_form.html.haml" + - "app/views/admin/organizations/index.html.haml" - "app/views/admin/programs/_form.html.haml" - "app/views/admin/programs/show.html.haml" - "app/views/admin/questions/_form.html.haml" @@ -144,6 +145,7 @@ linters: - "app/views/layouts/_messages.html.haml" - "app/views/layouts/_navigation.html.haml" - "app/views/layouts/application.html.haml" + - "app/views/organizations/index.html.haml" - "app/views/payments/_payment.html.haml" - "app/views/proposals/_form.html.haml" - "app/views/proposals/_proposal_form.html.haml" @@ -170,7 +172,7 @@ linters: - "app/views/users/edit.html.haml" - "app/views/users/show.html.haml" - # Offense count: 222 + # Offense count: 223 InstanceVariables: exclude: - "app/views/admin/campaigns/_form.html.haml" @@ -184,6 +186,7 @@ linters: - "app/views/admin/events/_voting.html.haml" - "app/views/admin/events/_voting_index.html.haml" - "app/views/admin/lodgings/_form.html.haml" + - "app/views/admin/organizations/_form.html.haml" - "app/views/admin/questions/_questions.html.haml" - "app/views/admin/registration_periods/_form.html.haml" - "app/views/admin/reports/_all_events.html.haml" @@ -245,14 +248,11 @@ linters: - "app/views/admin/users/show.html.haml" - "app/views/users/edit.html.haml" - # Offense count: 8 + # Offense count: 4 UnnecessaryInterpolation: exclude: - "app/views/admin/conferences/_doughnut_chart.html.haml" - "app/views/admin/conferences/_recent_submissions.html.haml" - - "app/views/admin/events/reports.html.haml" - - "app/views/admin/reports/_events_with_requirements.html.haml" - - "app/views/admin/reports/_events_without_commercials.html.haml" - "app/views/proposals/_proposal_form.html.haml" - "app/views/proposals/new.html.haml" @@ -328,11 +328,10 @@ linters: - "app/views/tickets/_ticket.html.haml" - "app/views/tickets/index.html.haml" - # Offense count: 27 + # Offense count: 23 ClassesBeforeIds: exclude: - "app/views/admin/emails/index.html.haml" - - "app/views/admin/events/reports.html.haml" - "app/views/admin/events/show.html.haml" - "app/views/admin/reports/index.html.haml" - "app/views/admin/users/show.html.haml" @@ -386,6 +385,19 @@ linters: - "app/views/admin/versions/_object_desc_and_link.html.haml" - "app/views/schedules/_carousel.html.haml" + # Offense count: 29 + TrailingWhitespace: + exclude: + - "app/views/admin/organizations/_form.html.haml" + - "app/views/admin/users/index.html.haml" + - "app/views/admin/users/show.html.haml" + - "app/views/admin/volunteers/index.html.haml" + - "app/views/admin/volunteers/show.html.haml" + - "app/views/conference_registrations/_volunteer.html.haml" + - "app/views/devise/passwords/new.html.haml" + - "app/views/payments/new.html.haml" + - "app/views/tickets/index.html.haml" + # Offense count: 2 FinalNewline: exclude: @@ -406,19 +418,6 @@ linters: - "app/views/schedules/_event.html.haml" - "app/views/schedules/_schedule_item.html.haml" - # Offense count: 38 - TrailingWhitespace: - exclude: - - "app/views/admin/users/_form.html.haml" - - "app/views/admin/users/index.html.haml" - - "app/views/admin/users/show.html.haml" - - "app/views/admin/volunteers/index.html.haml" - - "app/views/admin/volunteers/show.html.haml" - - "app/views/conference_registrations/_volunteer.html.haml" - - "app/views/devise/passwords/new.html.haml" - - "app/views/payments/new.html.haml" - - "app/views/tickets/index.html.haml" - # Offense count: 7 ClassAttributeWithStaticValue: exclude: diff --git a/spec/controllers/admin/organizations_controller_spec.rb b/spec/controllers/admin/organizations_controller_spec.rb index 43f7266f..14423cbd 100644 --- a/spec/controllers/admin/organizations_controller_spec.rb +++ b/spec/controllers/admin/organizations_controller_spec.rb @@ -37,7 +37,7 @@ describe Admin::OrganizationsController do expected = expect do post :create, organization: attributes_for(:organization) end - expected.to_not change { Organization.count } + expected.to_not change(Organization, :count) end it 'redirects to root' do @@ -60,23 +60,23 @@ describe Admin::OrganizationsController do end end - describe 'DELETE #destroy' do - context 'for a valid organization' do - it 'does not destroy a resource' do - expected = expect do - delete :destroy, id: organization.id - end - expected.to_not change { Organization.count } - end + # describe 'DELETE #destroy' do + # context 'for a valid organization' do + # it 'does not destroy a resource' do + # expected = expect do + # delete :destroy, id: organization.id + # end + # expected.to_not change { Organization.count } + # end - it 'redirects to root' do - delete :destroy, id: organization.id + # it 'redirects to root' do + # delete :destroy, id: organization.id - expect(flash[:alert]).to eq('You are not authorized to access this area!') - expect(response).to redirect_to(root_path) - end - end - end + # expect(flash[:alert]).to eq('You are not authorized to access this area!') + # expect(response).to redirect_to(root_path) + # end + # end + # end end context 'logged in as admin' do @@ -120,7 +120,7 @@ describe Admin::OrganizationsController do expected = expect do post :create, organization: attributes_for(:organization, name: '') end - expected.to_not change { Organization.count } + expected.to_not change(Organization, :count) end it 'redirects to new' do @@ -150,22 +150,22 @@ describe Admin::OrganizationsController do end end - describe 'DELETE #destroy' do - context 'for a valid organization' do - it 'should successfully destroy a resource' do - expected = expect do - delete :destroy, id: organization.id - end - expected.to change { Organization.count }.by(-1) - end + # describe 'DELETE #destroy' do + # context 'for a valid organization' do + # it 'should successfully destroy a resource' do + # expected = expect do + # delete :destroy, id: organization.id + # end + # expected.to change { Organization.count }.by(-1) + # end - it 'redirects to index' do - delete :destroy, id: organization.id + # it 'redirects to index' do + # delete :destroy, id: organization.id - expect(flash[:notice]).to eq('Organization successfully destroyed') - expect(response).to redirect_to(admin_organizations_path) - end - end - end + # expect(flash[:notice]).to eq('Organization successfully destroyed') + # expect(response).to redirect_to(admin_organizations_path) + # end + # end + # end end end From 6cf9ddbdea7c54f901a3b10382ca81f9da82f94b Mon Sep 17 00:00:00 2001 From: shlok007 Date: Sat, 10 Jun 2017 19:17:50 +0530 Subject: [PATCH 023/237] fix failing test --- .../admin/organizations_controller_spec.rb | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/spec/controllers/admin/organizations_controller_spec.rb b/spec/controllers/admin/organizations_controller_spec.rb index 14423cbd..a4afc994 100644 --- a/spec/controllers/admin/organizations_controller_spec.rb +++ b/spec/controllers/admin/organizations_controller_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe Admin::OrganizationsController do - let(:admin) { create(:admin) } - let(:organization) { create(:organization) } - let(:user) { create(:user) } + let!(:admin) { create(:admin) } + let!(:organization) { create(:organization) } + let!(:user) { create(:user) } context 'logged in as user with no role' do before :each do @@ -60,23 +60,23 @@ describe Admin::OrganizationsController do end end - # describe 'DELETE #destroy' do - # context 'for a valid organization' do - # it 'does not destroy a resource' do - # expected = expect do - # delete :destroy, id: organization.id - # end - # expected.to_not change { Organization.count } - # end + describe 'DELETE #destroy' do + context 'for a valid organization' do + it 'does not destroy a resource' do + expected = expect do + delete :destroy, id: organization.id + end + expected.to_not change(Organization, :count) + end - # it 'redirects to root' do - # delete :destroy, id: organization.id + it 'redirects to root' do + delete :destroy, id: organization.id - # expect(flash[:alert]).to eq('You are not authorized to access this area!') - # expect(response).to redirect_to(root_path) - # end - # end - # end + expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(response).to redirect_to(root_path) + end + end + end end context 'logged in as admin' do @@ -150,22 +150,22 @@ describe Admin::OrganizationsController do end end - # describe 'DELETE #destroy' do - # context 'for a valid organization' do - # it 'should successfully destroy a resource' do - # expected = expect do - # delete :destroy, id: organization.id - # end - # expected.to change { Organization.count }.by(-1) - # end + describe 'DELETE #destroy' do + context 'for a valid organization' do + it 'should successfully destroy a resource' do + expected = expect do + delete :destroy, id: organization.id + end + expected.to change { Organization.count }.by(-1) + end - # it 'redirects to index' do - # delete :destroy, id: organization.id + it 'redirects to index' do + delete :destroy, id: organization.id - # expect(flash[:notice]).to eq('Organization successfully destroyed') - # expect(response).to redirect_to(admin_organizations_path) - # end - # end - # end + expect(flash[:notice]).to eq('Organization successfully destroyed') + expect(response).to redirect_to(admin_organizations_path) + end + end + end end end From cc5d47e6de5812eb3c5bf4339e75f5f8620f089f Mon Sep 17 00:00:00 2001 From: shlok007 Date: Sat, 10 Jun 2017 19:36:50 +0530 Subject: [PATCH 024/237] suggested changes --- app/controllers/admin/conferences_controller.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index 0ff0289d..f8c9ea19 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -72,16 +72,11 @@ module Admin def new @conference = Conference.new - @organizations = {} - Organization.all.each do |organization| - @organizations.store(organization.name, organization.id) if can? :create, Conference.new(organization: organization) - end end def create - org = Organization.find_or_create_by(name: 'organization') @conference = Conference.new(conference_params) - @conference.organization = org + @conference.organization = Organization.find_or_create_by(name: 'organization') if @conference.save # user that creates the conference becomes organizer of that conference current_user.add_role :organizer, @conference From be72b9d02ebde2bc02f63d5187e66597c75f6992 Mon Sep 17 00:00:00 2001 From: Dimitris Date: Sat, 10 Jun 2017 19:36:12 +0300 Subject: [PATCH 025/237] Allow user to remove openid --- app/controllers/openids_controller.rb | 9 +++++++++ app/models/ability.rb | 2 ++ app/views/devise/registrations/edit.html.haml | 6 +++++- config/routes.rb | 4 +++- 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 app/controllers/openids_controller.rb diff --git a/app/controllers/openids_controller.rb b/app/controllers/openids_controller.rb new file mode 100644 index 00000000..35bc0bae --- /dev/null +++ b/app/controllers/openids_controller.rb @@ -0,0 +1,9 @@ +class OpenidsController < ApplicationController + load_and_authorize_resource :user + load_and_authorize_resource through: :user + + def destroy + @openid.destroy + redirect_to :back + end +end diff --git a/app/models/ability.rb b/app/models/ability.rb index dba29fa7..cc23a631 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -100,6 +100,8 @@ class Ability # can manage the commercials of their own events can :manage, Commercial, commercialable_type: 'Event', commercialable_id: user.events.pluck(:id) + + can [:destroy], Openid end # Abilities for signed in users with roles diff --git a/app/views/devise/registrations/edit.html.haml b/app/views/devise/registrations/edit.html.haml index d97b4867..c884a194 100644 --- a/app/views/devise/registrations/edit.html.haml +++ b/app/views/devise/registrations/edit.html.haml @@ -15,7 +15,11 @@ %h4 Currently the following openIDs are associated with your account - @openids.each do |openid| - %li= "#{openid.provider}:#{openid.email}" + %li{ style: "list-style: none; margin-left: 20px;" } + = link_to user_openid_path(openid, user_id: current_user.id), method: :delete, + data: { confirm: "Remove association with #{openid.provider} account?" } do + %span.fa.fa-times{ style: "color: red;" } + %span #{openid.provider}:#{openid.email} %br %h4 To add an openID with a different email address to your account, sign in with your diff --git a/config/routes.rb b/config/routes.rb index b10d5d9c..ccca3511 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,7 +15,9 @@ Osem::Application.routes.draw do mount LetterOpenerWeb::Engine, at: "/letter_opener" end - resources :users, except: [:new, :index, :create, :destroy] + resources :users, except: [:new, :index, :create, :destroy] do + resources :openids, only: :destroy + end namespace :admin do resources :organizations From cdf794ecbf21e0709c102d8f5e54ae16270e4664 Mon Sep 17 00:00:00 2001 From: divyanshumehta Date: Mon, 12 Jun 2017 22:37:45 +0530 Subject: [PATCH 026/237] Add Style/SelfAssignment Rubocop cop The cop enforces use of self assignment operator E.g. a=a+2 gets written as a+=2. Also the offenses listed in rubocop.todo.yml have been corrected automatically with the --auto-correct option. Fixes issue #1531 --- .rubocop.yml | 4 ++++ .rubocop_todo.yml | 8 -------- app/models/event.rb | 2 +- db/migrate/20141104131625_generate_username.rb | 4 +--- spec/support/save_feature_failures.rb | 2 +- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 9f7f0d00..5cc5d541 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -92,6 +92,10 @@ Style/SpaceAroundOperators: Style/SpaceInsideBrackets: Enabled: true +# This cop enforces the use the shorthand for self-assignment. +Style/SelfAssignment: + Enabled: true + # Use single quotes unless there's string interpolation Style/StringLiterals: Enabled: true diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 1544c6f2..928205b0 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -721,14 +721,6 @@ Style/RegexpLiteral: Exclude: - 'Guardfile' -# Offense count: 3 -# Cop supports --auto-correct. -Style/SelfAssignment: - Exclude: - - 'app/models/event.rb' - - 'db/migrate/20141104131625_generate_username.rb' - - 'spec/support/save_feature_failures.rb' - # Offense count: 3 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. diff --git a/app/models/event.rb b/app/models/event.rb index 0c786066..f8f9c2d8 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -115,7 +115,7 @@ class Event < ActiveRecord::Base def average_rating @total_rating = 0 votes.each do |vote| - @total_rating = @total_rating + vote.rating + @total_rating += vote.rating end @total = votes.size @total_rating > 0 ? number_with_precision(@total_rating / @total.to_f, precision: 2, strip_insignificant_zeros: true) : 0 diff --git a/db/migrate/20141104131625_generate_username.rb b/db/migrate/20141104131625_generate_username.rb index d7f4bdda..e1ddf111 100644 --- a/db/migrate/20141104131625_generate_username.rb +++ b/db/migrate/20141104131625_generate_username.rb @@ -7,9 +7,7 @@ class GenerateUsername < ActiveRecord::Migration TempUser.all.each do |user| if user.username.blank? username = user.email.split('@')[0] - if TempUser.find_by(username: username) - username = username + user.id.to_s - end + username += user.id.to_s if TempUser.find_by(username: username) user.update_attributes(username: username) end end diff --git a/spec/support/save_feature_failures.rb b/spec/support/save_feature_failures.rb index fe6edf66..2e0d33a9 100644 --- a/spec/support/save_feature_failures.rb +++ b/spec/support/save_feature_failures.rb @@ -5,7 +5,7 @@ RSpec.configure do |config| config.after(:each, type: :feature) do example_filename = RSpec.current_example.full_description example_filename = example_filename.tr(' ', '_') - example_filename = example_filename + '.html' + example_filename += '.html' example_filename = File.expand_path(example_filename, Capybara.save_and_open_page_path) if RSpec.current_example.exception.present? save_page(example_filename) From 58c80f1447c1c1db332aa02fec8ca448555409b8 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 14 Jun 2017 22:12:10 +0530 Subject: [PATCH 027/237] update nokogiri to 1.8.0 --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index e1c8218f..9dbc51e9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -273,7 +273,7 @@ GEM open4 (~> 1.3.4) rake mini_magick (4.5.1) - mini_portile2 (2.1.0) + mini_portile2 (2.2.0) minitest (5.10.1) momentjs-rails (2.8.1) railties (>= 3.1) @@ -293,8 +293,8 @@ GEM mysql2 (0.4.2) netrc (0.11.0) nio4r (1.2.1) - nokogiri (1.7.1) - mini_portile2 (~> 2.1.0) + nokogiri (1.8.0) + mini_portile2 (~> 2.2.0) oauth2 (0.9.4) faraday (>= 0.8, < 0.10) jwt (~> 1.0) From 0496ed23e5a3564313e6c7521f0c234a38763979 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Wed, 14 Jun 2017 02:46:39 +0530 Subject: [PATCH 028/237] Improves test speed --- spec/support/database_cleaner.rb | 12 +++++++++++- spec/support/factory_girl.rb | 12 +++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb index 3e6c8404..25bf528a 100644 --- a/spec/support/database_cleaner.rb +++ b/spec/support/database_cleaner.rb @@ -1,6 +1,16 @@ RSpec.configure do |config| - config.before(:each) do + config.before(:suite) do DatabaseCleaner.clean_with(:truncation) Rails.application.load_seed end + + config.before(:each) do |example| + DatabaseCleaner.strategy = example.metadata[:js] == true ? :truncation : :transaction + DatabaseCleaner.start + end + + config.after(:each) do |example| + DatabaseCleaner.clean + Rails.application.load_seed if example.metadata[:js] == true + end end diff --git a/spec/support/factory_girl.rb b/spec/support/factory_girl.rb index c46a5105..d745aece 100644 --- a/spec/support/factory_girl.rb +++ b/spec/support/factory_girl.rb @@ -4,9 +4,15 @@ RSpec.configure do |config| config.before(:suite) do if ENV['OSEM_FACTORY_LINT'] != 'false' - mock_commercial_request - FactoryGirl.lint + DatabaseCleaner.strategy = :transaction + DatabaseCleaner.clean_with(:truncation) + begin + DatabaseCleaner.start + mock_commercial_request + FactoryGirl.lint + ensure + DatabaseCleaner.clean + end end end - end From 2f70a1ddd114604c423393ddee3ae26b9e8a41be Mon Sep 17 00:00:00 2001 From: Stella Rouzi Date: Tue, 13 Jun 2017 10:22:23 +0300 Subject: [PATCH 029/237] Avoid horizontal scroll bar --- app/views/admin/organizations/index.html.haml | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/app/views/admin/organizations/index.html.haml b/app/views/admin/organizations/index.html.haml index 03bf11f9..52e2877a 100644 --- a/app/views/admin/organizations/index.html.haml +++ b/app/views/admin/organizations/index.html.haml @@ -6,26 +6,26 @@ = link_to 'Create Organization', new_admin_organization_path, class: 'btn btn-success pull-right' %p.text-muted Manage organizations in OSEM - .row - .col-md-12 - %table.table.table-hover.datatable - %thead - %th Name - %th Upcoming Conferences - %th Past Conferences - %th Actions - %tbody - - @organizations.each do |organization| - %tr - %td - = organization.name - %td - = organization.conferences.count - %td - = organization.conferences.count - %td - .btn-group - = link_to 'Edit', edit_admin_organization_path(organization), - method: :get, class: 'btn btn-primary' - = link_to 'Delete', admin_organization_path(organization), - method: :delete, class: 'btn btn-danger', data: { confirm: "Warning: This will delete #{organization.name} and all its data which includes data for all conferences within #{organization.name}. Do you really want to continue?" } +.row + .col-md-12 + %table.table.table-hover.datatable + %thead + %th Name + %th Upcoming Conferences + %th Past Conferences + %th Actions + %tbody + - @organizations.each do |organization| + %tr + %td + = organization.name + %td + = organization.conferences.count + %td + = organization.conferences.count + %td + .btn-group + = link_to 'Edit', edit_admin_organization_path(organization), + method: :get, class: 'btn btn-primary' + = link_to 'Delete', admin_organization_path(organization), + method: :delete, class: 'btn btn-danger', data: { confirm: "Warning: This will delete #{organization.name} and all its data which includes data for all conferences within #{organization.name}. Do you really want to continue?" } From d160c22a0b995a14e1e6cebbeb8344d295f6ad0b Mon Sep 17 00:00:00 2001 From: Dimitris Date: Thu, 15 Jun 2017 23:04:28 +0300 Subject: [PATCH 030/237] Enable rails/findEach Rubocop cop This cop enforce the use of `find_each` instead of `each`. Closes #1535 --- .rubocop.yml | 4 ++++ .rubocop_todo.yml | 8 -------- app/models/conference.rb | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 5cc5d541..f722ba55 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -196,6 +196,10 @@ Lint/DuplicatedKey: Rails: Enabled: true +# Use `find_each` instead of `each`. +Rails/FindEach: + Enabled: true + # Avoid use of old-style attribute validation Rails/Validation: Enabled: true diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 928205b0..ef9bcd98 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -154,14 +154,6 @@ Rails/FindBy: - 'app/models/ticket_purchase.rb' - 'app/models/user.rb' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: Include. -# Include: app/models/**/*.rb -Rails/FindEach: - Exclude: - - 'app/models/conference.rb' - # Offense count: 7 # Configuration parameters: Include. # Include: app/models/**/*.rb diff --git a/app/models/conference.rb b/app/models/conference.rb index f58c50ed..04fe1b52 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -643,7 +643,7 @@ class Conference < ActiveRecord::Base def self.write_event_distribution_to_db week = DateTime.now.end_of_week - Conference.where('end_date > ?', Date.today).each do |conference| + Conference.where('end_date > ?', Date.today).find_each do |conference| result = {} Event.state_machine.states.each do |state| count = conference.program.events.where('state = ?', state.name).count From 1c38b091cc3e3093a9f34bd1f06a51178f461722 Mon Sep 17 00:00:00 2001 From: Eugene Dubinin Date: Thu, 15 Jun 2017 18:11:43 +0300 Subject: [PATCH 031/237] Fixes for PostreSQL support --- Gemfile | 2 + app/models/conference.rb | 15 +++--- .../admin/reports/_missing_speakers.html.haml | 2 +- app/views/admin/reports/index.html.haml | 2 +- db/schema.rb | 51 ++++++++++--------- 5 files changed, 39 insertions(+), 33 deletions(-) diff --git a/Gemfile b/Gemfile index 76c49ce3..15b295fa 100644 --- a/Gemfile +++ b/Gemfile @@ -18,7 +18,9 @@ gem 'rails_12factor', group: :production gem 'responders', '~> 2.0' # as the database for Active Record +# choose only one gem 'mysql2' +#gem 'pg' # for observing records gem 'rails-observers' diff --git a/app/models/conference.rb b/app/models/conference.rb index 04fe1b52..0cf16de6 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -131,7 +131,7 @@ class Conference < ActiveRecord::Base result = [] if program && program.cfp && program.events - submissions = program.events.group(:week).count + submissions = program.events.select(:week).group(:week).order(:week).count start_week = program.cfp.start_week weeks = program.cfp.weeks result = calculate_items_per_week(start_week, weeks, submissions) @@ -179,7 +179,7 @@ class Conference < ActiveRecord::Base registration_period.start_date && registration_period.end_date - reg = registrations.group(:week).count + reg = registrations.group(:week).order(:week).count start_week = get_registration_start_week weeks = registration_weeks result = calculate_items_per_week(start_week, weeks, reg) @@ -337,8 +337,8 @@ class Conference < ActiveRecord::Base # ====Returns # * +hash+ -> user: submissions def self.get_top_submitter(limit = 5) - submitter = EventUser.where('event_role = ?', 'submitter').limit(limit).group(:user_id) - counter = submitter.order('count_all desc').count + submitter = EventUser.select(:user_id).where('event_role = ?', 'submitter').limit(limit).group(:user_id) + counter = submitter.order('count_all desc').count(:all) calculate_user_submission_hash(submitter, counter) end @@ -348,10 +348,10 @@ class Conference < ActiveRecord::Base # ====Returns # * +hash+ -> user: submissions def get_top_submitter(limit = 5) - submitter = EventUser.joins(:event) + submitter = EventUser.joins(:event).select(:user_id) .where('event_role = ? and program_id = ?', 'submitter', Conference.find(id).program.id) .limit(limit).group(:user_id) - counter = submitter.order('count_all desc').count + counter = submitter.order('count_all desc').count(:all) Conference.calculate_user_submission_hash(submitter, counter) end @@ -1100,7 +1100,8 @@ class Conference < ActiveRecord::Base def self.calculate_user_submission_hash(submitters, counter) result = ActiveSupport::OrderedHash.new counter.each do |key, value| - submitter = submitters.where(user_id: key).first + # make PG happy by including the user_id in ORDER + submitter = submitters.where(user_id: key).order(:user_id).first if submitter result[submitter.user] = value end diff --git a/app/views/admin/reports/_missing_speakers.html.haml b/app/views/admin/reports/_missing_speakers.html.haml index b269eef6..bc1769ae 100644 --- a/app/views/admin/reports/_missing_speakers.html.haml +++ b/app/views/admin/reports/_missing_speakers.html.haml @@ -3,7 +3,7 @@ .page-header %h1 Missing Speakers - = "(#{@missing_event_speakers.group(:user_id).length})" + = "(#{@missing_event_speakers.distinct(:user_id).length})" %p.text-muted All event speakers who haven't checked in .col-md-12 diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml index 704ffdaa..6bbb8886 100644 --- a/app/views/admin/reports/index.html.haml +++ b/app/views/admin/reports/index.html.haml @@ -17,7 +17,7 @@ %a{href: '#missing-speakers', 'data-toggle' => 'tab'} Missing Speakers %span.label.label-danger{style: 'border-radius: 1em;'} - = @missing_event_speakers.group(:user_id).length + = @missing_event_speakers.distinct(:user_id).length .tab-content #all.tab-pane.active diff --git a/db/schema.rb b/db/schema.rb index 9772066a..547d5858 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -13,17 +13,20 @@ ActiveRecord::Schema.define(version: 20170531094819) do + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + create_table "ahoy_events", force: :cascade do |t| - t.uuid "visit_id", limit: 16 + t.integer "visit_id" t.integer "user_id" t.string "name" t.text "properties" t.datetime "time" end - add_index "ahoy_events", ["time"], name: "index_ahoy_events_on_time" - add_index "ahoy_events", ["user_id"], name: "index_ahoy_events_on_user_id" - add_index "ahoy_events", ["visit_id"], name: "index_ahoy_events_on_visit_id" + add_index "ahoy_events", ["time"], name: "index_ahoy_events_on_time", using: :btree + add_index "ahoy_events", ["user_id"], name: "index_ahoy_events_on_user_id", using: :btree + add_index "ahoy_events", ["visit_id"], name: "index_ahoy_events_on_visit_id", using: :btree create_table "answers", force: :cascade do |t| t.string "title" @@ -65,9 +68,9 @@ ActiveRecord::Schema.define(version: 20170531094819) do t.integer "rgt" end - add_index "comments", ["commentable_id"], name: "index_comments_on_commentable_id" - add_index "comments", ["commentable_type"], name: "index_comments_on_commentable_type" - add_index "comments", ["user_id"], name: "index_comments_on_user_id" + add_index "comments", ["commentable_id"], name: "index_comments_on_commentable_id", using: :btree + add_index "comments", ["commentable_type"], name: "index_comments_on_commentable_type", using: :btree + add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree create_table "commercials", force: :cascade do |t| t.string "commercial_id" @@ -137,7 +140,7 @@ ActiveRecord::Schema.define(version: 20170531094819) do t.datetime "updated_at" end - add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority" + add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree create_table "difficulty_levels", force: :cascade do |t| t.string "title" @@ -190,10 +193,10 @@ ActiveRecord::Schema.define(version: 20170531094819) do t.datetime "updated_at", null: false end - add_index "event_schedules", ["event_id", "schedule_id"], name: "index_event_schedules_on_event_id_and_schedule_id", unique: true - add_index "event_schedules", ["event_id"], name: "index_event_schedules_on_event_id" - add_index "event_schedules", ["room_id"], name: "index_event_schedules_on_room_id" - add_index "event_schedules", ["schedule_id"], name: "index_event_schedules_on_schedule_id" + add_index "event_schedules", ["event_id", "schedule_id"], name: "index_event_schedules_on_event_id_and_schedule_id", unique: true, using: :btree + add_index "event_schedules", ["event_id"], name: "index_event_schedules_on_event_id", using: :btree + add_index "event_schedules", ["room_id"], name: "index_event_schedules_on_room_id", using: :btree + add_index "event_schedules", ["schedule_id"], name: "index_event_schedules_on_schedule_id", using: :btree create_table "event_types", force: :cascade do |t| t.string "title", null: false @@ -301,7 +304,7 @@ ActiveRecord::Schema.define(version: 20170531094819) do t.integer "schedule_interval", default: 15, null: false end - add_index "programs", ["selected_schedule_id"], name: "index_programs_on_selected_schedule_id" + add_index "programs", ["selected_schedule_id"], name: "index_programs_on_selected_schedule_id", using: :btree create_table "qanswers", force: :cascade do |t| t.integer "question_id" @@ -373,8 +376,8 @@ ActiveRecord::Schema.define(version: 20170531094819) do t.string "resource_type" end - add_index "roles", ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id" - add_index "roles", ["name"], name: "index_roles_on_name" + add_index "roles", ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree + add_index "roles", ["name"], name: "index_roles_on_name", using: :btree create_table "rooms", force: :cascade do |t| t.string "guid", null: false @@ -389,7 +392,7 @@ ActiveRecord::Schema.define(version: 20170531094819) do t.datetime "updated_at", null: false end - add_index "schedules", ["program_id"], name: "index_schedules_on_program_id" + add_index "schedules", ["program_id"], name: "index_schedules_on_program_id", using: :btree create_table "splashpages", force: :cascade do |t| t.integer "conference_id" @@ -512,17 +515,17 @@ ActiveRecord::Schema.define(version: 20170531094819) do t.boolean "is_disabled", default: false end - add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true - add_index "users", ["email"], name: "index_users_on_email", unique: true - add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true - add_index "users", ["username"], name: "index_users_on_username", unique: true + add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree + add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree + add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree + add_index "users", ["username"], name: "index_users_on_username", unique: true, using: :btree create_table "users_roles", force: :cascade do |t| t.integer "role_id" t.integer "user_id" end - add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id" + add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree create_table "vchoices", force: :cascade do |t| t.integer "vday_id" @@ -566,10 +569,10 @@ ActiveRecord::Schema.define(version: 20170531094819) do t.integer "conference_id" end - add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id" + add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id", using: :btree create_table "visits", force: :cascade do |t| - t.uuid "visitor_id", limit: 16 + t.uuid "visitor_id" t.string "ip" t.text "user_agent" t.text "referrer" @@ -591,7 +594,7 @@ ActiveRecord::Schema.define(version: 20170531094819) do t.datetime "started_at" end - add_index "visits", ["user_id"], name: "index_visits_on_user_id" + add_index "visits", ["user_id"], name: "index_visits_on_user_id", using: :btree create_table "votes", force: :cascade do |t| t.integer "event_id" From 5c56683ae8b7a66e47b6f7f5d9dbe587e73fa936 Mon Sep 17 00:00:00 2001 From: Siddhant Bajaj Date: Sat, 3 Jun 2017 16:05:59 +0530 Subject: [PATCH 032/237] Introduced Physical Ticket Added PhysicalTicket model and controller. It holds the information about each physical ticket bought at the purchase. Physical Tickets are created after every successfull payment. --- Gemfile | 2 +- app/controllers/payments_controller.rb | 6 ++-- app/controllers/physical_ticket_controller.rb | 12 +++++++ .../ticket_purchases_controller.rb | 2 +- app/models/ability.rb | 1 + app/models/conference.rb | 1 + app/models/physical_ticket.rb | 6 ++++ app/models/ticket_purchase.rb | 13 +++++-- app/models/user.rb | 5 +++ .../conferences/_conference_details.html.haml | 2 ++ app/views/physical_ticket/index.html.haml | 35 +++++++++++++++++++ app/views/physical_ticket/show.html.haml | 0 config/routes.rb | 1 + .../20170603095900_create_physical_tickets.rb | 9 +++++ db/schema.rb | 8 ++++- spec/features/ticket_purchases_spec.rb | 4 +-- spec/models/ticket_purchase_spec.rb | 20 +++++++++-- 17 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 app/controllers/physical_ticket_controller.rb create mode 100644 app/models/physical_ticket.rb create mode 100644 app/views/physical_ticket/index.html.haml create mode 100644 app/views/physical_ticket/show.html.haml create mode 100644 db/migrate/20170603095900_create_physical_tickets.rb diff --git a/Gemfile b/Gemfile index 15b295fa..245080c3 100644 --- a/Gemfile +++ b/Gemfile @@ -20,7 +20,7 @@ gem 'responders', '~> 2.0' # as the database for Active Record # choose only one gem 'mysql2' -#gem 'pg' +# gem 'pg' # for observing records gem 'rails-observers' diff --git a/app/controllers/payments_controller.rb b/app/controllers/payments_controller.rb index e8766548..b5e2c193 100644 --- a/app/controllers/payments_controller.rb +++ b/app/controllers/payments_controller.rb @@ -18,7 +18,7 @@ class PaymentsController < ApplicationController if @payment.purchase && @payment.save update_purchased_ticket_purchases - redirect_to conference_conference_registration_path(@conference.short_title), + redirect_to conference_physical_ticket_index_path, notice: 'Thanks! Your ticket is booked successfully.' else @total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false) @@ -38,6 +38,8 @@ class PaymentsController < ApplicationController end def update_purchased_ticket_purchases - current_user.ticket_purchases.by_conference(@conference).unpaid.update_all(paid: true, payment_id: @payment.id) + current_user.ticket_purchases.by_conference(@conference).unpaid.each do |ticket_purchase| + ticket_purchase.pay(@payment) + end end end diff --git a/app/controllers/physical_ticket_controller.rb b/app/controllers/physical_ticket_controller.rb new file mode 100644 index 00000000..2354f279 --- /dev/null +++ b/app/controllers/physical_ticket_controller.rb @@ -0,0 +1,12 @@ +class PhysicalTicketController < ApplicationController + before_action :authenticate_user! + load_resource :conference, find_by: :short_title + load_and_authorize_resource + authorize_resource :conference_registrations, class: Registration + + def index + @physical_tickets = current_user.physical_tickets.by_conference(@conference) + end + + def show; end +end diff --git a/app/controllers/ticket_purchases_controller.rb b/app/controllers/ticket_purchases_controller.rb index 1c672d69..3945e154 100644 --- a/app/controllers/ticket_purchases_controller.rb +++ b/app/controllers/ticket_purchases_controller.rb @@ -11,7 +11,7 @@ class TicketPurchasesController < ApplicationController redirect_to new_conference_payment_path, notice: 'Please pay here to get tickets.' elsif current_user.ticket_purchases.by_conference(@conference).paid.any? - redirect_to conference_conference_registration_path(@conference.short_title), + redirect_to conference_physical_ticket_index_path, notice: 'You have free tickets for the conference.' else redirect_to conference_tickets_path(@conference.short_title), diff --git a/app/models/ability.rb b/app/models/ability.rb index cc23a631..bdf554cc 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -87,6 +87,7 @@ class Ability can :index, Ticket can :manage, TicketPurchase, user_id: user.id can [:new, :create], Payment, user_id: user.id + can [:index, :show], PhysicalTicket, user_id: user.id can [:create, :destroy], Subscription, user_id: user.id diff --git a/app/models/conference.rb b/app/models/conference.rb index 0cf16de6..11fab753 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -19,6 +19,7 @@ class Conference < ActiveRecord::Base has_one :email_settings, dependent: :destroy has_one :program, dependent: :destroy has_one :venue, dependent: :destroy + has_many :physical_tickets, through: :ticket_purchases has_many :ticket_purchases, dependent: :destroy has_many :payments, dependent: :destroy has_many :supporters, through: :ticket_purchases, source: :user diff --git a/app/models/physical_ticket.rb b/app/models/physical_ticket.rb new file mode 100644 index 00000000..a0874a6e --- /dev/null +++ b/app/models/physical_ticket.rb @@ -0,0 +1,6 @@ +class PhysicalTicket < ActiveRecord::Base + belongs_to :ticket_purchase + has_one :ticket, through: :ticket_purchase + has_one :conference, through: :ticket_purchase + has_one :user, through: :ticket_purchase +end diff --git a/app/models/ticket_purchase.rb b/app/models/ticket_purchase.rb index d1c370c4..675527ae 100644 --- a/app/models/ticket_purchase.rb +++ b/app/models/ticket_purchase.rb @@ -13,6 +13,8 @@ class TicketPurchase < ActiveRecord::Base delegate :price_cents, to: :ticket delegate :price_currency, to: :ticket + has_many :physical_tickets + scope :paid, -> { where(paid: true) } scope :unpaid, -> { where(paid: false) } scope :by_conference, ->(conference) { where(conference_id: conference.id) } @@ -45,8 +47,8 @@ class TicketPurchase < ActiveRecord::Base purchase = new(ticket_id: ticket.id, conference_id: conference.id, user_id: user.id, - quantity: quantity, - paid: ticket.price_cents.zero?) + quantity: quantity) + purchase.pay(nil) if ticket.price_cents.zero? end purchase end @@ -60,6 +62,13 @@ class TicketPurchase < ActiveRecord::Base purchase.quantity = quantity if quantity > 0 purchase end + + def pay(payment) + update_attributes(paid: true, payment: payment) + PhysicalTicket.transaction do + quantity.times { physical_tickets.create } + end + end end private diff --git a/app/models/user.rb b/app/models/user.rb index 4be77fe8..6ffb739f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -6,6 +6,11 @@ end class User < ActiveRecord::Base rolify + has_many :physical_tickets, through: :ticket_purchases do + def by_conference(conference) + where('ticket_purchases.conference_id = ?', conference) + end + end has_many :users_roles has_many :roles, through: :users_roles, dependent: :destroy diff --git a/app/views/conferences/_conference_details.html.haml b/app/views/conferences/_conference_details.html.haml index bdbd5fc6..d5bafad4 100644 --- a/app/views/conferences/_conference_details.html.haml +++ b/app/views/conferences/_conference_details.html.haml @@ -38,3 +38,5 @@ = link_to 'Subscribe', conference_subscriptions_path(conference.short_title), method: :post, class: 'btn btn-default' - else = link_to 'Unsubscribe', conference_subscriptions_path(conference.short_title), method: :delete, class: 'btn btn-default' + - if current_user && current_user.physical_tickets.by_conference(conference).any? + = link_to "My Tickets", conference_physical_ticket_index_path(conference.short_title), class: 'btn btn-default' diff --git a/app/views/physical_ticket/index.html.haml b/app/views/physical_ticket/index.html.haml new file mode 100644 index 00000000..ce741c39 --- /dev/null +++ b/app/views/physical_ticket/index.html.haml @@ -0,0 +1,35 @@ +.container + .row + .col-md-12.page-header + %h2 + Tickets + .text-muted + Your tickets for the conference + + .col-md-12 + - if @physical_tickets.present? + %table.table.table-bordered.table-striped.table-hover#roles + %thead + %th ID + %th Type + %th User + %th Actions + %tbody + - @physical_tickets.each do |physical_ticket| + %tr + %td= physical_ticket.id + %td= physical_ticket.ticket.title + %td= physical_ticket.user.name + %td + .btn-group + = link_to 'Show', + conference_physical_ticket_path(@conference.short_title, + physical_ticket.id), + class: 'btn btn-primary' + = link_to 'Generate PDF', + conference_physical_ticket_path(@conference.short_title, + physical_ticket.id, + format: :pdf), + class: 'button btn btn-default btn-info' + - else + %h5 No Tickets found! diff --git a/app/views/physical_ticket/show.html.haml b/app/views/physical_ticket/show.html.haml new file mode 100644 index 00000000..e69de29b diff --git a/config/routes.rb b/config/routes.rb index ccca3511..60b03f54 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -126,6 +126,7 @@ Osem::Application.routes.draw do resources :tickets, only: [:index] resources :ticket_purchases, only: [:create, :destroy] resources :payments, only: [:index, :new, :create] + resources :physical_ticket, only: [:index, :show] resource :subscriptions, only: [:create, :destroy] resource :schedule, only: [:show] do member do diff --git a/db/migrate/20170603095900_create_physical_tickets.rb b/db/migrate/20170603095900_create_physical_tickets.rb new file mode 100644 index 00000000..5e0c1d98 --- /dev/null +++ b/db/migrate/20170603095900_create_physical_tickets.rb @@ -0,0 +1,9 @@ +class CreatePhysicalTickets < ActiveRecord::Migration + def change + create_table :physical_tickets do |t| + t.integer :ticket_purchase_id, null: false + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 547d5858..19a3df19 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170531094819) do +ActiveRecord::Schema.define(version: 20170603095900) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -289,6 +289,12 @@ ActiveRecord::Schema.define(version: 20170531094819) do t.datetime "updated_at", null: false end + create_table "physical_tickets", force: :cascade do |t| + t.integer "ticket_purchase_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "programs", force: :cascade do |t| t.integer "conference_id" t.integer "rating", default: 0 diff --git a/spec/features/ticket_purchases_spec.rb b/spec/features/ticket_purchases_spec.rb index f8c755a3..958ae645 100644 --- a/spec/features/ticket_purchases_spec.rb +++ b/spec/features/ticket_purchases_spec.rb @@ -101,12 +101,10 @@ feature Registration do click_button 'Continue' - expect(current_path).to eq(conference_conference_registration_path(conference.short_title)) + expect(current_path).to eq(conference_physical_ticket_index_path(conference.short_title)) purchase = TicketPurchase.where(user_id: participant.id, ticket_id: free_ticket.id).first expect(purchase.quantity).to eq(5) expect(purchase.paid).to be true - - expect(page.has_content?("5 #{free_ticket.title} Tickets for $ 0")).to be true end end diff --git a/spec/models/ticket_purchase_spec.rb b/spec/models/ticket_purchase_spec.rb index 0bb33f8e..f11a8187 100644 --- a/spec/models/ticket_purchase_spec.rb +++ b/spec/models/ticket_purchase_spec.rb @@ -34,7 +34,6 @@ describe TicketPurchase do it 'is valid with a quantity greater than zero' do should allow_value(1).for(:quantity) end - end describe 'self#purchase' do @@ -54,7 +53,6 @@ describe TicketPurchase do expect(TicketPurchase.count).to eq(1) expect(purchase.quantity).to eq(10) expect(message.blank?).to be true - end it 'creates a purchase for one ticket' do @@ -116,4 +114,22 @@ describe TicketPurchase do expect(message.blank?).to be true end end + + describe 'after_create' do + let(:ticket_purchase) { create(:ticket_purchase, quantity: 4, paid: true) } + + it 'creates physical tickets equal to the quantity of purchase' do + expect(ticket_purchase.physical_tickets.count).to eq(4) + end + end + + describe 'after_update' do + let(:ticket_purchase) { create(:ticket_purchase, quantity: 5) } + + it 'creates physical tickets if the payment is made successfully' do + ticket_purchase + ticket_purchase.paid = true + expect{ ticket_purchase.save }.to change{ ticket_purchase.physical_tickets.count }.from(0).to(5) + end + end end From d7678b2fa08dfdfc281d694c75d18dc4e1481850 Mon Sep 17 00:00:00 2001 From: Siddhant Bajaj Date: Thu, 8 Jun 2017 03:45:08 +0530 Subject: [PATCH 033/237] Added model test Added test for physical ticket model. --- spec/factories/physical_ticket.rb | 5 +++++ spec/factories/ticket_purchases.rb | 6 ++++++ spec/models/physical_ticket_spec.rb | 14 ++++++++++++++ spec/models/ticket_purchase_spec.rb | 18 ------------------ 4 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 spec/factories/physical_ticket.rb create mode 100644 spec/models/physical_ticket_spec.rb diff --git a/spec/factories/physical_ticket.rb b/spec/factories/physical_ticket.rb new file mode 100644 index 00000000..8b4f2a0e --- /dev/null +++ b/spec/factories/physical_ticket.rb @@ -0,0 +1,5 @@ +FactoryGirl.define do + factory :physical_ticket do + ticket_purchase + end +end diff --git a/spec/factories/ticket_purchases.rb b/spec/factories/ticket_purchases.rb index 82103db3..bee365cf 100644 --- a/spec/factories/ticket_purchases.rb +++ b/spec/factories/ticket_purchases.rb @@ -4,5 +4,11 @@ FactoryGirl.define do conference ticket quantity 10 + factory :paid_ticket_purchase do + after(:build) do |ticket_purchase| + payment = create(:payment) + ticket_purchase.pay(payment) + end + end end end diff --git a/spec/models/physical_ticket_spec.rb b/spec/models/physical_ticket_spec.rb new file mode 100644 index 00000000..9910a4a3 --- /dev/null +++ b/spec/models/physical_ticket_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' + +describe PhysicalTicket do + + describe 'association' do + it { is_expected.to belong_to :ticket_purchase } + end + + describe 'validations' do + it 'has a valid factory' do + expect(build(:physical_ticket)).to be_valid + end + end +end diff --git a/spec/models/ticket_purchase_spec.rb b/spec/models/ticket_purchase_spec.rb index f11a8187..3ef9a861 100644 --- a/spec/models/ticket_purchase_spec.rb +++ b/spec/models/ticket_purchase_spec.rb @@ -114,22 +114,4 @@ describe TicketPurchase do expect(message.blank?).to be true end end - - describe 'after_create' do - let(:ticket_purchase) { create(:ticket_purchase, quantity: 4, paid: true) } - - it 'creates physical tickets equal to the quantity of purchase' do - expect(ticket_purchase.physical_tickets.count).to eq(4) - end - end - - describe 'after_update' do - let(:ticket_purchase) { create(:ticket_purchase, quantity: 5) } - - it 'creates physical tickets if the payment is made successfully' do - ticket_purchase - ticket_purchase.paid = true - expect{ ticket_purchase.save }.to change{ ticket_purchase.physical_tickets.count }.from(0).to(5) - end - end end From 02f27dd4bc1cb72267a88bd344eb033d3f38b92f Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Thu, 22 Jun 2017 18:14:13 +0530 Subject: [PATCH 034/237] Fixed association between TicketPurchase and Payment Model. One to many association between TicketPurchase model and Payment Model wasn't properly set up. --- app/models/ticket_purchase.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/ticket_purchase.rb b/app/models/ticket_purchase.rb index 675527ae..88e1f4de 100644 --- a/app/models/ticket_purchase.rb +++ b/app/models/ticket_purchase.rb @@ -2,6 +2,7 @@ class TicketPurchase < ActiveRecord::Base belongs_to :ticket belongs_to :user belongs_to :conference + belongs_to :payment validates :ticket_id, :user_id, :conference_id, :quantity, presence: true From 6469ea7da5236562c69642625dfd87f16bb2466f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=20Mar=C3=ADa=20Mart=C3=ADnez=20G=C3=B3mez?= Date: Thu, 22 Jun 2017 16:49:52 +0200 Subject: [PATCH 035/237] Remove default configuration from `.rubocop.yml` We had part of the default Rubocop configuration in the `.rubocop.yml` file. It is not needed as it is the default and it also don't make sense, because we only have part of it. That was caused because when enabling a cop we were moving it from `.rubocop_todo.yml` to `.rubocop.yml`, but this is only needed if we overwrite the default configuration. --- .rubocop.yml | 184 --------------------------------------------------- 1 file changed, 184 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index f722ba55..cff7046b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -13,112 +13,6 @@ AllCops: - 'config/**/*' - 'bin/*' -#################### Style ############################### - -# Align the elements of a hash literal if they span more than one line -Style/AlignHash: - Enabled: true - -# Align the parameters of a method call if they span more than one line -Style/AlignParameters: - Enabled: true - -# Use && instead of and, use || instead of or -Style/AndOr: - Enabled: true - -# Avoid redundunt curly braces when it is obvious that hash is used -Style/BracesAroundHashParameters: - Enabled: true - -# Avoid the use of the case equality operator `===` -Style/CaseEquality: - Enabled: true - -# Use nested module/class definitions instead of compact style -Style/ClassAndModuleChildren: - Enabled: true - -# Checks the . position in multi-line method calls. -Style/DotPosition: - Enabled: true - -# Checks for uses of double negation (!!) to convert something to a boolean value. -Style/DoubleNegation: - Enabled: true - -# Use one empty line between method definitions -Style/EmptyLineBetweenDefs: - Enabled: true - -# There should be only one empty line in designated place -Style/EmptyLines: - Enabled: true - -# Keep a blank line before and after private. -Style/EmptyLinesAroundAccessModifier: - Enabled: true - -# Use hash literal {} instead of Hash.new -Style/EmptyLiteral: - Enabled: true - -# Prefer `each` over `for i` -Style/For: - Enabled: true - -# Use the new Ruby 1.9 hash syntax -Style/HashSyntax: - Enabled: true - EnforcedStyle: ruby19 - -# Checks for uses of if with negated condition. Use unless instead -Style/NegatedIf: - Enabled: true - -# Do not compare with nil. Use .nil? instead -Style/NilComparison: - Enabled: true - -# Checks for redundant uses of self. -Style/RedundantSelf: - Enabled: true - -# Checks that operators have space around them, except for ** which should not have surrounding space. -Style/SpaceAroundOperators: - Enabled: true - -# Checks for spaces inside square brackets. -Style/SpaceInsideBrackets: - Enabled: true - -# This cop enforces the use the shorthand for self-assignment. -Style/SelfAssignment: - Enabled: true - -# Use single quotes unless there's string interpolation -Style/StringLiterals: - Enabled: true - -# This cop checks for tabs where spaces should be used. -Style/Tab: - Enabled: true - -# Avoid trailing blank lines -Style/TrailingBlankLines: - Enabled: true - -# Avoid trailing whitespace -Style/TrailingWhitespace: - Enabled: true - -# Check for array literals made up of word-like strings, that are not using the %w() syntax -Style/WordArray: - Enabled: true - -# This cop checks for numeric comparisons that can be replaced by a predicate method. -Style/ZeroLengthPredicate: - Enabled: true #################### Metrics ############################### @@ -135,81 +29,3 @@ Metrics/ClassLength: Metrics/BlockLength: Exclude: - 'spec/models/conference_spec.rb' - -#################### Lint ############################### - -# Wrap your assignment in condition if you mean it, otherwise it is most likely equality check -Lint/AssignmentInCondition: - Enabled: true - -# Align blocks of code properly -Lint/BlockAlignment: - Enabled: true - -# Things deprecated in current ruby API -Lint/DeprecatedClassMethods: - Enabled: true - -# Do not use literal in conditions. We have it enabled for now -Lint/LiteralInCondition: - Enabled: false - -# Prefer `Kernel#loop -> break` over `begin -> while` -Lint/Loop: - Enabled: true - -# Do not put space before arguments when they are in parentheses -Lint/ParenthesesAsGroupedExpression: - Enabled: true - -# Do not rescue Exceptions class itself -Lint/RescueException: - Enabled: true - -# Do not shadow local variables in blocks, choose other name -Lint/ShadowingOuterLocalVariable: - Enabled: true - -# Use _ or variable_name to explicitly mark variable as unused -Lint/UnusedBlockArgument: - Enabled: true - -# Use _ or _argument_name to explicitly mark argument as unused -Lint/UnusedMethodArgument: - Enabled: true - -# Avoid useless assignment -Lint/UselessAssignment: - Enabled: true - -# Do not use variables in void context -Lint/Void: - Enabled: true - -# Do not use duplicated keys in hash literals. -Lint/DuplicatedKey: - Enabled: true - -#################### Rails ############################### - -# Enforce Rails specific style -Rails: - Enabled: true - -# Use `find_each` instead of `each`. -Rails/FindEach: - Enabled: true - -# Avoid use of old-style attribute validation -Rails/Validation: - Enabled: true - -# Looks for delegations, that could have been created automatically with delegate method -Rails/Delegate: - Enabled: true - -#################### Performance ############################### - -# Identifies places where gsub can be replaced by tr or delete. -Performance/StringReplacement: - Enabled: true From 5378b7524bf9ce0a022354982dc345d231aa2988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=20Mar=C3=ADa=20Mart=C3=ADnez=20G=C3=B3mez?= Date: Thu, 22 Jun 2017 16:55:00 +0200 Subject: [PATCH 036/237] Fix Style/LeadingCommentSpace Rubocop offense Fix Rubocop offense introduced in: https://github.com/openSUSE/osem/pull/1229 --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 15b295fa..245080c3 100644 --- a/Gemfile +++ b/Gemfile @@ -20,7 +20,7 @@ gem 'responders', '~> 2.0' # as the database for Active Record # choose only one gem 'mysql2' -#gem 'pg' +# gem 'pg' # for observing records gem 'rails-observers' From ed1f219b814184a93c2edcf53d9e385995ce9961 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Sun, 18 Jun 2017 02:57:39 +0300 Subject: [PATCH 037/237] Update Ruby to 2.2 Force development environment to use ruby 2.2 in preparation for the update to Rails 5 --- bootstrap.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index 42766366..8b5e848a 100644 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -2,7 +2,7 @@ pushd /vagrant echo -e "\ninstalling required software packages...\n" -zypper -q -n install update-alternatives ruby-devel make gcc gcc-c++ \ +zypper -q -n install update-alternatives ruby2.2-devel make gcc gcc-c++ \ libxml2-devel libxslt-devel nodejs screen mariadb \ libmysqld-devel sqlite3-devel imagemagick @@ -10,7 +10,7 @@ echo -e "\ndisabling versioned gem binary names...\n" echo 'install: --no-format-executable' >> /etc/gemrc echo -e "\ninstalling bundler...\n" -gem install bundler +gem.ruby2.2 install bundler echo -e "\ninstalling your bundle...\n" su - vagrant -c "cd /vagrant/; bundle install --quiet" From bf7e890739faad7f42b86ec0de9ecb29c7c1a8b4 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Sun, 18 Jun 2017 02:59:28 +0300 Subject: [PATCH 038/237] Update vagrant box image to openSUSE 42.2 And fix dependencies --- Vagrantfile | 2 +- bootstrap.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index e2faad9d..bf3622e4 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -12,7 +12,7 @@ Vagrant.configure(2) do |config| # Every Vagrant development environment requires a box. You can search for # boxes at https://atlas.hashicorp.com/search. - config.vm.box = "opensuse/openSUSE-42.1-x86_64" + config.vm.box = "opensuse/openSUSE-42.2-x86_64" # Disable automatic box update checking. If you disable this, then # boxes will only be checked for updates when the user runs diff --git a/bootstrap.sh b/bootstrap.sh index 8b5e848a..503d1bbf 100644 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -4,7 +4,7 @@ pushd /vagrant echo -e "\ninstalling required software packages...\n" zypper -q -n install update-alternatives ruby2.2-devel make gcc gcc-c++ \ libxml2-devel libxslt-devel nodejs screen mariadb \ - libmysqld-devel sqlite3-devel imagemagick + libmysqld-devel sqlite3-devel ImageMagick echo -e "\ndisabling versioned gem binary names...\n" echo 'install: --no-format-executable' >> /etc/gemrc From a925ceac3589a0e8d1a65f53c1bca52c04463897 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Mon, 19 Jun 2017 14:41:52 +0300 Subject: [PATCH 039/237] Fix typo in bootstrap.sh --- bootstrap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap.sh b/bootstrap.sh index 503d1bbf..197b6be2 100644 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -26,7 +26,7 @@ if [ ! -f /vagrant/config/database.yml ] && [ -f /vagrant/config/database.yml.ex echo -e "WARNING: Please make sure this database works in this vagrant box!\n\n" fi else - echo -e "\nnWARNING: You have already configured your database in config/database.yml." + echo -e "\n\nWARNING: You have already configured your database in config/database.yml." echo -e "WARNING: Please make sure this configuration works in this vagrant box!\n\n" fi From 905f8954d05b344cf885990fd4009ae6e0ca1d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=20Mar=C3=ADa=20Mart=C3=ADnez=20G=C3=B3mez?= Date: Sat, 17 Jun 2017 20:32:57 +0200 Subject: [PATCH 040/237] Fix broken test in Admin::EventsController We are using `paper_trail` gem, which saves data in database table versions. It has a native way to search in the versions records, using `where_object()` and `where_object_changes()`. They are broken, under certain conditions. We changed them to a manual `where()`. To test this case we need: an Event with ID 1, an Event with ID 2, and a commercial with ID 1, for event with ID 2 - obviously the numbers could be different as long as there is this matching of IDs. Before this was made wit ha expect, which would make the test fail if this is not the case. But this is actually the test case, not what we want to test, so I moved to the `let`. This was also the case why one of the test was broken after we change how the database is cleaned in: https://github.com/openSUSE/osem/pull/1541 I also remove the feature test, as this should be tested in a controller test. --- spec/controllers/admin/events_controller_spec.rb | 12 +++++++----- spec/features/versions_spec.rb | 2 -- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/controllers/admin/events_controller_spec.rb b/spec/controllers/admin/events_controller_spec.rb index a413ba7a..682defce 100644 --- a/spec/controllers/admin/events_controller_spec.rb +++ b/spec/controllers/admin/events_controller_spec.rb @@ -4,9 +4,13 @@ describe Admin::EventsController do let(:conference) { create(:conference) } let(:organizer_role) { Role.find_by(name: 'organizer', resource: conference) } let(:organizer) { create(:user, role_ids: organizer_role.id) } - let!(:event_without_commercial) { create(:event, program: conference.program) } - let!(:event_with_commercial) { create(:event, program: conference.program) } - let!(:event_commercial) { create(:event_commercial, commercialable: event_with_commercial, url: 'https://www.youtube.com/watch?v=M9bq_alk-sw') } + # The where_object() and where_object_changes() methods of paper_trail gem are broken when having: + # an Event with ID 1, an Event with ID 2, and a commercial with ID 1, for event with ID 2 + # (the numbers could be different as long as there is this matching of IDs). + # We implemented or own where method to solve this and those ids are for testing this case. + let!(:event_without_commercial) { create(:event, id: 1, program: conference.program) } + let!(:event_with_commercial) { create(:event, id: 2, program: conference.program) } + let!(:event_commercial) { create(:event_commercial, id: 1, commercialable: event_with_commercial, url: 'https://www.youtube.com/watch?v=M9bq_alk-sw') } with_versioning do describe 'GET #show' do @@ -17,8 +21,6 @@ describe Admin::EventsController do it 'assigns versions' do versions = event_without_commercial.versions - expect(event_without_commercial.id).to eq event_commercial.id - expect(event_commercial.id).not_to eq event_commercial.commercialable_id expect(assigns(:versions)).to eq versions end end diff --git a/spec/features/versions_spec.rb b/spec/features/versions_spec.rb index ff73eee0..90c0fa35 100644 --- a/spec/features/versions_spec.rb +++ b/spec/features/versions_spec.rb @@ -286,8 +286,6 @@ feature 'Version' do expect(page).to have_text('Someone (probably via the console) created new commercial') visit admin_conference_program_event_path(conference.short_title, event_without_commercial) click_link 'History' - expect(event_commercial.id).not_to eq event_commercial.commercialable_id - expect(event_without_commercial.id).to eq event_commercial.id expect(page).to have_no_text('Someone (probably via the console) created new commercial') end From 267f080ac77e6df04092676df1e148baffffa6f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=20Mar=C3=ADa=20Mart=C3=ADnez=20G=C3=B3mez?= Date: Mon, 26 Jun 2017 16:47:07 +0200 Subject: [PATCH 041/237] Enable Style/CommentAnnotation Rubocop cop This cop checks that comment annotation keywords are written according to guidelines. The offense was automatically corrected. --- .rubocop_todo.yml | 8 -------- app/models/event_user.rb | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index ef9bcd98..56ff7885 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -288,14 +288,6 @@ Style/ColonMethodCall: - 'app/models/commercial.rb' - 'app/models/contact.rb' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: Keywords. -# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW -Style/CommentAnnotation: - Exclude: - - 'app/models/event_user.rb' - # Offense count: 14 # Cop supports --auto-correct. Style/CommentIndentation: diff --git a/app/models/event_user.rb b/app/models/event_user.rb index 58adadad..70d9ca91 100644 --- a/app/models/event_user.rb +++ b/app/models/event_user.rb @@ -1,5 +1,5 @@ class EventUser < ActiveRecord::Base - # TODO Do we need these roles? + # TODO: Do we need these roles? ROLES = [%w[Speaker speaker], %w[Submitter submitter], %w[Moderator moderator]] belongs_to :event From 7fd738bc7d7bd5d2667b9163c78472a7486310fb Mon Sep 17 00:00:00 2001 From: Dimitris Date: Fri, 16 Jun 2017 02:51:01 +0300 Subject: [PATCH 042/237] Add option to render html at format_helper --- app/helpers/format_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/format_helper.rb b/app/helpers/format_helper.rb index bd64e3ac..472edc38 100644 --- a/app/helpers/format_helper.rb +++ b/app/helpers/format_helper.rb @@ -176,7 +176,7 @@ module FormatHelper (schedule == @selected_schedule) ? 'Yes' : 'No' end - def markdown(text) + def markdown(text, escape_html=true) return '' if text.nil? options = { @@ -184,12 +184,12 @@ module FormatHelper space_after_headers: true, no_intra_emphasis: true } - markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(escape_html: true), options) + markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(escape_html: escape_html), options) markdown.render(text).html_safe end def markdown_hint(text='') - markdown("#{text} Please look at #{link_to '**Markdown Syntax**', 'https://daringfireball.net/projects/markdown/syntax', target: '_blank'} to format your text") + markdown("#{text} Please look at #{link_to '**Markdown Syntax**', 'https://daringfireball.net/projects/markdown/syntax', target: '_blank'} to format your text", false) end def quantity_left_of(resource) From c3eb178546fe341b1fa1ad62b9362d79296cb06b Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Tue, 30 May 2017 20:54:48 +0300 Subject: [PATCH 043/237] Modify CFP to accept proposals for other things Add field cfp_type and relevant validations Add Program#cfp to preserve backwards compatibility Add 'for_events' scope to the cfp, in order for it to be used like program.cfps.events Add useful methods Add rspec test for the new code The supported cfp types can be viewed via Cfp::TYPES --- .rubocop_todo.yml | 1 + app/controllers/admin/cfps_controller.rb | 3 +- app/models/cfp.rb | 23 ++++++++++ app/models/program.rb | 21 +++++++++- db/migrate/20170530072155_add_type_to_cfps.rb | 15 +++++++ db/schema.rb | 1 + spec/models/cfp_spec.rb | 42 ++++++++++++++++++- spec/models/program_spec.rb | 19 +++++++++ 8 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20170530072155_add_type_to_cfps.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 56ff7885..68360907 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -645,6 +645,7 @@ Style/PercentLiteralDelimiters: - 'app/models/contact.rb' - 'app/models/registration.rb' - 'app/models/subscription.rb' + - 'app/models/cfp.rb' - 'app/uploaders/picture_uploader.rb' - 'spec/models/ability_spec.rb' - 'spec/models/program_spec.rb' diff --git a/app/controllers/admin/cfps_controller.rb b/app/controllers/admin/cfps_controller.rb index 42d10218..81fd78a9 100644 --- a/app/controllers/admin/cfps_controller.rb +++ b/app/controllers/admin/cfps_controller.rb @@ -2,7 +2,7 @@ module Admin class CfpsController < Admin::BaseController load_and_authorize_resource :conference, find_by: :short_title load_and_authorize_resource :program, through: :conference, singleton: true - load_and_authorize_resource through: :program, singleton: true + load_and_authorize_resource through: :program def show; end @@ -27,7 +27,6 @@ module Admin end def update - @cfp = @program.cfp @cfp.assign_attributes(cfp_params) send_mail_on_cfp_dates_updates = @cfp.notify_on_cfp_date_update? diff --git a/app/models/cfp.rb b/app/models/cfp.rb index affcc408..92058e87 100644 --- a/app/models/cfp.rb +++ b/app/models/cfp.rb @@ -1,6 +1,10 @@ # cannot delete program if there are events submitted class Cfp < ActiveRecord::Base + TYPES = %w(events).freeze + + scope :for_events, (-> { find_by(cfp_type: 'events') }) + has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id } belongs_to :program @@ -8,6 +12,15 @@ class Cfp < ActiveRecord::Base validates :start_date, :end_date, presence: true validate :before_end_of_conference validate :start_after_end_date + validates :cfp_type, + presence: true, + inclusion: { + in: TYPES + }, + uniqueness: { + scope: :program, + case_sensitive: false + } ## # Checks whether cfp date is updated @@ -55,6 +68,16 @@ class Cfp < ActiveRecord::Base result > 0 ? result : 0 end + ## + # Checks if the call for papers is currently open + # + # ====Returns + # * +false+ -> If the CFP is not set or today isn't in the CFP period. + # * +true+ -> If today is in the CFP period. + def open? + (start_date..end_date).cover?(Date.current) + end + private def before_end_of_conference diff --git a/app/models/program.rb b/app/models/program.rb index e36d65bf..09bb3627 100644 --- a/app/models/program.rb +++ b/app/models/program.rb @@ -5,7 +5,7 @@ class Program < ActiveRecord::Base belongs_to :conference - has_one :cfp, dependent: :destroy + has_many :cfps, dependent: :destroy has_many :event_types, dependent: :destroy has_many :tracks, dependent: :destroy has_many :difficulty_levels, dependent: :destroy @@ -135,7 +135,7 @@ class Program < ActiveRecord::Base # * +false+ -> If the CFP is not set or today isn't in the CFP period. # * +true+ -> If today is in the CFP period. def cfp_open? - cfp = self.cfp + cfp = cfps.events cfp.present? && (cfp.start_date..cfp.end_date).cover?(Date.current) end @@ -163,6 +163,23 @@ class Program < ActiveRecord::Base EventSchedule.where(schedule: selected_schedule).where(start_time: parsed_date..(parsed_date + 1)).any? end + ## + # Provides backwards compatibility for when the program had one cfp + # + # ====Returns + # * +ActiveRecord+ -> The program's cfp with cfp_type == 'events' + def cfp + return nil if cfps.for_events.blank? + cfps.for_events + end + + ## + # ====Returns + # * +Array+ -> The types of cfps for which a cfp doesn't exist yet + def remaining_cfp_types + Cfp::TYPES - cfps.pluck(:cfp_type) + end + private ## diff --git a/db/migrate/20170530072155_add_type_to_cfps.rb b/db/migrate/20170530072155_add_type_to_cfps.rb new file mode 100644 index 00000000..50423281 --- /dev/null +++ b/db/migrate/20170530072155_add_type_to_cfps.rb @@ -0,0 +1,15 @@ +class AddTypeToCfps < ActiveRecord::Migration + class TmpCfp < ActiveRecord::Base + self.table_name = 'cfps' + end + + def change + add_column :cfps, :cfp_type, :string + + TmpCfp.reset_column_information + TmpCfp.find_each do |cfp| + cfp.cfp_type = 'events' + cfp.save! + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 19a3df19..348f6170 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -52,6 +52,7 @@ ActiveRecord::Schema.define(version: 20170603095900) do t.datetime "created_at" t.datetime "updated_at" t.integer "program_id" + t.string "cfp_type" end create_table "comments", force: :cascade do |t| diff --git a/spec/models/cfp_spec.rb b/spec/models/cfp_spec.rb index 3f8e7a0f..606f5f9f 100644 --- a/spec/models/cfp_spec.rb +++ b/spec/models/cfp_spec.rb @@ -1,8 +1,24 @@ require 'spec_helper' describe Cfp do + subject { create(:cfp) } let!(:conference) { create(:conference, end_date: Date.today) } - let!(:cfp) { build(:cfp, start_date: Date.today - 2, end_date: Date.today - 1, program_id: conference.program.id) } + let!(:cfp) { create(:cfp, start_date: Date.today - 2, end_date: Date.today - 1, program_id: conference.program.id) } + + describe 'scope' do + describe '#for_events' do + it 'returns the cfp for events' do + expect(conference.program.cfps.for_events).to be_a Cfp + expect(conference.program.cfps.for_events.cfp_type).to eq('events') + end + end + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:cfp_type) } + it { is_expected.to validate_inclusion_of(:cfp_type).in_array(Cfp::TYPES) } + it { is_expected.to validate_uniqueness_of(:cfp_type).scoped_to(:program_id).case_insensitive } + end describe '#before_end_of_conference' do describe 'fails to save cfp' do @@ -97,4 +113,28 @@ describe Cfp do end end end + + describe '#open?' do + context 'returns false' do + it 'when start and end dates are in the past' do + cfp.start_date = Date.current - 3 + cfp.end_date = Date.current - 1 + expect(cfp.open?).to eq(false) + end + + it 'when start and end dates are in the future' do + cfp.start_date = Date.current + 1 + cfp.end_date = Date.current + 3 + expect(cfp.open?).to eq(false) + end + end + + context 'returns true' do + it 'when start date is in the past and end date is in the future' do + cfp.start_date = Date.current - 1 + cfp.end_date = Date.current + 1 + expect(cfp.open?).to eq(true) + end + end + end end diff --git a/spec/models/program_spec.rb b/spec/models/program_spec.rb index a2106791..6ea62cf0 100644 --- a/spec/models/program_spec.rb +++ b/spec/models/program_spec.rb @@ -240,4 +240,23 @@ describe Program do end end + describe '#cfp' do + it 'returns the cfp for events' do + create(:cfp, cfp_type: 'events', program: program, end_date: Date.current + 1) + expect(program.cfp).to be_a Cfp + expect(program.cfp.cfp_type).to eq('events') + end + + it 'returns nil if the program doesn\'t have a cfp' do + expect(program.cfp).to eq(nil) + end + end + + describe '#remaining_cfp_types' do + it 'returns an array with the types for which a cfp doesn\'t exist' do + expect(program.remaining_cfp_types).to eq(Cfp::TYPES) + create(:cfp, cfp_type: 'events', program: program, end_date: Date.current + 1) + expect(program.remaining_cfp_types).to eq([]) + end + end end From 2bff9185563c7f174f5b59be91d87ceca4a4db9f Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 31 May 2017 21:03:15 +0300 Subject: [PATCH 044/237] Add index view for the cfp and modify existing ones Add cfp_type to the form partial Refactor Cfps#show to use partials for the different cfp types Modify the rest of the view, where the cfp was used --- .haml-lint_todo.yml | 5 +- app/controllers/admin/cfps_controller.rb | 16 ++--- app/views/admin/cfps/_events_cfp.html.haml | 38 ++++++++++++ app/views/admin/cfps/_form.html.haml | 3 +- app/views/admin/cfps/index.html.haml | 36 +++++++++++ app/views/admin/cfps/show.html.haml | 62 +++---------------- .../admin/conferences/_todo_list.html.haml | 2 +- .../versions/_object_desc_and_link.html.haml | 6 +- app/views/layouts/_admin_sidebar.html.haml | 4 +- config/routes.rb | 2 +- 10 files changed, 107 insertions(+), 67 deletions(-) create mode 100644 app/views/admin/cfps/_events_cfp.html.haml create mode 100644 app/views/admin/cfps/index.html.haml diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 918178e2..0f6f5408 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -171,6 +171,7 @@ linters: - "app/views/tickets/index.html.haml" - "app/views/users/edit.html.haml" - "app/views/users/show.html.haml" + - "app/views/admin/cfps/index.html.haml" # Offense count: 223 InstanceVariables: @@ -229,6 +230,7 @@ linters: - "app/views/schedules/_schedule.html.haml" - "app/views/schedules/_schedule_item.html.haml" - "app/views/schedules/_schedule_tabs.html.haml" + - "app/views/admin/cfps/_events_cfp.html.haml" # Offense count: 32 IdNames: @@ -247,6 +249,7 @@ linters: - "app/views/admin/users/_event_registrations.html.haml" - "app/views/admin/users/show.html.haml" - "app/views/users/edit.html.haml" + - "app/views/admin/cfps/_events_cfp.html.haml" # Offense count: 4 UnnecessaryInterpolation: @@ -423,4 +426,4 @@ linters: exclude: - "app/views/conferences/_gallery.html.haml" - "app/views/layouts/_navigation.html.haml" - - "app/views/schedules/events.html.haml" \ No newline at end of file + - "app/views/schedules/events.html.haml" diff --git a/app/controllers/admin/cfps_controller.rb b/app/controllers/admin/cfps_controller.rb index 81fd78a9..da2723b7 100644 --- a/app/controllers/admin/cfps_controller.rb +++ b/app/controllers/admin/cfps_controller.rb @@ -4,21 +4,23 @@ module Admin load_and_authorize_resource :program, through: :conference, singleton: true load_and_authorize_resource through: :program + def index; end + def show; end def new - @cfp = @program.build_cfp + @cfp = @program.cfps.new end def edit; end def create - @cfp = @program.build_cfp(cfp_params) + @cfp = @program.cfps.new(cfp_params) send_mail_on_cfp_dates_updates = @cfp.notify_on_cfp_date_update? if @cfp.save ConferenceCfpUpdateMailJob.perform_later(@conference) if send_mail_on_cfp_dates_updates - redirect_to admin_conference_program_cfp_path, + redirect_to admin_conference_program_cfps_path, notice: 'Call for papers successfully created.' else flash.now[:error] = "Creating the call for papers failed. #{@cfp.errors.full_messages.join('. ')}." @@ -33,7 +35,7 @@ module Admin if @cfp.update_attributes(cfp_params) ConferenceCfpUpdateMailJob.perform_later(@conference) if send_mail_on_cfp_dates_updates - redirect_to admin_conference_program_cfp_path(@conference.short_title), + redirect_to admin_conference_program_cfps_path(@conference.short_title), notice: 'Call for papers successfully updated.' else flash.now[:error] = "Updating call for papers failed. #{@cfp.errors.to_a.join('. ')}." @@ -43,9 +45,9 @@ module Admin def destroy if @cfp.destroy - redirect_to admin_conference_program_cfp_path, notice: 'Call for Papers was successfully deleted.' + redirect_to admin_conference_program_cfps_path, notice: 'Call for Papers was successfully deleted.' else - redirect_to admin_conference_program_cfp_path, error: 'An error prohibited this Call for Papers from being destroyed: '\ + redirect_to admin_conference_program_cfps_path, error: 'An error prohibited this Call for Papers from being destroyed: '\ "#{@cfp.errors.full_messages.join('. ')}." end end @@ -53,7 +55,7 @@ module Admin private def cfp_params - params.require(:cfp).permit(:start_date, :end_date) + params.require(:cfp).permit(:start_date, :end_date, :cfp_type) end end end diff --git a/app/views/admin/cfps/_events_cfp.html.haml b/app/views/admin/cfps/_events_cfp.html.haml new file mode 100644 index 00000000..51bc2079 --- /dev/null +++ b/app/views/admin/cfps/_events_cfp.html.haml @@ -0,0 +1,38 @@ +%dt + Start Date: +%dd#start_date + = @cfp.start_date.strftime('%A, %B %-d. %Y') +%dt + End Date: +%dd#end_date + = @cfp.end_date.strftime('%A, %B %-d. %Y') +%dt + Days Left: +%dd + = pluralize(@cfp.remaining_days, 'day') +%dt + Event types: +%dd + = event_types(@conference) +%dt + Tracks: +%dd + = tracks(@conference) +%dt + Public Schedule +%dd#schedule_public + - if @program.schedule_public + Yes + - else + No +%dt + Schedule changeable? +%dd#schedule_changes + - if @program.schedule_fluid + Yes + - else + No +%dt + Rating Levels +%dd#rating + = @program.rating diff --git a/app/views/admin/cfps/_form.html.haml b/app/views/admin/cfps/_form.html.haml index e8110406..a02f3a02 100644 --- a/app/views/admin/cfps/_form.html.haml +++ b/app/views/admin/cfps/_form.html.haml @@ -4,8 +4,9 @@ %h1 Call for Papers .row .col-md-8 - = semantic_form_for(@cfp, url: admin_conference_program_cfp_path(@conference.short_title), html: {multipart: true}) do |f| + = semantic_form_for(@cfp, url: (@cfp.new_record? ? admin_conference_program_cfps_path : admin_conference_program_cfp_path(@conference.short_title, @cfp)), html: {multipart: true}) do |f| = f.input :start_date, as: :string, input_html: { id: 'registration-period-start-datepicker', start_date: @conference.start_date, end_date: @conference.end_date, readonly: 'readonly' } = f.input :end_date, as: :string, input_html: { id: 'registration-period-end-datepicker', readonly: 'readonly' } + = f.input :cfp_type, as: :select, collection: (@cfp.new_record? ? @program.remaining_cfp_types : [@cfp.cfp_type] + @program.remaining_cfp_types).map {|type| ["#{type.capitalize}", type]}, include_blank: false, label: 'Type', input_html: { class: 'select-help-toggle' } %p.text-right = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/cfps/index.html.haml b/app/views/admin/cfps/index.html.haml new file mode 100644 index 00000000..16ab8e84 --- /dev/null +++ b/app/views/admin/cfps/index.html.haml @@ -0,0 +1,36 @@ +.row + .col-md-12 + .page-header + %h1 Call for Papers + %p.text-muted + Call for people to submit events to your conference +- if @program.cfps + .row + .col-md-12 + %table.table.table-hover.datatable#tickets + %thead + %th Type + %th Start Date + %th End Date + %th Days Left + %th Actions + %tbody + - @program.cfps.each do |cfp| + %tr + %td + = link_to(admin_conference_program_cfp_path(@conference.short_title, cfp.id)) do + = cfp.cfp_type.capitalize + %td + = cfp.start_date.strftime('%A, %B %-d. %Y') + %td + = cfp.end_date.strftime('%A, %B %-d. %Y') + %td + = pluralize(cfp.remaining_days, 'day') + %td + .btn-group + = link_to 'Edit', edit_admin_conference_program_cfp_path(@conference.short_title, cfp.id), method: :get, class: 'btn btn-primary' + = link_to 'Delete', admin_conference_program_cfp_path(@conference.short_title, cfp.id), method: 'delete', class: 'btn btn-danger', data: { confirm: 'Are you sure you want to delete the CfP?' } +- if @program.remaining_cfp_types.length > 0 + .row + .col-md-12.text-right + = link_to 'Create Call for Papers', new_admin_conference_program_cfp_path(@conference.short_title), class: 'btn btn-primary' diff --git a/app/views/admin/cfps/show.html.haml b/app/views/admin/cfps/show.html.haml index 09441508..e2a043ea 100644 --- a/app/views/admin/cfps/show.html.haml +++ b/app/views/admin/cfps/show.html.haml @@ -4,55 +4,13 @@ %h1 Call for Papers %p.text-muted Call for people to submit events to your conference -- if @cfp - .row - .col-md-8 - %dl.dl-horizontal - %dt - Start Date: - %dd#start_date - = @cfp.start_date.strftime('%A, %B %-d. %Y') - %dt - End Date: - %dd#end_date - = @cfp.end_date.strftime('%A, %B %-d. %Y') - %dt - Days Left: - %dd - = pluralize(@cfp.remaining_days, 'day') - %dt - Event types: - %dd - = event_types(@conference) - %dt - Tracks: - %dd - = tracks(@conference) - %dt - Public Schedule - %dd#schedule_public - - if @program.schedule_public - Yes - - else - No - %dt - Schedule changeable? - %dd#schedule_changes - - if @program.schedule_fluid - Yes - - else - No - %dt - Rating Levels - %dd#rating - = @program.rating - .row - .col-md-12.text-right - = link_to(edit_admin_conference_program_cfp_path(@conference.short_title), class: 'btn btn-primary') do - Edit - = link_to(admin_conference_program_cfp_path(@conference.short_title), method: 'delete', class: 'btn btn-danger', data: { confirm: 'Are you sure you want to delete the CfP?' }) do - Delete -- else - .row - .col-md-12.text-right - = link_to 'Create Call for Papers', new_admin_conference_program_cfp_path(@conference.short_title), class: 'btn btn-primary' +.row + .col-md-8 + %dl.dl-horizontal + = render "#{@cfp.cfp_type}_cfp" +.row + .col-md-12.text-right + = link_to(edit_admin_conference_program_cfp_path(@conference.short_title, @cfp.id), class: 'btn btn-primary') do + Edit + = link_to(admin_conference_program_cfp_path(@conference.short_title, @cfp.id), method: 'delete', class: 'btn btn-danger', data: { confirm: 'Are you sure you want to delete the CfP?' }) do + Delete diff --git a/app/views/admin/conferences/_todo_list.html.haml b/app/views/admin/conferences/_todo_list.html.haml index 63f4e3aa..88bb7c36 100644 --- a/app/views/admin/conferences/_todo_list.html.haml +++ b/app/views/admin/conferences/_todo_list.html.haml @@ -18,7 +18,7 @@ %li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['cfp'])}" } %span{ 'class' => icon_for_todo(conference_progress['cfp']) } - if can? :update, Cfp.new(program_id: @program.id) - = link_to 'Set up call for papers', admin_conference_program_cfp_path(conference_progress['short_title']) + = link_to 'Set up call for papers', admin_conference_program_cfps_path(conference_progress['short_title']) - else Set up call for papers %li{'class'=>"list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['venue'])}"} diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index 44eedf82..1c7ed154 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -85,8 +85,10 @@ admin_conference_program_path(conference_id: Conference.find(version.conference_id).short_title) - when 'Cfp' - = link_if_alive version, 'cfp', - admin_conference_program_cfp_path(conference_id: Conference.find(version.conference_id).short_title) + = 'cfp' + - cfp = current_or_last_object_state(version.item_type, version.item_id) + = link_if_alive version, cfp.cfp_type, + admin_conference_program_cfp_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) - when 'Track' = 'track' diff --git a/app/views/layouts/_admin_sidebar.html.haml b/app/views/layouts/_admin_sidebar.html.haml index a9a2a99a..2c3eaf52 100644 --- a/app/views/layouts/_admin_sidebar.html.haml +++ b/app/views/layouts/_admin_sidebar.html.haml @@ -67,8 +67,8 @@ - if @conference.program %ul - if can? :update, Cfp.new(program_id: @conference.program.id) - %li{class: active_nav_li(admin_conference_program_cfp_path(@conference.short_title))} - = link_to 'Call for Papers', admin_conference_program_cfp_path(@conference.short_title) + %li{class: active_nav_li(admin_conference_program_cfps_path(@conference.short_title))} + = link_to 'Call for Papers', admin_conference_program_cfps_path(@conference.short_title) - if can? :update, @conference.program.events.build %li{class: active_nav_li(admin_conference_program_events_path(@conference.short_title))} = link_to 'Events', admin_conference_program_events_path(@conference.short_title) diff --git a/config/routes.rb b/config/routes.rb index 60b03f54..8fa4b857 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -53,7 +53,7 @@ Osem::Application.routes.draw do end resource :registration_period resource :program do - resource :cfp + resources :cfps resources :tracks resources :event_types resources :difficulty_levels From a1124546f1fa5e9b98596845e0d9525dd4162009 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Thu, 1 Jun 2017 01:11:28 +0300 Subject: [PATCH 045/237] Fix rspec tests because of the changes to the cfp Remove redundant association Note: a conference created with :full_conference already has a cfp --- app/models/cfp.rb | 4 +- app/models/program.rb | 2 +- app/models/registration.rb | 1 - .../versions/_object_desc_and_link.html.haml | 2 +- .../admin/conferences_controller_spec.rb | 8 +- spec/controllers/proposals_controller_spec.rb | 8 +- spec/factories/cfps.rb | 1 + spec/factories/programs.rb | 4 + spec/features/ability_spec.rb | 14 ++-- spec/features/cfp_spec.rb | 8 +- spec/features/versions_spec.rb | 6 +- spec/models/ability_spec.rb | 4 +- spec/models/conference_spec.rb | 80 +++++++++---------- spec/models/email_settings_spec.rb | 7 +- spec/models/program_spec.rb | 2 +- spec/models/registration_spec.rb | 1 - 16 files changed, 78 insertions(+), 74 deletions(-) diff --git a/app/models/cfp.rb b/app/models/cfp.rb index 92058e87..f06bec7b 100644 --- a/app/models/cfp.rb +++ b/app/models/cfp.rb @@ -81,12 +81,12 @@ class Cfp < ActiveRecord::Base private def before_end_of_conference - if program.conference && program.conference.end_date && end_date && (end_date > program.conference.end_date) + if program && program.conference && program.conference.end_date && end_date && (end_date > program.conference.end_date) errors .add(:end_date, "can't be after the conference end date (#{program.conference.end_date})") end - if program.conference && program.conference.end_date && start_date && (start_date > program.conference.end_date) + if program && program.conference && program.conference.end_date && start_date && (start_date > program.conference.end_date) errors .add(:start_date, "can't be after the conference end date (#{program.conference.end_date})") end diff --git a/app/models/program.rb b/app/models/program.rb index 09bb3627..49894cbd 100644 --- a/app/models/program.rb +++ b/app/models/program.rb @@ -135,7 +135,7 @@ class Program < ActiveRecord::Base # * +false+ -> If the CFP is not set or today isn't in the CFP period. # * +true+ -> If today is in the CFP period. def cfp_open? - cfp = cfps.events + cfp = self.cfp cfp.present? && (cfp.start_date..cfp.end_date).cover?(Date.current) end diff --git a/app/models/registration.rb b/app/models/registration.rb index 5d2555f2..7003dfd7 100644 --- a/app/models/registration.rb +++ b/app/models/registration.rb @@ -2,7 +2,6 @@ class Registration < ActiveRecord::Base belongs_to :user belongs_to :conference - has_and_belongs_to_many :events has_and_belongs_to_many :qanswers has_and_belongs_to_many :vchoices diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index 1c7ed154..14b1f2fc 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -85,7 +85,7 @@ admin_conference_program_path(conference_id: Conference.find(version.conference_id).short_title) - when 'Cfp' - = 'cfp' + = 'cfp for' - cfp = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, cfp.cfp_type, admin_conference_program_cfp_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) diff --git a/spec/controllers/admin/conferences_controller_spec.rb b/spec/controllers/admin/conferences_controller_spec.rb index 3964996f..74acbb3f 100644 --- a/spec/controllers/admin/conferences_controller_spec.rb +++ b/spec/controllers/admin/conferences_controller_spec.rb @@ -177,10 +177,10 @@ describe Admin::ConferencesController do it 'assigns cfp_max an array with maximum weeks' do conference date = Date.new(2014, 05, 26) - conference.program.cfp = create(:cfp, - program: conference.program, - start_date: date, - end_date: date + 14) + create(:cfp, + program: conference.program, + start_date: date, + end_date: date + 14) get :index expect(assigns(:cfp_weeks)).to match_array([1, 2, 3]) end diff --git a/spec/controllers/proposals_controller_spec.rb b/spec/controllers/proposals_controller_spec.rb index 8f033973..9b01e55f 100644 --- a/spec/controllers/proposals_controller_spec.rb +++ b/spec/controllers/proposals_controller_spec.rb @@ -10,7 +10,7 @@ describe ProposalsController do describe 'GET #new' do before do # We allow new proposal only if program has open cfp - conference.program.update_attributes(cfp: create(:cfp)) + create(:cfp, program: conference.program) get :new, conference_id: conference.short_title end @@ -26,7 +26,7 @@ describe ProposalsController do describe 'POST #create' do # We allow proposal create only if program has open cfp - before { conference.program.update_attributes(cfp: create(:cfp)) } + before { create(:cfp, program: conference.program) } it 'assigns url variables' do post :create, event: attributes_for(:event, event_type_id: event_type.id), @@ -192,7 +192,7 @@ describe ProposalsController do describe 'GET #new' do before do # We allow new proposal only if program has open cfp - conference.program.update_attributes(cfp: create(:cfp)) + create(:cfp, program: conference.program) get :new, conference_id: conference.short_title end @@ -223,7 +223,7 @@ describe ProposalsController do describe 'POST #create' do # We allow proposal create only if program has open cfp - before { conference.program.update_attributes(cfp: create(:cfp)) } + before { create(:cfp, program: conference.program) } it 'assigns url variables' do post :create, event: attributes_for(:event, event_type_id: event_type.id), diff --git a/spec/factories/cfps.rb b/spec/factories/cfps.rb index 1ff58b9d..6a8e96ed 100644 --- a/spec/factories/cfps.rb +++ b/spec/factories/cfps.rb @@ -4,6 +4,7 @@ FactoryGirl.define do factory :cfp do start_date { 1.day.ago } end_date { 6.days.from_now } + cfp_type 'events' program end diff --git a/spec/factories/programs.rb b/spec/factories/programs.rb index a1a6e1f7..e3c20153 100644 --- a/spec/factories/programs.rb +++ b/spec/factories/programs.rb @@ -5,5 +5,9 @@ FactoryGirl.define do schedule_public false schedule_fluid false conference + + trait :with_cfp do + after(:create) { |program| create(:cfp, program: program) } + end end end diff --git a/spec/features/ability_spec.rb b/spec/features/ability_spec.rb index 80e968bd..162123f4 100644 --- a/spec/features/ability_spec.rb +++ b/spec/features/ability_spec.rb @@ -40,7 +40,7 @@ feature 'Has correct abilities' do expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference1.short_title}/venue/rooms") expect(page).to have_link('Lodgings', href: "/admin/conferences/#{conference1.short_title}/lodgings") expect(page).to have_link('Program', href: "/admin/conferences/#{conference1.short_title}/program") - expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference1.short_title}/program/cfp") + expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference1.short_title}/program/cfps") expect(page).to have_link('Events', href: "/admin/conferences/#{conference1.short_title}/program/events") expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference1.short_title}/program/tracks") expect(page).to have_link('Event Types', href: "/admin/conferences/#{conference1.short_title}/program/event_types") @@ -112,8 +112,8 @@ feature 'Has correct abilities' do visit new_admin_conference_program_cfp_path(conference1.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference1.short_title)) - visit edit_admin_conference_program_cfp_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference1.short_title)) + visit edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp)) visit admin_conference_program_events_path(conference1.short_title) expect(current_path).to eq(admin_conference_program_events_path(conference1.short_title)) @@ -256,7 +256,7 @@ feature 'Has correct abilities' do expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference2.short_title}/venue/rooms") expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference2.short_title}/lodgings") expect(page).to have_link('Program', href: "/admin/conferences/#{conference2.short_title}/program") - expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference2.short_title}/program/cfp") + expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference2.short_title}/program/cfps") expect(page).to have_link('Events', href: "/admin/conferences/#{conference2.short_title}/program/events") expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference2.short_title}/program/tracks") expect(page).to have_link('Event Types', href: "/admin/conferences/#{conference2.short_title}/program/event_types") @@ -324,8 +324,8 @@ feature 'Has correct abilities' do visit new_admin_conference_program_cfp_path(conference2.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference2.short_title)) - visit edit_admin_conference_program_cfp_path(conference2.short_title) - expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference2.short_title)) + visit edit_admin_conference_program_cfp_path(conference2.short_title, conference2.program.cfp) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference2.short_title, conference2.program.cfp)) visit admin_conference_program_events_path(conference2.short_title) expect(current_path).to eq(admin_conference_program_events_path(conference2.short_title)) @@ -537,7 +537,7 @@ feature 'Has correct abilities' do visit new_admin_conference_program_cfp_path(conference3.short_title) expect(current_path).to eq(root_path) - visit edit_admin_conference_program_cfp_path(conference3.short_title) + visit edit_admin_conference_program_cfp_path(conference3.short_title, conference3.program.cfp) expect(current_path).to eq(root_path) visit admin_conference_program_events_path(conference3.short_title) diff --git a/spec/features/cfp_spec.rb b/spec/features/cfp_spec.rb index 8869de1f..7ecfb1e6 100644 --- a/spec/features/cfp_spec.rb +++ b/spec/features/cfp_spec.rb @@ -31,6 +31,8 @@ feature Conference do # Validations expect(flash) .to eq('Call for papers successfully created.') + + visit admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) expect(find('#start_date').text).to eq(today.strftime('%A, %B %-d. %Y')) expect(find('#end_date').text).to eq((today + 6).strftime('%A, %B %-d. %Y')) @@ -38,11 +40,11 @@ feature Conference do end scenario 'update cfp', feature: true, js: true do - conference.program.cfp = create(:cfp) + create(:cfp, program: conference.program) expected_count = Cfp.count sign_in organizer - visit admin_conference_program_cfp_path(conference.short_title) + visit admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) click_link 'Edit' # Validate update with empty start date will not saved @@ -65,6 +67,8 @@ feature Conference do # Validations expect(flash) .to eq('Call for papers successfully updated.') + + visit admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) expect(find('#start_date').text).to eq(today.strftime('%A, %B %-d. %Y')) expect(find('#end_date').text).to eq((today + 14).strftime('%A, %B %-d. %Y')) expect(Cfp.count).to eq(expected_count) diff --git a/spec/features/versions_spec.rb b/spec/features/versions_spec.rb index 90c0fa35..11afa1d2 100644 --- a/spec/features/versions_spec.rb +++ b/spec/features/versions_spec.rb @@ -38,9 +38,9 @@ feature 'Version' do cfp.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new cfp in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated start date and end date of cfp in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted cfp in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new cfp for events in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated start date and end date of cfp for events in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted cfp for events in conference #{conference.short_title}") end scenario 'display changes in registration_period', feature: true, versioning: true, js: true do diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 6ddc44e6..001c7365 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -10,7 +10,6 @@ describe 'User' do let(:user){ nil } let!(:my_conference) { create(:full_conference) } - let!(:my_cfp) { create(:cfp, program: my_conference.program) } let(:my_venue) { my_conference.venue || create(:venue, conference: my_conference) } let(:my_registration) { create(:registration, conference: my_conference, user: admin) } @@ -22,7 +21,6 @@ describe 'User' do let(:conference_not_public) { create(:conference, splashpage: create(:splashpage, public: false)) } let(:conference_public) { create(:full_conference, splashpage: create(:splashpage, public: true)) } - let!(:conference_public_cfp) { create(:cfp, program: conference_public.program) } let(:event_confirmed) { create(:event, state: 'confirmed') } let(:event_unconfirmed) { create(:event) } @@ -32,7 +30,7 @@ describe 'User' do let(:resource) { create(:resource, conference: my_conference)} let(:registration) { create(:registration) } - let(:program_with_cfp) { create(:program, cfp: create(:cfp)) } + let(:program_with_cfp) { create(:program, :with_cfp) } let(:program_without_cfp) { create(:program) } let(:conference_with_open_registration) { create(:conference) } let!(:open_registration_period) { create(:registration_period, conference: conference_with_open_registration, start_date: Date.current - 6.days) } diff --git a/spec/models/conference_spec.rb b/spec/models/conference_spec.rb index 9bdbea83..d6e4f485 100755 --- a/spec/models/conference_spec.rb +++ b/spec/models/conference_spec.rb @@ -48,7 +48,7 @@ describe Conference do subject.start_date = Date.today + 6.weeks subject.end_date = Date.today + 7.weeks subject.save - subject.program.cfp = create(:cfp, start_date: Date.today - 3.weeks) + create(:cfp, start_date: Date.today - 3.weeks, program: subject.program) create(:event, program: subject.program, created_at: Date.today) options = {} @@ -115,7 +115,7 @@ describe Conference do } subject.events_per_week = db_data subject.save - subject.program.cfp = create(:cfp, start_date: Date.today - 3.weeks) + create(:cfp, start_date: Date.today - 3.weeks, program: subject.program) create(:event, program: subject.program, created_at: Date.today) unconfirmed = create(:event, program: subject.program) @@ -186,7 +186,7 @@ describe Conference do subject.events_per_week = db_data subject.save - subject.program.cfp = create(:cfp, start_date: Date.today - 2.weeks) + create(:cfp, start_date: Date.today - 2.weeks, program: subject.program) create(:event, program: subject.program, created_at: Date.today - 2.weeks) @@ -203,7 +203,7 @@ describe Conference do subject.start_date = Date.today + 6.weeks subject.end_date = Date.today + 7.weeks subject.save - subject.program.cfp = create(:cfp, start_date: Date.today) + create(:cfp, start_date: Date.today, program: subject.program) create(:event, program: subject.program) result = { @@ -220,7 +220,7 @@ describe Conference do subject.start_date = Date.today + 6.weeks subject.end_date = Date.today + 7.weeks subject.save - subject.program.cfp = create(:cfp, start_date: Date.today - 3.weeks) + create(:cfp, start_date: Date.today - 3.weeks, program: subject.program) create(:event, program: subject.program, created_at: Date.today) unconfirmed = create(:event, program: subject.program) @@ -258,7 +258,7 @@ describe Conference do subject.events_per_week = db_data subject.save - subject.program.cfp = create(:cfp, start_date: Date.today - 3.weeks) + create(:cfp, start_date: Date.today - 3.weeks, program: subject.program) create(:event, program: subject.program, created_at: Date.today - 3.weeks) @@ -992,7 +992,6 @@ describe Conference do end it 'calculates correct for new conference' do - subject.program.cfp = nil subject.venue = nil subject.program.tracks = [] subject.program.event_types = [] @@ -1006,7 +1005,6 @@ describe Conference do subject.registration_period = create(:registration_period, start_date: subject.end_date - 14, end_date: subject.end_date, conference: subject) - subject.program.cfp = nil subject.venue = nil subject.program.event_types = [] subject.program.tracks = [] @@ -1024,7 +1022,7 @@ describe Conference do subject.registration_period = create(:registration_period, start_date: subject.end_date - 14, end_date: subject.end_date, conference: subject) - subject.program.cfp = create(:cfp) + create(:cfp, program: subject.program) subject.venue = nil subject.program.tracks = [] subject.program.event_types = [] @@ -1043,7 +1041,7 @@ describe Conference do subject.registration_period = create(:registration_period, start_date: subject.end_date - 14, end_date: subject.end_date, conference: subject) - subject.program.cfp = create(:cfp) + create(:cfp, program: subject.program) subject.venue = create(:venue, conference: subject) subject.venue.rooms = [] subject.program.tracks = [] @@ -1063,7 +1061,7 @@ describe Conference do subject.registration_period = create(:registration_period, start_date: Date.today, end_date: Date.today + 14, conference: subject) - subject.program.cfp = create(:cfp) + create(:cfp, program: subject.program) subject.venue = create(:venue, conference: subject) subject.venue.rooms = [create(:room, venue: subject.venue)] subject.program.tracks = [] @@ -1087,7 +1085,7 @@ describe Conference do subject.registration_period = create(:registration_period, start_date: Date.today, end_date: Date.today + 14, conference: subject) - subject.program.cfp = create(:cfp) + create(:cfp, program: subject.program) subject.program.event_types = [] subject.program.difficulty_levels = [] subject.splashpage = create(:splashpage, public: false) @@ -1109,7 +1107,7 @@ describe Conference do subject.registration_period = create(:registration_period, start_date: Date.today, end_date: Date.today + 14, conference: subject) - subject.program.cfp = create(:cfp) + create(:cfp, program: subject.program) subject.venue = create(:venue, conference: subject) subject.venue.rooms = [create(:room, venue: subject.venue)] subject.program.difficulty_levels = [] @@ -1133,7 +1131,7 @@ describe Conference do subject.registration_period = create(:registration_period, start_date: Date.today, end_date: Date.today + 14, conference: subject) - subject.program.cfp = create(:cfp) + create(:cfp, program: subject.program) subject.venue = create(:venue, conference: subject) subject.venue.rooms = [create(:room, venue: subject.venue)] subject.splashpage = create(:splashpage, public: true) @@ -1176,34 +1174,34 @@ describe Conference do describe '#cfp_weeks' do it 'calculates new year' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2013, 12, 30) cfp.end_date = Date.new(2013, 12, 30) + 6 - subject.program.cfp = cfp + cfp.save! expect(subject.cfp_weeks).to eq(1) end it 'is one if start and end are 6 days apart' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 6 - subject.program.cfp = cfp + cfp.save! expect(subject.cfp_weeks).to eq(1) end it 'is one if start and end are the same date' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) - subject.program.cfp = cfp + cfp.save! expect(subject.cfp_weeks).to eq(1) end it 'is two if start and end are 10 days apart' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 10 - subject.program.cfp = cfp + cfp.save! expect(subject.cfp_weeks).to eq(2) end end @@ -1211,36 +1209,36 @@ describe Conference do describe '#get_submissions_per_week' do it 'does calculate correct if cfp start date is altered' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 21 - subject.program.cfp = cfp + cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) - 7)] expect(subject.get_submissions_per_week).to eq([1, 1, 1, 1, 1]) end it 'does calculate correct if cfp end date is altered' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 21 - subject.program.cfp = cfp + cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 28)] expect(subject.get_submissions_per_week).to eq([0, 0, 0, 0, 1]) end it 'pads with zeros if there are no submissions' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 21 - subject.program.cfp = cfp + cfp.save! expect(subject.get_submissions_per_week).to eq([0, 0, 0, 0]) end it 'summarized correct if there are no submissions in one week' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 28 - subject.program.cfp = cfp + cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 7)] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 14)] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 28)] @@ -1248,20 +1246,20 @@ describe Conference do end it 'summarized correct if there are submissions every week except the first' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 21 - subject.program.cfp = cfp + cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 7)] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 14)] expect(subject.get_submissions_per_week).to eq([0, 1, 2, 2]) end it 'summarized correct if there are submissions every week' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 21 - subject.program.cfp = cfp + cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26))] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 7)] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 14)] @@ -1269,29 +1267,29 @@ describe Conference do end it 'pads left' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 21 - subject.program.cfp = cfp + cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 21)] expect(subject.get_submissions_per_week).to eq([0, 0, 0, 1]) end it 'pads middle' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 21 - subject.program.cfp = cfp + cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26))] subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26) + 21)] expect(subject.get_submissions_per_week).to eq([1, 1, 1, 2]) end it 'pads right' do - cfp = create(:cfp) + cfp = create(:cfp, program: subject.program) cfp.start_date = Date.new(2014, 05, 26) cfp.end_date = Date.new(2014, 05, 26) + 21 - subject.program.cfp = cfp + cfp.save! subject.program.events += [create(:event, created_at: Date.new(2014, 05, 26))] expect(subject.get_submissions_per_week).to eq([1, 1, 1, 1]) end @@ -1460,7 +1458,7 @@ describe Conference do context 'open cfp' do before do - subject.program.cfp = create(:cfp) + create(:cfp, program: subject.program) end it '#registration_open? is true' do diff --git a/spec/models/email_settings_spec.rb b/spec/models/email_settings_spec.rb index 949f5762..c4ab7830 100644 --- a/spec/models/email_settings_spec.rb +++ b/spec/models/email_settings_spec.rb @@ -46,9 +46,10 @@ describe EmailSettings do context 'conference has cfp' do before do - conference.program.update_attributes(cfp: create(:cfp, - start_date: Date.new(2014, 04, 29), - end_date: Date.new(2014, 05, 06))) + create(:cfp, + start_date: Date.new(2014, 04, 29), + end_date: Date.new(2014, 05, 06), + program: conference.program) cfp_dates_hash = { 'cfp_start_date' => Date.new(2014, 04, 29), 'cfp_end_date' => Date.new(2014, 05, 06) } expected_hash.merge!(cfp_dates_hash) end diff --git a/spec/models/program_spec.rb b/spec/models/program_spec.rb index 6ea62cf0..208ca386 100644 --- a/spec/models/program_spec.rb +++ b/spec/models/program_spec.rb @@ -7,7 +7,7 @@ describe Program do describe 'association' do it { is_expected.to belong_to :conference } - it { is_expected.to have_one(:cfp).dependent(:destroy) } + it { is_expected.to have_many(:cfps).dependent(:destroy) } it { is_expected.to have_many(:schedules).dependent(:destroy) } it { is_expected.to have_many(:event_types).dependent(:destroy) } it { is_expected.to have_many(:tracks).dependent(:destroy) } diff --git a/spec/models/registration_spec.rb b/spec/models/registration_spec.rb index 772ccda1..25ec9888 100644 --- a/spec/models/registration_spec.rb +++ b/spec/models/registration_spec.rb @@ -29,7 +29,6 @@ describe 'Registration' do describe 'association' do it { is_expected.to belong_to(:user) } it { is_expected.to belong_to(:conference) } - it { is_expected.to have_and_belong_to_many(:events) } it { is_expected.to have_and_belong_to_many(:qanswers) } it { is_expected.to have_and_belong_to_many(:vchoices) } it { is_expected.to have_many(:events_registrations) } From 5f3b48c9f7083891ce365ea02e372bdc2097b902 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Thu, 15 Jun 2017 11:34:58 +0300 Subject: [PATCH 046/237] Update shoulda-matchers to 2.8 --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9dbc51e9..74e8ce84 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -471,7 +471,7 @@ GEM sprockets (~> 2.8, < 2.12) sprockets-rails (~> 2.0) selectize-rails (0.12.4) - shoulda-matchers (2.6.1) + shoulda-matchers (2.8.0) activesupport (>= 3.0.0) simplecov (0.11.2) docile (~> 1.1.0) @@ -653,4 +653,4 @@ DEPENDENCIES whenever BUNDLED WITH - 1.14.5 + 1.15.1 From f37d3095e1bc3a991f66c1cf2edcddb13f01b8cc Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Mon, 19 Jun 2017 17:35:46 +0300 Subject: [PATCH 047/237] Rework cfp abilities --- .rubocop.yml | 1 + app/models/ability.rb | 7 ++++++- app/views/admin/cfps/index.html.haml | 2 +- spec/features/ability_spec.rb | 14 ++++++++++++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index cff7046b..22e17db0 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -29,3 +29,4 @@ Metrics/ClassLength: Metrics/BlockLength: Exclude: - 'spec/models/conference_spec.rb' + - 'spec/features/ability_spec.rb' diff --git a/app/models/ability.rb b/app/models/ability.rb index bdf554cc..6fa8c12f 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -139,6 +139,11 @@ class Ability cannot :destroy, Venue do |venue| venue.conference.program.events.where.not(room_id: nil).any? end + + # Can't create cfp if there are no available cfp types + cannot [:new, :create], Cfp do |cfp| + cfp.program.remaining_cfp_types.empty? + end end def signed_in_with_organizer_role(user) @@ -166,7 +171,7 @@ class Ability can :manage, Program, conference_id: conf_ids_for_organizer can :manage, Schedule, program: { conference_id: conf_ids_for_organizer } can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids_for_organizer } } - can :manage, Cfp, program: { conference_id: conf_ids_for_organizer} + can :manage, Cfp, program: { conference_id: conf_ids_for_organizer } can :manage, Event, program: { conference_id: conf_ids_for_organizer} can :manage, EventType, program: { conference_id: conf_ids_for_organizer} can :manage, Track, program: { conference_id: conf_ids_for_organizer} diff --git a/app/views/admin/cfps/index.html.haml b/app/views/admin/cfps/index.html.haml index 16ab8e84..0067229c 100644 --- a/app/views/admin/cfps/index.html.haml +++ b/app/views/admin/cfps/index.html.haml @@ -30,7 +30,7 @@ .btn-group = link_to 'Edit', edit_admin_conference_program_cfp_path(@conference.short_title, cfp.id), method: :get, class: 'btn btn-primary' = link_to 'Delete', admin_conference_program_cfp_path(@conference.short_title, cfp.id), method: 'delete', class: 'btn btn-danger', data: { confirm: 'Are you sure you want to delete the CfP?' } -- if @program.remaining_cfp_types.length > 0 +- if can? :new, @program.cfps.new .row .col-md-12.text-right = link_to 'Create Call for Papers', new_admin_conference_program_cfp_path(@conference.short_title), class: 'btn btn-primary' diff --git a/spec/features/ability_spec.rb b/spec/features/ability_spec.rb index 162123f4..fe3a3c36 100644 --- a/spec/features/ability_spec.rb +++ b/spec/features/ability_spec.rb @@ -110,7 +110,12 @@ feature 'Has correct abilities' do expect(current_path).to eq(edit_admin_conference_program_path(conference1.short_title)) visit new_admin_conference_program_cfp_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_program_cfp_path(conference1.short_title)) + expect(current_path).to eq root_path + + conference1.program.cfp.destroy! + visit new_admin_conference_program_cfp_path(conference1.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference1.short_title) + create(:cfp, program: conference1.program) visit edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp) expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp)) @@ -322,7 +327,12 @@ feature 'Has correct abilities' do expect(current_path).to eq(edit_admin_conference_program_path(conference2.short_title)) visit new_admin_conference_program_cfp_path(conference2.short_title) - expect(current_path).to eq(new_admin_conference_program_cfp_path(conference2.short_title)) + expect(current_path).to eq root_path + + conference2.program.cfp.destroy! + visit new_admin_conference_program_cfp_path(conference2.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference2.short_title) + create(:cfp, program: conference2.program) visit edit_admin_conference_program_cfp_path(conference2.short_title, conference2.program.cfp) expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference2.short_title, conference2.program.cfp)) From b72e64b2385767f2b1634322ac2cf97c9a3a3638 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 13 Jun 2017 04:39:47 +0530 Subject: [PATCH 048/237] Introduce organization admins --- app/controllers/admin/base_controller.rb | 2 +- .../admin/organizations_controller.rb | 5 + app/models/ability.rb | 95 +++++++++++-------- app/models/organization.rb | 10 ++ lib/tasks/roles.rake | 4 + spec/models/ability_spec.rb | 21 +++- 6 files changed, 96 insertions(+), 41 deletions(-) diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 638d2ab6..5c71ffdc 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -8,7 +8,7 @@ module Admin return false end unless (current_user.has_role? :organizer, :any) || (current_user.has_role? :cfp, :any) || - (current_user.has_role? :info_desk, :any) || + (current_user.has_role? :info_desk, :any) || (current_user.has_role? :organization_admin, :any) || (current_user.has_role? :volunteers_coordinator, :any) || current_user.is_admin raise CanCan::AccessDenied.new('You are not authorized to access this area!') end diff --git a/app/controllers/admin/organizations_controller.rb b/app/controllers/admin/organizations_controller.rb index 087bf7f8..9d0dc78b 100644 --- a/app/controllers/admin/organizations_controller.rb +++ b/app/controllers/admin/organizations_controller.rb @@ -1,6 +1,7 @@ module Admin class OrganizationsController < Admin::BaseController load_and_authorize_resource :organization + after_action :assign_role, only: :create def index @organizations = Organization.all @@ -45,6 +46,10 @@ module Admin private + def assign_role + current_user.add_role :organization_admin, @organization + end + def organization_params params.require(:organization).permit(:name, :description, :picture) end diff --git a/app/models/ability.rb b/app/models/ability.rb index 6fa8c12f..7d1cf868 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -110,6 +110,7 @@ class Ability # Abilities from not_signed_in and signed_in are also inherited signed_in(user) + signed_in_with_organization_admin_role(user) if user.has_role? :organization_admin, :any signed_in_with_organizer_role(user) if user.has_role? :organizer, :any signed_in_with_cfp_role(user) if user.has_role? :cfp, :any signed_in_with_info_desk_role(user) if user.has_role? :info_desk, :any @@ -146,57 +147,73 @@ class Ability end end - def signed_in_with_organizer_role(user) - # ids of all the conferences for which the user has the 'organizer' role - conf_ids_for_organizer = Conference.with_role(:organizer, user).pluck(:id) + def signed_in_with_organization_admin_role(user) + org_ids_for_organization_admin = Organization.with_role(:organization_admin, user).pluck(:id) - can :manage, Resource, conference_id: conf_ids_for_organizer - can [:new, :create], Conference if user.has_role?(:organizer, :any) - can :manage, Conference, id: conf_ids_for_organizer - can :manage, Splashpage, conference_id: conf_ids_for_organizer - can :manage, Contact, conference_id: conf_ids_for_organizer - can :manage, EmailSettings, conference_id: conf_ids_for_organizer - can :manage, Campaign, conference_id: conf_ids_for_organizer - can :manage, Target, conference_id: conf_ids_for_organizer - can :manage, Commercial, commercialable_type: 'Conference', - commercialable_id: conf_ids_for_organizer - can :manage, Registration, conference_id: conf_ids_for_organizer - can :manage, RegistrationPeriod, conference_id: conf_ids_for_organizer - can :manage, Question, conference_id: conf_ids_for_organizer - can :manage, Question do |question| - !(question.conferences.pluck(:id) & conf_ids_for_organizer).empty? + can :manage, Organization, id: org_ids_for_organization_admin + can :manage, Conference, organization_id: org_ids_for_organization_admin + conf_ids_for_organization_admin = [] + org_ids_for_organization_admin.each do |org_id| + conf_ids_for_organization_admin += Organization.find(org_id).conferences.pluck(:id) end - can :manage, Vposition, conference_id: conf_ids_for_organizer - can :manage, Vday, conference_id: conf_ids_for_organizer - can :manage, Program, conference_id: conf_ids_for_organizer - can :manage, Schedule, program: { conference_id: conf_ids_for_organizer } - can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids_for_organizer } } - can :manage, Cfp, program: { conference_id: conf_ids_for_organizer } - can :manage, Event, program: { conference_id: conf_ids_for_organizer} - can :manage, EventType, program: { conference_id: conf_ids_for_organizer} - can :manage, Track, program: { conference_id: conf_ids_for_organizer} - can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_organizer} + can [:index, :show], Role + can [:edit, :update], Role do |role| + role.resource_type == 'Organization' && (org_ids_for_organization_admin.include? role.resource_id) + end + signed_in_with_organizer_role(user, conf_ids_for_organization_admin) + end + + 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' + conf_ids_for_organization_admin_and_organizer = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq + can :manage, Resource, conference_id: conf_ids_for_organization_admin_and_organizer + can [:new, :create], Conference if user.has_role?(:organizer, :any) + can :manage, Conference, id: conf_ids_for_organization_admin_and_organizer + can :manage, Splashpage, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Contact, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, EmailSettings, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Campaign, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Target, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Commercial, commercialable_type: 'Conference', + commercialable_id: conf_ids_for_organization_admin_and_organizer + can :manage, Registration, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, RegistrationPeriod, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Question, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Question do |question| + !(question.conferences.pluck(:id) & conf_ids_for_organization_admin_and_organizer).empty? + end + can :manage, Vposition, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Vday, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Program, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Schedule, program: { conference_id: conf_ids_for_organization_admin_and_organizer } + can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids_for_organization_admin_and_organizer } } + can :manage, Cfp, program: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, Event, program: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, EventType, program: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, Track, program: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_organization_admin_and_organizer} can :manage, Commercial, commercialable_type: 'Event', - commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id) - can :manage, Venue, conference_id: conf_ids_for_organizer + commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organization_admin_and_organizer).pluck(:id)).pluck(:id) + can :manage, Venue, conference_id: conf_ids_for_organization_admin_and_organizer can :manage, Commercial, commercialable_type: 'Venue', - commercialable_id: Venue.where(conference_id: conf_ids_for_organizer).pluck(:id) - can :manage, Lodging, conference_id: conf_ids_for_organizer - can :manage, Room, venue: { conference_id: conf_ids_for_organizer} - can :manage, Sponsor, conference_id: conf_ids_for_organizer - can :manage, SponsorshipLevel, conference_id: conf_ids_for_organizer - can :manage, Ticket, conference_id: conf_ids_for_organizer + commercialable_id: Venue.where(conference_id: conf_ids_for_organization_admin_and_organizer).pluck(:id) + can :manage, Lodging, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Room, venue: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, Sponsor, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, SponsorshipLevel, conference_id: conf_ids_for_organization_admin_and_organizer + can :manage, Ticket, conference_id: conf_ids_for_organization_admin_and_organizer can :index, Comment, commentable_type: 'Event', - commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id) + commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organization_admin_and_organizer).pluck(:id)).pluck(:id) # Abilities for Role (Conference resource) can [:index, :show], Role can [:edit, :update, :toggle_user], Role do |role| - role.resource_type == 'Conference' && (conf_ids_for_organizer.include? role.resource_id) + role.resource_type == 'Conference' && (conf_ids_for_organization_admin_and_organizer.include? role.resource_id) end can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| - version.item_type == 'User' || (conf_ids_for_organizer.include? version.conference_id) + version.item_type == 'User' || (conf_ids_for_organization_admin_and_organizer.include? version.conference_id) end end diff --git a/app/models/organization.rb b/app/models/organization.rb index 60a83fef..0fdbe5f9 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -1,7 +1,17 @@ class Organization < ActiveRecord::Base + resourcify :roles, dependent: :delete_all + has_many :conferences, dependent: :destroy + after_create :create_roles + validates :name, presence: true mount_uploader :picture, PictureUploader, mount_on: :picture + + private + + def create_roles + Role.where(name: 'organization_admin', resource: self).first_or_create(description: "For the administrators of an organization (who shall have full access to the organization and it's conferences)") + end end diff --git a/lib/tasks/roles.rake b/lib/tasks/roles.rake index 8c817db0..227f9642 100644 --- a/lib/tasks/roles.rake +++ b/lib/tasks/roles.rake @@ -2,6 +2,10 @@ namespace :roles do desc 'Adds back deleted roles to all conferences' task add: :environment do + Organization.all.each do |org| + Role.where(name: 'organization_admin', resource: org).first_or_create(description: "For the administrators of an organization (who shall have full access to the organization and it's conferences)") + end + Conference.all.each do |c| Role.where(name: 'organizer', resource: c).first_or_create(description: 'For the organizers of the conference (who shall have full access)') Role.where(name: 'cfp', resource: c).first_or_create(description: 'For the members of the CfP team') diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 001c7365..980cc194 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -9,7 +9,8 @@ describe 'User' do subject(:ability){ Ability.new(user) } let(:user){ nil } - let!(:my_conference) { create(:full_conference) } + let!(:organization) { create(:organization) } + let!(:my_conference) { create(:full_conference, organization: organization) } let(:my_venue) { my_conference.venue || create(:venue, conference: my_conference) } let(:my_registration) { create(:registration, conference: my_conference, user: admin) } @@ -44,6 +45,7 @@ describe 'User' do let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) } # Test abilities for not signed in users context 'when user is not signed in' do + it{ should be_able_to(:index, Organization)} it{ should be_able_to(:index, Conference)} it{ should be_able_to(:show, conference_public)} @@ -138,9 +140,14 @@ describe 'User' do shared_examples 'user with any role' do before do + @other_organization = create(:organization) @other_conference = create(:conference) end + it{ should_not be_able_to(:update, Role.find_by(name: 'organization_admin', resource: @other_organization)) } + it{ should_not be_able_to(:edit, Role.find_by(name: 'organization_admin', resource: @other_organization)) } + it{ should_not be_able_to(:show, Role.find_by(name: 'organization_admin', resource: @other_organization)) } + %w(organizer cfp info_desk volunteers_coordinator).each do |role| it{ should_not be_able_to(:toggle_user, Role.find_by(name: role, resource: @other_conference)) } it{ should_not be_able_to(:update, Role.find_by(name: role, resource: @other_conference)) } @@ -164,6 +171,18 @@ describe 'User' do end end + context 'when user has the role organization_admin' do + let(:role) { Role.find_by(name: 'organization_admin', resource: organization) } + let(:user) { create(:user, role_ids: [role.id]) } + let(:other_conference) { create(:conference) } + + it{ should_not be_able_to(:manage, other_conference) } + it{ should be_able_to(:manage, my_conference) } + it{ should be_able_to(:manage, organization) } + + it_behaves_like 'user with any role' + end + context 'when user has the role organizer' do let(:role) { Role.find_by(name: 'organizer', resource: my_conference) } let(:user) { create(:user, role_ids: [role.id]) } From aa3df0243eff061502050fa0d346f47fc9569789 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 13 Jun 2017 20:57:55 +0530 Subject: [PATCH 049/237] mending permissions and test --- app/models/ability.rb | 22 ++++++++++++++-------- spec/models/ability_spec.rb | 10 +++++----- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 7d1cf868..00a0b291 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -29,6 +29,7 @@ class Ability # Abilities for not signed in users (guests) def not_signed_in + can [:index], Organization can [:index], Conference can [:show], Conference do |conference| conference.splashpage && conference.splashpage.public == true @@ -168,7 +169,6 @@ class Ability # conferences that belong to organizations for which user is 'organization_admin' conf_ids_for_organization_admin_and_organizer = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq can :manage, Resource, conference_id: conf_ids_for_organization_admin_and_organizer - can [:new, :create], Conference if user.has_role?(:organizer, :any) can :manage, Conference, id: conf_ids_for_organization_admin_and_organizer can :manage, Splashpage, conference_id: conf_ids_for_organization_admin_and_organizer can :manage, Contact, conference_id: conf_ids_for_organization_admin_and_organizer @@ -207,7 +207,10 @@ class Ability commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organization_admin_and_organizer).pluck(:id)).pluck(:id) # Abilities for Role (Conference resource) - can [:index, :show], Role + can [:index, :show], Role do |role| + role.resource_type == 'Conference' + end + can [:edit, :update, :toggle_user], Role do |role| role.resource_type == 'Conference' && (conf_ids_for_organization_admin_and_organizer.include? role.resource_id) end @@ -239,8 +242,9 @@ class Ability commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id) # Abilities for Role (Conference resource) - can [:index, :show], Role - + can [:index, :show], Role do |role| + role.resource_type == 'Conference' + end # Can add or remove users from role, when user has that same role for the conference # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') can :toggle_user, Role do |role| @@ -268,8 +272,9 @@ class Ability end # Abilities for Role (Conference resource) - can [:index, :show], Role - + can [:index, :show], Role do |role| + role.resource_type == 'Conference' + end # Can add or remove users from role, when user has that same role for the conference # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') can :toggle_user, Role do |role| @@ -287,8 +292,9 @@ class Ability can :manage, Vday, conference_id: conf_ids_for_volunteers_coordinator # Abilities for Role (Conference resource) - can [:index, :show], Role - + can [:index, :show], Role do |role| + role.resource_type == 'Conference' + end # Can add or remove users from role, when user has that same role for the conference # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') can :toggle_user, Role do |role| diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 980cc194..fcf9b384 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -141,7 +141,7 @@ describe 'User' do shared_examples 'user with any role' do before do @other_organization = create(:organization) - @other_conference = create(:conference) + @other_conference = create(:conference, organization: @other_organization) end it{ should_not be_able_to(:update, Role.find_by(name: 'organization_admin', resource: @other_organization)) } @@ -179,8 +179,6 @@ describe 'User' do it{ should_not be_able_to(:manage, other_conference) } it{ should be_able_to(:manage, my_conference) } it{ should be_able_to(:manage, organization) } - - it_behaves_like 'user with any role' end context 'when user has the role organizer' do @@ -199,8 +197,10 @@ describe 'User' do should be_able_to(:destroy, my_venue) end - it{ should be_able_to(:new, Conference) } - it{ should be_able_to(:create, Conference) } + it{ should_not be_able_to(:new, Organization)} + it{ should_not be_able_to(:create, Organization)} + it{ should_not be_able_to(:new, Conference.new) } + it{ should_not be_able_to(:create, Conference.new) } it{ should be_able_to(:manage, my_conference) } it{ should_not be_able_to(:manage, conference_public) } it{ should be_able_to(:manage, my_conference.splashpage) } From ad3d6f2f95bc5d6af98a3056747b63c3ed14bc37 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 14 Jun 2017 20:42:50 +0530 Subject: [PATCH 050/237] modify admin/conference_controller_spec and not authorized error messages --- app/controllers/admin/base_controller.rb | 2 +- .../admin/conferences_controller.rb | 5 +- app/models/ability.rb | 1 + app/views/admin/conferences/new.html.haml | 1 + .../admin/comments_controller_spec.rb | 2 +- .../admin/conferences_controller_spec.rb | 210 +++++++++--------- spec/features/ability_spec.rb | 2 +- spec/features/base_controller_spec.rb | 2 +- 8 files changed, 120 insertions(+), 105 deletions(-) diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 5c71ffdc..85dba43d 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -10,7 +10,7 @@ module Admin unless (current_user.has_role? :organizer, :any) || (current_user.has_role? :cfp, :any) || (current_user.has_role? :info_desk, :any) || (current_user.has_role? :organization_admin, :any) || (current_user.has_role? :volunteers_coordinator, :any) || current_user.is_admin - raise CanCan::AccessDenied.new('You are not authorized to access this area!') + raise CanCan::AccessDenied.new('You are not authorized to access this page.') end end end diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index f8c9ea19..bf1dfdb5 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -72,11 +72,14 @@ module Admin def new @conference = Conference.new + @organizations = {} + Organization.all.each do |organization| + @organizations.store(organization.name, organization.id) if can? :create, Conference.new(organization: organization) + end end def create @conference = Conference.new(conference_params) - @conference.organization = Organization.find_or_create_by(name: 'organization') if @conference.save # user that creates the conference becomes organizer of that conference current_user.add_role :organizer, @conference diff --git a/app/models/ability.rb b/app/models/ability.rb index 00a0b291..6e560a63 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -152,6 +152,7 @@ class Ability org_ids_for_organization_admin = Organization.with_role(:organization_admin, user).pluck(:id) can :manage, Organization, id: org_ids_for_organization_admin + can [:new], Conference can :manage, Conference, organization_id: org_ids_for_organization_admin conf_ids_for_organization_admin = [] org_ids_for_organization_admin.each do |org_id| diff --git a/app/views/admin/conferences/new.html.haml b/app/views/admin/conferences/new.html.haml index 014758de..0d2eb4b3 100644 --- a/app/views/admin/conferences/new.html.haml +++ b/app/views/admin/conferences/new.html.haml @@ -6,6 +6,7 @@ input_html: { required: 'required' } = f.input :short_title, hint: "A short and unique handle for your conference, using only letters, numbers, underscores, and dashes. This will be used to identify your conference in URLs etc. Example: 'froscon2011'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' }, prepend: conferences_url + '/' + = f.input :organization, as: :select, collection: @organizations = f.inputs 'Scheduling' do = f.input :timezone, as: :time_zone, default: Time.zone.name, hint: 'Please select in what time zone your conference will take place.' = f.input :start_date, as: :string, input_html: { id: 'conference-start-datepicker', required: 'required' } diff --git a/spec/controllers/admin/comments_controller_spec.rb b/spec/controllers/admin/comments_controller_spec.rb index 5429dabd..23b6b88a 100644 --- a/spec/controllers/admin/comments_controller_spec.rb +++ b/spec/controllers/admin/comments_controller_spec.rb @@ -51,7 +51,7 @@ describe Admin::CommentsController, type: :controller do comment get :index expect(response).to redirect_to(root_path) - expect(flash[:alert]).to match('You are not authorized to access this area!') + expect(flash[:alert]).to match('You are not authorized to access this page.') end end end diff --git a/spec/controllers/admin/conferences_controller_spec.rb b/spec/controllers/admin/conferences_controller_spec.rb index 74acbb3f..d6133c65 100644 --- a/spec/controllers/admin/conferences_controller_spec.rb +++ b/spec/controllers/admin/conferences_controller_spec.rb @@ -3,19 +3,18 @@ require 'spec_helper' describe Admin::ConferencesController do # It is necessary to use bang version of let to build roles before user - let(:conference) { create(:conference, end_date: Date.new(2014, 05, 26) + 15) } + let(:organization) { create(:organization) } + let(:conference) { create(:conference, organization: organization, end_date: Date.new(2014, 05, 26) + 15) } let!(:organizer_role) { Role.find_by(name: 'organizer', resource: conference) } - + let!(:organization_admin_role) { Role.find_by(name: 'organization_admin', resource: organization) } + let(:organization_admin) { create(:user, role_ids: organization_admin_role.id) } let(:organizer) { create(:user, role_ids: organizer_role.id) } let(:organizer2) { create(:user, email: 'organizer2@email.osem', role_ids: organizer_role.id) } let(:participant) { create(:user) } - shared_examples 'access as organizer' do - + shared_examples 'access as organizer or organization_admin' do describe 'PATCH #update' do - context 'valid attributes' do - it 'locates the requested conference' do patch :update, id: conference.short_title, conference: attributes_for(:conference, title: 'Example Con') expect(assigns(:conference)).to eq(conference) @@ -25,7 +24,6 @@ describe Admin::ConferencesController do patch :update, id: conference.short_title, conference: attributes_for(:conference, title: 'Example Con', short_title: 'ExCon') - conference.reload expect(conference.title).to eq('Example Con') expect(conference.short_title).to eq('ExCon') @@ -75,72 +73,6 @@ describe Admin::ConferencesController do end end - describe 'POST #create' do - context 'with valid attributes' do - it 'saves the conference to the database' do - expected = expect do - post :create, conference: - attributes_for(:conference, short_title: 'dps15') - end - expected.to change { Conference.count }.by 1 - end - - it 'redirects to conference#show' do - post :create, conference: - attributes_for(:conference, short_title: 'dps15') - - expect(response).to redirect_to admin_conference_path( - assigns[:conference].short_title) - end - - it 'creates roles for the conference' do - cfp_role = Role.find_by(name: 'cfp', resource: conference) - info_desk_role = Role.find_by(name: 'info_desk', resource: conference) - volunteers_coordinator_role = Role.find_by(name: 'volunteers_coordinator', resource: conference) - - post :create, conference: - attributes_for(:conference, short_title: 'dps15') - - expect(conference.roles.count).to eq 4 - - expect(conference.roles).to eq [organizer_role, cfp_role, info_desk_role, volunteers_coordinator_role] - end - end - - context 'with invalid attributes' do - it 'does not save the conference to the database' do - expected = expect do - post :create, conference: - attributes_for(:conference, short_title: nil) - end - expected.to_not change { Conference.count } - end - - it 're-renders the new template' do - post :create, conference: - attributes_for(:conference, short_title: nil) - expect(response).to be_success - end - end - - context 'with duplicate conference short title' do - it 'does not save the conference to the database' do - conference - expected = expect do - post :create, conference: - attributes_for(:conference, short_title: conference.short_title) - end - expected.to_not change { Conference.count } - end - - it 're-renders the new template' do - conference - post :create, conference: attributes_for(:conference, short_title: conference.short_title) - expect(response).to be_success - end - end - end - describe 'GET #edit' do it 'assigns the requested conference to conference' do get :edit, id: conference.short_title @@ -203,6 +135,74 @@ describe Admin::ConferencesController do end end end + end + + shared_examples 'access as organization_admin' do + describe 'POST #create' do + context 'with valid attributes' do + it 'saves the conference to the database' do + expected = expect do + post :create, conference: + attributes_for(:conference, short_title: 'dps15', organization: organization) + end + expected.to change { Conference.count }.by 1 + end + + it 'redirects to conference#show' do + post :create, conference: + attributes_for(:conference, short_title: 'dps15', organization: organization) + + expect(response).to redirect_to admin_conference_path( + assigns[:conference].short_title) + end + + it 'creates roles for the conference' do + cfp_role = Role.find_by(name: 'cfp', resource: conference) + info_desk_role = Role.find_by(name: 'info_desk', resource: conference) + volunteers_coordinator_role = Role.find_by(name: 'volunteers_coordinator', resource: conference) + + post :create, conference: + attributes_for(:conference, short_title: 'dps15') + + expect(conference.roles.count).to eq 4 + + expect(conference.roles).to eq [organizer_role, cfp_role, info_desk_role, volunteers_coordinator_role] + end + end + + context 'with invalid attributes' do + it 'does not save the conference to the database' do + expected = expect do + post :create, conference: + attributes_for(:conference, short_title: nil, organization: organization) + end + expected.to_not change { Conference.count } + end + + it 're-renders the new template' do + post :create, conference: + attributes_for(:conference, short_title: nil, organization: organization) + expect(response).to be_success + end + end + + context 'with duplicate conference short title' do + it 'does not save the conference to the database' do + conference + expected = expect do + post :create, conference: + attributes_for(:conference, short_title: conference.short_title, organization: organization) + end + expected.to_not change { Conference.count } + end + + it 're-renders the new template' do + conference + post :create, conference: attributes_for(:conference, short_title: conference.short_title, organization: organization) + expect(response).to be_success + end + end + end describe 'GET #new' do it 'assigns a new conference to conference' do @@ -217,14 +217,45 @@ describe Admin::ConferencesController do end end - describe 'organizer access' do + describe 'organization admin access' do + before do + sign_in(organization_admin) + end + it_behaves_like 'access as organizer or organization_admin' + it_behaves_like 'access as organization_admin' + end + + shared_examples 'access as organizer, participant or guest' do |path, message| + describe 'GET #new' do + it 'requires organizer privileges' do + get :new + expect(response).to redirect_to(send(path)) + if message + expect(flash[:alert]).to match(/#{message}/) + end + end + end + + describe 'POST #create' do + it 'requires organizer privileges' do + post :create, conference: attributes_for(:conference, + short_title: 'ExCon') + expect(response).to redirect_to(send(path)) + if message + expect(flash[:alert]).to match(/#{message}/) + end + end + end + end + + describe 'organizer access' do before do sign_in(organizer) end - it_behaves_like 'access as organizer' - + it_behaves_like 'access as organizer or organization_admin' + it_behaves_like 'access as organizer, participant or guest', :root_path, 'You are not authorized to access this page.' end shared_examples 'access as participant or guest' do |path, message| @@ -248,27 +279,6 @@ describe Admin::ConferencesController do end end - describe 'GET #new' do - it 'requires organizer privileges' do - get :new - expect(response).to redirect_to(send(path)) - if message - expect(flash[:alert]).to match(/#{message}/) - end - end - end - - describe 'POST #create' do - it 'requires organizer privileges' do - post :create, conference: attributes_for(:conference, - short_title: 'ExCon') - expect(response).to redirect_to(send(path)) - if message - expect(flash[:alert]).to match(/#{message}/) - end - end - end - describe 'PATCH #update' do it 'requires organizer privileges' do patch :update, id: conference.short_title, @@ -287,13 +297,13 @@ describe Admin::ConferencesController do sign_in(participant) end - it_behaves_like 'access as participant or guest', :root_path, 'You are not authorized to access this area!' - + it_behaves_like 'access as participant or guest', :root_path, 'You are not authorized to access this page.' + it_behaves_like 'access as organizer, participant or guest', :root_path, 'You are not authorized to access this page.' end describe 'guest access' do it_behaves_like 'access as participant or guest', :new_user_session_path - + it_behaves_like 'access as organizer, participant or guest', :new_user_session_path end end diff --git a/spec/features/ability_spec.rb b/spec/features/ability_spec.rb index fe3a3c36..8ddcb001 100644 --- a/spec/features/ability_spec.rb +++ b/spec/features/ability_spec.rb @@ -22,7 +22,7 @@ feature 'Has correct abilities' do visit admin_conference_path(conference1.short_title) expect(current_path).to eq root_path - expect(flash).to eq 'You are not authorized to access this area!' + expect(flash).to eq 'You are not authorized to access this page.' end scenario 'when user is organizer' do diff --git a/spec/features/base_controller_spec.rb b/spec/features/base_controller_spec.rb index be52c3a9..1f75f81b 100644 --- a/spec/features/base_controller_spec.rb +++ b/spec/features/base_controller_spec.rb @@ -25,7 +25,7 @@ feature 'BaseController' do it 'not an admin it redirects to root_path' do visit admin_conferences_path expect(current_path).to eq root_path - expect(flash).to eq 'You are not authorized to access this area!' + expect(flash).to eq 'You are not authorized to access this page.' end it 'an admin he can access the admin area' do From 8839a928ed83a0fca8b90f9c5a6871f9c7bc946e Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 14 Jun 2017 21:59:58 +0530 Subject: [PATCH 051/237] mending failing tests --- .../admin/conferences_controller.rb | 5 +---- app/models/ability.rb | 2 +- app/views/admin/conferences/new.html.haml | 1 - .../admin/conferences_controller_spec.rb | 18 +++++++++--------- .../admin/organizations_controller_spec.rb | 10 +++++----- 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index bf1dfdb5..f8c9ea19 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -72,14 +72,11 @@ module Admin def new @conference = Conference.new - @organizations = {} - Organization.all.each do |organization| - @organizations.store(organization.name, organization.id) if can? :create, Conference.new(organization: organization) - end end def create @conference = Conference.new(conference_params) + @conference.organization = Organization.find_or_create_by(name: 'organization') if @conference.save # user that creates the conference becomes organizer of that conference current_user.add_role :organizer, @conference diff --git a/app/models/ability.rb b/app/models/ability.rb index 6e560a63..37090a49 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -152,7 +152,7 @@ class Ability org_ids_for_organization_admin = Organization.with_role(:organization_admin, user).pluck(:id) can :manage, Organization, id: org_ids_for_organization_admin - can [:new], Conference + can :new, Conference can :manage, Conference, organization_id: org_ids_for_organization_admin conf_ids_for_organization_admin = [] org_ids_for_organization_admin.each do |org_id| diff --git a/app/views/admin/conferences/new.html.haml b/app/views/admin/conferences/new.html.haml index 0d2eb4b3..014758de 100644 --- a/app/views/admin/conferences/new.html.haml +++ b/app/views/admin/conferences/new.html.haml @@ -6,7 +6,6 @@ input_html: { required: 'required' } = f.input :short_title, hint: "A short and unique handle for your conference, using only letters, numbers, underscores, and dashes. This will be used to identify your conference in URLs etc. Example: 'froscon2011'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' }, prepend: conferences_url + '/' - = f.input :organization, as: :select, collection: @organizations = f.inputs 'Scheduling' do = f.input :timezone, as: :time_zone, default: Time.zone.name, hint: 'Please select in what time zone your conference will take place.' = f.input :start_date, as: :string, input_html: { id: 'conference-start-datepicker', required: 'required' } diff --git a/spec/controllers/admin/conferences_controller_spec.rb b/spec/controllers/admin/conferences_controller_spec.rb index d6133c65..009e40ba 100644 --- a/spec/controllers/admin/conferences_controller_spec.rb +++ b/spec/controllers/admin/conferences_controller_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe Admin::ConferencesController do # It is necessary to use bang version of let to build roles before user - let(:organization) { create(:organization) } - let(:conference) { create(:conference, organization: organization, end_date: Date.new(2014, 05, 26) + 15) } + let!(:organization) { create(:organization, name: 'organization') } + let!(:conference) { create(:conference, organization: organization, end_date: Date.new(2014, 05, 26) + 15) } let!(:organizer_role) { Role.find_by(name: 'organizer', resource: conference) } let!(:organization_admin_role) { Role.find_by(name: 'organization_admin', resource: organization) } let(:organization_admin) { create(:user, role_ids: organization_admin_role.id) } @@ -143,14 +143,14 @@ describe Admin::ConferencesController do it 'saves the conference to the database' do expected = expect do post :create, conference: - attributes_for(:conference, short_title: 'dps15', organization: organization) + attributes_for(:conference, short_title: 'dps15', organization_id: organization.id) end expected.to change { Conference.count }.by 1 end it 'redirects to conference#show' do post :create, conference: - attributes_for(:conference, short_title: 'dps15', organization: organization) + attributes_for(:conference, short_title: 'dps15', organization_id: organization.id) expect(response).to redirect_to admin_conference_path( assigns[:conference].short_title) @@ -174,14 +174,14 @@ describe Admin::ConferencesController do it 'does not save the conference to the database' do expected = expect do post :create, conference: - attributes_for(:conference, short_title: nil, organization: organization) + attributes_for(:conference, short_title: nil, organization_id: organization.id) end expected.to_not change { Conference.count } end it 're-renders the new template' do post :create, conference: - attributes_for(:conference, short_title: nil, organization: organization) + attributes_for(:conference, short_title: nil, organization_id: organization.id) expect(response).to be_success end end @@ -191,14 +191,14 @@ describe Admin::ConferencesController do conference expected = expect do post :create, conference: - attributes_for(:conference, short_title: conference.short_title, organization: organization) + attributes_for(:conference, short_title: conference.short_title, organization_id: organization.id) end expected.to_not change { Conference.count } end it 're-renders the new template' do conference - post :create, conference: attributes_for(:conference, short_title: conference.short_title, organization: organization) + post :create, conference: attributes_for(:conference, short_title: conference.short_title, organization_id: organization.id) expect(response).to be_success end end @@ -240,7 +240,7 @@ describe Admin::ConferencesController do describe 'POST #create' do it 'requires organizer privileges' do post :create, conference: attributes_for(:conference, - short_title: 'ExCon') + short_title: 'ExCon', organization_id: organization.id) expect(response).to redirect_to(send(path)) if message expect(flash[:alert]).to match(/#{message}/) diff --git a/spec/controllers/admin/organizations_controller_spec.rb b/spec/controllers/admin/organizations_controller_spec.rb index a4afc994..abe5005b 100644 --- a/spec/controllers/admin/organizations_controller_spec.rb +++ b/spec/controllers/admin/organizations_controller_spec.rb @@ -16,7 +16,7 @@ describe Admin::OrganizationsController do end it 'redirects to root' do - expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(flash[:alert]).to eq('You are not authorized to access this page.') expect(response).to redirect_to(root_path) end end @@ -27,7 +27,7 @@ describe Admin::OrganizationsController do end it 'redirects to root' do - expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(flash[:alert]).to eq('You are not authorized to access this page.') expect(response).to redirect_to(root_path) end end @@ -43,7 +43,7 @@ describe Admin::OrganizationsController do it 'redirects to root' do post :create, organization: attributes_for(:organization) - expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(flash[:alert]).to eq('You are not authorized to access this page.') expect(response).to redirect_to(root_path) end end @@ -55,7 +55,7 @@ describe Admin::OrganizationsController do organization.reload expect(organization.name).to eq(old_name) - expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(flash[:alert]).to eq('You are not authorized to access this page.') expect(response).to redirect_to(root_path) end end @@ -72,7 +72,7 @@ describe Admin::OrganizationsController do it 'redirects to root' do delete :destroy, id: organization.id - expect(flash[:alert]).to eq('You are not authorized to access this area!') + expect(flash[:alert]).to eq('You are not authorized to access this page.') expect(response).to redirect_to(root_path) end end From 7d408ee33cfdac2b35410ac2c78e8c222de7f131 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 14 Jun 2017 22:51:26 +0530 Subject: [PATCH 052/237] suggested changes change description of organization_admin remove assign_role callback --- app/controllers/admin/organizations_controller.rb | 5 ----- app/models/organization.rb | 2 +- lib/tasks/roles.rake | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/controllers/admin/organizations_controller.rb b/app/controllers/admin/organizations_controller.rb index 9d0dc78b..087bf7f8 100644 --- a/app/controllers/admin/organizations_controller.rb +++ b/app/controllers/admin/organizations_controller.rb @@ -1,7 +1,6 @@ module Admin class OrganizationsController < Admin::BaseController load_and_authorize_resource :organization - after_action :assign_role, only: :create def index @organizations = Organization.all @@ -46,10 +45,6 @@ module Admin private - def assign_role - current_user.add_role :organization_admin, @organization - end - def organization_params params.require(:organization).permit(:name, :description, :picture) end diff --git a/app/models/organization.rb b/app/models/organization.rb index 0fdbe5f9..de3d4f94 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -12,6 +12,6 @@ class Organization < ActiveRecord::Base private def create_roles - Role.where(name: 'organization_admin', resource: self).first_or_create(description: "For the administrators of an organization (who shall have full access to the organization and it's conferences)") + roles.where(name: 'organization_admin').first_or_create(description: 'For the administrators of an organization and its conferences') end end diff --git a/lib/tasks/roles.rake b/lib/tasks/roles.rake index 227f9642..c29d0e24 100644 --- a/lib/tasks/roles.rake +++ b/lib/tasks/roles.rake @@ -3,7 +3,7 @@ namespace :roles do task add: :environment do Organization.all.each do |org| - Role.where(name: 'organization_admin', resource: org).first_or_create(description: "For the administrators of an organization (who shall have full access to the organization and it's conferences)") + Role.where(name: 'organization_admin', resource: org).first_or_create(description: 'For the administrators of an organization and its conferences') end Conference.all.each do |c| From 21b2e5466f3ed49e0ee78da08ca4ddcb822691f3 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Fri, 16 Jun 2017 03:47:34 +0530 Subject: [PATCH 053/237] refactor features/ability_spec and increase test coverage for organization --- spec/features/ability_spec.rb | 1045 ++++++++++++++-------------- spec/features/organization_spec.rb | 51 ++ 2 files changed, 562 insertions(+), 534 deletions(-) create mode 100644 spec/features/organization_spec.rb diff --git a/spec/features/ability_spec.rb b/spec/features/ability_spec.rb index 8ddcb001..41775de4 100644 --- a/spec/features/ability_spec.rb +++ b/spec/features/ability_spec.rb @@ -1,18 +1,22 @@ require 'spec_helper' feature 'Has correct abilities' do - # It is necessary to use bang version of let to build roles before user - let(:conference1) { create(:full_conference) } # user is organizer - let(:conference2) { create(:full_conference) } # user is cfp - let(:conference3) { create(:full_conference) } # user is info_desk - let(:conference6) { create(:conference) } # user is organizer, venue is not set by default + let(:organization) { create(:organization) } + # It is necessary to use bang version of let to build roles before user + let(:conference1) { create(:full_conference, organization: organization) } # user is organizer + let(:conference2) { create(:full_conference, organization: organization) } # user is cfp + let(:conference3) { create(:full_conference, organization: organization) } # user is info_desk + let(:conference6) { create(:conference, organization: organization) } # user is organizer, venue is not set by default + + let(:role_organization_admin) { Role.find_by(name: 'organization_admin', resource: organization) } let(:role_organizer_conf1) { Role.find_by(name: 'organizer', resource: conference1) } let(:role_organizer_conf6) { Role.find_by(name: 'organizer', resource: conference6) } let(:role_cfp) { Role.find_by(name: 'cfp', resource: conference2) } let(:role_info_desk) { Role.find_by(name: 'info_desk', resource: conference3) } let(:user) { create(:user) } + let(:user_organization_admin) { create(:user, role_ids: [role_organization_admin.id]) } let(:user_organizer) { create(:user, role_ids: [role_organizer_conf1.id, role_organizer_conf6.id]) } let(:user_cfp) { create(:user, role_ids: [role_cfp.id]) } let(:user_info_desk) { create(:user, role_ids: [role_info_desk.id]) } @@ -25,653 +29,626 @@ feature 'Has correct abilities' do expect(flash).to eq 'You are not authorized to access this page.' end - scenario 'when user is organizer' do - sign_in user_organizer + shared_examples 'correct abilities for organizers and organization_admin' do + scenario 'for conference attributes' do + visit admin_conference_path(conference1.short_title) + expect(current_path).to eq(admin_conference_path(conference1.short_title)) - visit admin_conference_path(conference1.short_title) - expect(current_path).to eq(admin_conference_path(conference1.short_title)) + expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') + expect(page).to have_link('Basics', href: "/admin/conferences/#{conference1.short_title}/edit") + expect(page).to have_link('Contact', href: "/admin/conferences/#{conference1.short_title}/contact/edit") + expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference1.short_title}/commercials") + expect(page).to have_link('Splashpage', href: "/admin/conferences/#{conference1.short_title}/splashpage") + expect(page).to have_link('Venue', href: "/admin/conferences/#{conference1.short_title}/venue") + expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference1.short_title}/venue/rooms") + expect(page).to have_link('Lodgings', href: "/admin/conferences/#{conference1.short_title}/lodgings") + expect(page).to have_link('Program', href: "/admin/conferences/#{conference1.short_title}/program") + expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference1.short_title}/program/cfps") + expect(page).to have_link('Events', href: "/admin/conferences/#{conference1.short_title}/program/events") + expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference1.short_title}/program/tracks") + expect(page).to have_link('Event Types', href: "/admin/conferences/#{conference1.short_title}/program/event_types") + expect(page).to have_link('Difficulty Levels', href: "/admin/conferences/#{conference1.short_title}/program/difficulty_levels") + expect(page).to have_link('Schedules', href: "/admin/conferences/#{conference1.short_title}/schedules") + expect(page).to have_link('Reports', href: "/admin/conferences/#{conference1.short_title}/program/reports") + expect(page).to have_link('Registrations', href: "/admin/conferences/#{conference1.short_title}/registrations") + expect(page).to have_link('Registration Period', href: "/admin/conferences/#{conference1.short_title}/registration_period") + expect(page).to have_link('Questions', href: "/admin/conferences/#{conference1.short_title}/questions") + expect(page).to have_text('Donations') + expect(page).to have_link('Sponsorship Levels', href: "/admin/conferences/#{conference1.short_title}/sponsorship_levels") + expect(page).to have_link('Sponsors', href: "/admin/conferences/#{conference1.short_title}/sponsors") + expect(page).to have_link('Tickets', href: "/admin/conferences/#{conference1.short_title}/tickets") + expect(page).to have_text('Objectives') + expect(page).to have_link('Campaigns', href: "/admin/conferences/#{conference1.short_title}/campaigns") + expect(page).to have_link('Goals', href: "/admin/conferences/#{conference1.short_title}/targets") + expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference1.short_title}/emails") + expect(page).to have_link('Roles', href: "/admin/conferences/#{conference1.short_title}/roles") + expect(page).to have_link('Resources', href: "/admin/conferences/#{conference1.short_title}/resources") - expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') - expect(page).to have_link('Basics', href: "/admin/conferences/#{conference1.short_title}/edit") - expect(page).to have_link('Contact', href: "/admin/conferences/#{conference1.short_title}/contact/edit") - expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference1.short_title}/commercials") - expect(page).to have_link('Splashpage', href: "/admin/conferences/#{conference1.short_title}/splashpage") - expect(page).to have_link('Venue', href: "/admin/conferences/#{conference1.short_title}/venue") - expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference1.short_title}/venue/rooms") - expect(page).to have_link('Lodgings', href: "/admin/conferences/#{conference1.short_title}/lodgings") - expect(page).to have_link('Program', href: "/admin/conferences/#{conference1.short_title}/program") - expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference1.short_title}/program/cfps") - expect(page).to have_link('Events', href: "/admin/conferences/#{conference1.short_title}/program/events") - expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference1.short_title}/program/tracks") - expect(page).to have_link('Event Types', href: "/admin/conferences/#{conference1.short_title}/program/event_types") - expect(page).to have_link('Difficulty Levels', href: "/admin/conferences/#{conference1.short_title}/program/difficulty_levels") - expect(page).to have_link('Schedules', href: "/admin/conferences/#{conference1.short_title}/schedules") - expect(page).to have_link('Reports', href: "/admin/conferences/#{conference1.short_title}/program/reports") - expect(page).to have_link('Registrations', href: "/admin/conferences/#{conference1.short_title}/registrations") - expect(page).to have_link('Registration Period', href: "/admin/conferences/#{conference1.short_title}/registration_period") - expect(page).to have_link('Questions', href: "/admin/conferences/#{conference1.short_title}/questions") - expect(page).to have_text('Donations') - expect(page).to have_link('Sponsorship Levels', href: "/admin/conferences/#{conference1.short_title}/sponsorship_levels") - expect(page).to have_link('Sponsors', href: "/admin/conferences/#{conference1.short_title}/sponsors") - expect(page).to have_link('Tickets', href: "/admin/conferences/#{conference1.short_title}/tickets") - expect(page).to have_text('Objectives') - expect(page).to have_link('Campaigns', href: "/admin/conferences/#{conference1.short_title}/campaigns") - expect(page).to have_link('Goals', href: "/admin/conferences/#{conference1.short_title}/targets") - expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference1.short_title}/emails") - expect(page).to have_link('Roles', href: "/admin/conferences/#{conference1.short_title}/roles") - expect(page).to have_link('Resources', href: "/admin/conferences/#{conference1.short_title}/resources") + visit admin_conference_path(conference6.short_title) + expect(page).to have_link('Add venue', href: "/admin/conferences/#{conference6.short_title}/venue/new") - visit admin_conference_path(conference6.short_title) - expect(page).to have_link('Add venue', href: "/admin/conferences/#{conference6.short_title}/venue/new") + visit edit_admin_conference_path(conference1.short_title) + expect(current_path).to eq(edit_admin_conference_path(conference1.short_title)) - visit edit_admin_conference_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_path(conference1.short_title)) + visit edit_admin_conference_contact_path(conference1.short_title) + expect(current_path).to eq(edit_admin_conference_contact_path(conference1.short_title)) - visit edit_admin_conference_contact_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_contact_path(conference1.short_title)) + visit admin_conference_commercials_path(conference1.short_title) + expect(current_path).to eq(admin_conference_commercials_path(conference1.short_title)) - visit admin_conference_commercials_path(conference1.short_title) - expect(current_path).to eq(admin_conference_commercials_path(conference1.short_title)) + visit new_admin_conference_splashpage_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_splashpage_path(conference1.short_title)) - visit new_admin_conference_splashpage_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_splashpage_path(conference1.short_title)) + visit edit_admin_conference_splashpage_path(conference1.short_title) + expect(current_path).to eq(edit_admin_conference_splashpage_path(conference1.short_title)) - visit edit_admin_conference_splashpage_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_splashpage_path(conference1.short_title)) + visit new_admin_conference_venue_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_venue_path(conference1.short_title)) - visit new_admin_conference_venue_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_venue_path(conference1.short_title)) + conference1.venue = create(:venue) + visit edit_admin_conference_venue_path(conference1.short_title) + expect(current_path).to eq(edit_admin_conference_venue_path(conference1.short_title)) - conference1.venue = create(:venue) - visit edit_admin_conference_venue_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_venue_path(conference1.short_title)) + visit admin_conference_venue_rooms_path(conference1.short_title) + expect(current_path).to eq(admin_conference_venue_rooms_path(conference1.short_title)) - visit admin_conference_venue_rooms_path(conference1.short_title) - expect(current_path).to eq(admin_conference_venue_rooms_path(conference1.short_title)) + create(:room, venue: conference1.venue) + visit edit_admin_conference_venue_room_path(conference1.short_title, conference1.venue.rooms.first) + expect(current_path).to eq(edit_admin_conference_venue_room_path(conference1.short_title, conference1.venue.rooms.first)) - create(:room, venue: conference1.venue) - visit edit_admin_conference_venue_room_path(conference1.short_title, conference1.venue.rooms.first) - expect(current_path).to eq(edit_admin_conference_venue_room_path(conference1.short_title, conference1.venue.rooms.first)) + visit admin_conference_lodgings_path(conference1.short_title) + expect(current_path).to eq(admin_conference_lodgings_path(conference1.short_title)) - visit admin_conference_lodgings_path(conference1.short_title) - expect(current_path).to eq(admin_conference_lodgings_path(conference1.short_title)) + visit new_admin_conference_lodging_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_lodging_path(conference1.short_title)) - visit new_admin_conference_lodging_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_lodging_path(conference1.short_title)) + create(:lodging, conference: conference1) + visit edit_admin_conference_lodging_path(conference1.short_title, conference1.lodgings.first) + expect(current_path).to eq(edit_admin_conference_lodging_path(conference1.short_title, conference1.lodgings.first)) - create(:lodging, conference: conference1) - visit edit_admin_conference_lodging_path(conference1.short_title, conference1.lodgings.first) - expect(current_path).to eq(edit_admin_conference_lodging_path(conference1.short_title, conference1.lodgings.first)) + visit new_admin_conference_program_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_program_path(conference1.short_title)) - visit new_admin_conference_program_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_program_path(conference1.short_title)) + visit edit_admin_conference_program_path(conference1.short_title) + expect(current_path).to eq(edit_admin_conference_program_path(conference1.short_title)) - visit edit_admin_conference_program_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_program_path(conference1.short_title)) + visit new_admin_conference_program_cfp_path(conference1.short_title) + expect(current_path).to eq root_path + + conference1.program.cfp.destroy! + visit new_admin_conference_program_cfp_path(conference1.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference1.short_title) + create(:cfp, program: conference1.program) + + visit edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp)) - visit new_admin_conference_program_cfp_path(conference1.short_title) - expect(current_path).to eq root_path + visit admin_conference_program_events_path(conference1.short_title) + expect(current_path).to eq(admin_conference_program_events_path(conference1.short_title)) - conference1.program.cfp.destroy! - visit new_admin_conference_program_cfp_path(conference1.short_title) - expect(current_path).to eq new_admin_conference_program_cfp_path(conference1.short_title) - create(:cfp, program: conference1.program) + create(:event, program: conference1.program) + visit edit_admin_conference_program_event_path(conference1.short_title, conference1.program.events.first) + expect(current_path).to eq(edit_admin_conference_program_event_path(conference1.short_title, conference1.program.events.first)) - visit edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp) - expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp)) + visit admin_conference_program_event_types_path(conference1.short_title) + expect(current_path).to eq(admin_conference_program_event_types_path(conference1.short_title)) - visit admin_conference_program_events_path(conference1.short_title) - expect(current_path).to eq(admin_conference_program_events_path(conference1.short_title)) + visit new_admin_conference_program_event_type_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_program_event_type_path(conference1.short_title)) - create(:event, program: conference1.program) - visit edit_admin_conference_program_event_path(conference1.short_title, conference1.program.events.first) - expect(current_path).to eq(edit_admin_conference_program_event_path(conference1.short_title, conference1.program.events.first)) + visit edit_admin_conference_program_event_type_path(conference1.short_title, conference1.program.event_types.first) + expect(current_path).to eq(edit_admin_conference_program_event_type_path(conference1.short_title, conference1.program.event_types.first)) - visit admin_conference_program_event_types_path(conference1.short_title) - expect(current_path).to eq(admin_conference_program_event_types_path(conference1.short_title)) + visit admin_conference_program_difficulty_levels_path(conference1.short_title) + expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference1.short_title)) - visit new_admin_conference_program_event_type_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_program_event_type_path(conference1.short_title)) + visit new_admin_conference_program_difficulty_level_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_program_difficulty_level_path(conference1.short_title)) - visit edit_admin_conference_program_event_type_path(conference1.short_title, conference1.program.event_types.first) - expect(current_path).to eq(edit_admin_conference_program_event_type_path(conference1.short_title, conference1.program.event_types.first)) + visit edit_admin_conference_program_difficulty_level_path(conference1.short_title, conference1.program.difficulty_levels.first) + expect(current_path).to eq(edit_admin_conference_program_difficulty_level_path(conference1.short_title, conference1.program.difficulty_levels.first)) - visit admin_conference_program_difficulty_levels_path(conference1.short_title) - expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference1.short_title)) + visit admin_conference_schedules_path(conference1.short_title) + expect(current_path).to eq(admin_conference_schedules_path(conference1.short_title)) - visit new_admin_conference_program_difficulty_level_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_program_difficulty_level_path(conference1.short_title)) + create(:schedule, program: conference1.program) + visit admin_conference_schedule_path(conference1.short_title, conference1.program.schedules.first) + expect(current_path).to eq(admin_conference_schedule_path(conference1.short_title, conference1.program.schedules.first)) - visit edit_admin_conference_program_difficulty_level_path(conference1.short_title, conference1.program.difficulty_levels.first) - expect(current_path).to eq(edit_admin_conference_program_difficulty_level_path(conference1.short_title, conference1.program.difficulty_levels.first)) + visit admin_conference_program_reports_path(conference1.short_title) + expect(current_path).to eq(admin_conference_program_reports_path(conference1.short_title)) - visit admin_conference_schedules_path(conference1.short_title) - expect(current_path).to eq(admin_conference_schedules_path(conference1.short_title)) + visit admin_conference_registrations_path(conference1.short_title) + expect(current_path).to eq(admin_conference_registrations_path(conference1.short_title)) - create(:schedule, program: conference1.program) - visit admin_conference_schedule_path(conference1.short_title, conference1.program.schedules.first) - expect(current_path).to eq(admin_conference_schedule_path(conference1.short_title, conference1.program.schedules.first)) + create(:registration, user: create(:user), conference: conference1) + visit edit_admin_conference_registration_path(conference1.short_title, conference1.registrations.first) + expect(current_path).to eq(edit_admin_conference_registration_path(conference1.short_title, conference1.registrations.first)) - visit admin_conference_program_reports_path(conference1.short_title) - expect(current_path).to eq(admin_conference_program_reports_path(conference1.short_title)) + visit new_admin_conference_registration_period_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_registration_period_path(conference1.short_title)) - visit admin_conference_registrations_path(conference1.short_title) - expect(current_path).to eq(admin_conference_registrations_path(conference1.short_title)) + create(:registration_period, conference: conference1) + visit edit_admin_conference_registration_period_path(conference1.short_title) + expect(current_path).to eq(edit_admin_conference_registration_period_path(conference1.short_title)) - create(:registration, user: create(:user), conference: conference1) - visit edit_admin_conference_registration_path(conference1.short_title, conference1.registrations.first) - expect(current_path).to eq(edit_admin_conference_registration_path(conference1.short_title, conference1.registrations.first)) + visit admin_conference_questions_path(conference1.short_title) + expect(current_path).to eq(admin_conference_questions_path(conference1.short_title)) - visit new_admin_conference_registration_period_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_registration_period_path(conference1.short_title)) + visit admin_conference_sponsorship_levels_path(conference1.short_title) + expect(current_path).to eq(admin_conference_sponsorship_levels_path(conference1.short_title)) - create(:registration_period, conference: conference1) - visit edit_admin_conference_registration_period_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_registration_period_path(conference1.short_title)) + visit new_admin_conference_sponsorship_level_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_sponsorship_level_path(conference1.short_title)) - visit admin_conference_questions_path(conference1.short_title) - expect(current_path).to eq(admin_conference_questions_path(conference1.short_title)) + create(:sponsorship_level, conference: conference1) + visit edit_admin_conference_sponsorship_level_path(conference1.short_title, conference1.sponsorship_levels.first) + expect(current_path).to eq(edit_admin_conference_sponsorship_level_path(conference1.short_title, conference1.sponsorship_levels.first)) - visit admin_conference_sponsorship_levels_path(conference1.short_title) - expect(current_path).to eq(admin_conference_sponsorship_levels_path(conference1.short_title)) + visit admin_conference_sponsors_path(conference1.short_title) + expect(current_path).to eq(admin_conference_sponsors_path(conference1.short_title)) - visit new_admin_conference_sponsorship_level_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_sponsorship_level_path(conference1.short_title)) + visit new_admin_conference_sponsor_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_sponsor_path(conference1.short_title)) - create(:sponsorship_level, conference: conference1) - visit edit_admin_conference_sponsorship_level_path(conference1.short_title, conference1.sponsorship_levels.first) - expect(current_path).to eq(edit_admin_conference_sponsorship_level_path(conference1.short_title, conference1.sponsorship_levels.first)) + create(:sponsor, conference: conference1, sponsorship_level: conference1.sponsorship_levels.first) + visit edit_admin_conference_sponsor_path(conference1.short_title, conference1.sponsors.first) + expect(current_path).to eq(edit_admin_conference_sponsor_path(conference1.short_title, conference1.sponsors.first)) - visit admin_conference_sponsors_path(conference1.short_title) - expect(current_path).to eq(admin_conference_sponsors_path(conference1.short_title)) + visit admin_conference_tickets_path(conference1.short_title) + expect(current_path).to eq(admin_conference_tickets_path(conference1.short_title)) - visit new_admin_conference_sponsor_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_sponsor_path(conference1.short_title)) + visit new_admin_conference_ticket_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_ticket_path(conference1.short_title)) - create(:sponsor, conference: conference1, sponsorship_level: conference1.sponsorship_levels.first) - visit edit_admin_conference_sponsor_path(conference1.short_title, conference1.sponsors.first) - expect(current_path).to eq(edit_admin_conference_sponsor_path(conference1.short_title, conference1.sponsors.first)) + create(:ticket, conference: conference1) + visit edit_admin_conference_ticket_path(conference1.short_title, conference1.tickets.first) + expect(current_path).to eq(edit_admin_conference_ticket_path(conference1.short_title, conference1.tickets.first)) - visit admin_conference_tickets_path(conference1.short_title) - expect(current_path).to eq(admin_conference_tickets_path(conference1.short_title)) + visit admin_conference_campaigns_path(conference1.short_title) + expect(current_path).to eq(admin_conference_campaigns_path(conference1.short_title)) - visit new_admin_conference_ticket_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_ticket_path(conference1.short_title)) + visit new_admin_conference_campaign_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_campaign_path(conference1.short_title)) - create(:ticket, conference: conference1) - visit edit_admin_conference_ticket_path(conference1.short_title, conference1.tickets.first) - expect(current_path).to eq(edit_admin_conference_ticket_path(conference1.short_title, conference1.tickets.first)) + create(:campaign, conference: conference1) + visit edit_admin_conference_campaign_path(conference1.short_title, conference1.campaigns.first) + expect(current_path).to eq(edit_admin_conference_campaign_path(conference1.short_title, conference1.campaigns.first)) - visit admin_conference_campaigns_path(conference1.short_title) - expect(current_path).to eq(admin_conference_campaigns_path(conference1.short_title)) + visit admin_conference_targets_path(conference1.short_title) + expect(current_path).to eq(admin_conference_targets_path(conference1.short_title)) - visit new_admin_conference_campaign_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_campaign_path(conference1.short_title)) + visit new_admin_conference_target_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_target_path(conference1.short_title)) - create(:campaign, conference: conference1) - visit edit_admin_conference_campaign_path(conference1.short_title, conference1.campaigns.first) - expect(current_path).to eq(edit_admin_conference_campaign_path(conference1.short_title, conference1.campaigns.first)) + create(:target, conference: conference1) + visit edit_admin_conference_target_path(conference1.short_title, conference1.targets.first) + expect(current_path).to eq(edit_admin_conference_target_path(conference1.short_title, conference1.targets.first)) - visit admin_conference_targets_path(conference1.short_title) - expect(current_path).to eq(admin_conference_targets_path(conference1.short_title)) + visit admin_conference_program_tracks_path(conference1.short_title) + expect(current_path).to eq(admin_conference_program_tracks_path(conference1.short_title)) - visit new_admin_conference_target_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_target_path(conference1.short_title)) + visit admin_conference_roles_path(conference1.short_title) + expect(current_path).to eq(admin_conference_roles_path(conference1.short_title)) - create(:target, conference: conference1) - visit edit_admin_conference_target_path(conference1.short_title, conference1.targets.first) - expect(current_path).to eq(edit_admin_conference_target_path(conference1.short_title, conference1.targets.first)) + visit admin_conference_emails_path(conference1.short_title) + expect(current_path).to eq(admin_conference_emails_path(conference1.short_title)) - visit admin_conference_program_tracks_path(conference1.short_title) - expect(current_path).to eq(admin_conference_program_tracks_path(conference1.short_title)) + visit admin_conference_resources_path(conference1.short_title) + expect(current_path).to eq(admin_conference_resources_path(conference1.short_title)) - visit admin_conference_roles_path(conference1.short_title) - expect(current_path).to eq(admin_conference_roles_path(conference1.short_title)) + visit new_admin_conference_resource_path(conference1.short_title) + expect(current_path).to eq(new_admin_conference_resource_path(conference1.short_title)) - visit admin_conference_emails_path(conference1.short_title) - expect(current_path).to eq(admin_conference_emails_path(conference1.short_title)) + create(:resource, conference: conference1) + visit edit_admin_conference_resource_path(conference1.short_title, conference1.resources.first) + expect(current_path).to eq(edit_admin_conference_resource_path(conference1.short_title, conference1.resources.first)) - visit admin_conference_resources_path(conference1.short_title) - expect(current_path).to eq(admin_conference_resources_path(conference1.short_title)) - - visit new_admin_conference_resource_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_resource_path(conference1.short_title)) - - create(:resource, conference: conference1) - visit edit_admin_conference_resource_path(conference1.short_title, conference1.resources.first) - expect(current_path).to eq(edit_admin_conference_resource_path(conference1.short_title, conference1.resources.first)) - - visit admin_revision_history_path - expect(current_path).to eq(admin_revision_history_path) + visit admin_revision_history_path + expect(current_path).to eq(admin_revision_history_path) + end end - scenario 'when user is cfp' do - sign_in user_cfp + context 'when user is organization_admin' do + before do + sign_in user_organization_admin + end - visit admin_conference_path(conference2.short_title) - expect(current_path).to eq(admin_conference_path(conference2.short_title)) + scenario 'can manage organization' do + visit admin_organizations_path + expect(current_path).to eq(admin_organizations_path) - expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') - expect(page).to_not have_link('Basics', href: "/admin/conferences/#{conference2.short_title}/edit") - expect(page).to have_text('Basics') - expect(page).to_not have_link('Contact', href: "/admin/conferences/#{conference2.short_title}/contact/edit") - expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference2.short_title}/commercials") - expect(page).to_not have_link('Splashpage', href: "/admin/conferences/#{conference2.short_title}/splashpage") - expect(page).to have_link('Venue', href: "/admin/conferences/#{conference2.short_title}/venue") - expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference2.short_title}/venue/rooms") - expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference2.short_title}/lodgings") - expect(page).to have_link('Program', href: "/admin/conferences/#{conference2.short_title}/program") - expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference2.short_title}/program/cfps") - expect(page).to have_link('Events', href: "/admin/conferences/#{conference2.short_title}/program/events") - expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference2.short_title}/program/tracks") - expect(page).to have_link('Event Types', href: "/admin/conferences/#{conference2.short_title}/program/event_types") - expect(page).to have_link('Difficulty Levels', href: "/admin/conferences/#{conference2.short_title}/program/difficulty_levels") - expect(page).to have_link('Schedules', href: "/admin/conferences/#{conference2.short_title}/schedules") - expect(page).to have_link('Reports', href: "/admin/conferences/#{conference2.short_title}/program/reports") - expect(page).to_not have_link('Registrations', href: "/admin/conferences/#{conference2.short_title}/registrations") - expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference2.short_title}/registration_period") - expect(page).to_not have_link('Questions', href: "/admin/conferences/#{conference2.short_title}/questions") - expect(page).to_not have_text('Donations') - expect(page).to_not have_link('Sponsorship Levels', href: "/admin/conferences/#{conference2.short_title}/supporter_levels") - expect(page).to_not have_link('Sponsors', href: "/admin/conferences/#{conference2.short_title}/sponsors") - expect(page).to_not have_link('Tickets', href: "/admin/conferences/#{conference2.short_title}/tickets") - expect(page).to_not have_text('Objectives') - expect(page).to_not have_link('Campaigns', href: "/admin/conferences/#{conference2.short_title}/campaigns") - expect(page).to_not have_link('Goals', href: "/admin/conferences/#{conference2.short_title}/targets") - expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference2.short_title}/emails") - expect(page).to have_link('Roles', href: "/admin/conferences/#{conference2.short_title}/roles") - expect(page).to have_link('Resources', href: "/admin/conferences/#{conference2.short_title}/resources") + visit edit_admin_organization_path(organization) + expect(current_path).to eq(edit_admin_organization_path(organization)) - visit edit_admin_conference_path(conference2.short_title) - expect(current_path).to eq(root_path) + visit new_admin_organization_path + expect(current_path).to eq(root_path) + end - visit edit_admin_conference_contact_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_commercials_path(conference2.short_title) - expect(current_path).to eq(admin_conference_commercials_path(conference2.short_title)) - - visit new_admin_conference_splashpage_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit edit_admin_conference_splashpage_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_venue_path(conference2.short_title) - expect(current_path).to eq(root_path) - - conference2.venue = create(:venue) - visit edit_admin_conference_venue_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_venue_rooms_path(conference2.short_title) - expect(current_path).to eq(admin_conference_venue_rooms_path(conference2.short_title)) - create(:room, venue: conference2.venue) - visit edit_admin_conference_venue_room_path(conference2.short_title, conference2.venue.rooms.first) - expect(current_path).to eq(edit_admin_conference_venue_room_path(conference2.short_title, conference2.venue.rooms.first)) - - visit admin_conference_lodgings_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_lodging_path(conference2.short_title) - expect(current_path).to eq(root_path) - - create(:lodging, conference: conference2) - visit edit_admin_conference_lodging_path(conference2.short_title, conference2.lodgings.first) - expect(current_path).to eq(root_path) - - visit new_admin_conference_program_path(conference2.short_title) - expect(current_path).to eq(new_admin_conference_program_path(conference2.short_title)) - - visit edit_admin_conference_program_path(conference2.short_title) - expect(current_path).to eq(edit_admin_conference_program_path(conference2.short_title)) - - visit new_admin_conference_program_cfp_path(conference2.short_title) - expect(current_path).to eq root_path - - conference2.program.cfp.destroy! - visit new_admin_conference_program_cfp_path(conference2.short_title) - expect(current_path).to eq new_admin_conference_program_cfp_path(conference2.short_title) - create(:cfp, program: conference2.program) - - visit edit_admin_conference_program_cfp_path(conference2.short_title, conference2.program.cfp) - expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference2.short_title, conference2.program.cfp)) - - visit admin_conference_program_events_path(conference2.short_title) - expect(current_path).to eq(admin_conference_program_events_path(conference2.short_title)) - - create(:event, program: conference2.program) - visit edit_admin_conference_program_event_path(conference2.short_title, conference2.program.events.first) - expect(current_path).to eq(edit_admin_conference_program_event_path(conference2.short_title, conference2.program.events.first)) - - visit admin_conference_program_event_types_path(conference2.short_title) - expect(current_path).to eq(admin_conference_program_event_types_path(conference2.short_title)) - - visit new_admin_conference_program_event_type_path(conference2.short_title) - expect(current_path).to eq(new_admin_conference_program_event_type_path(conference2.short_title)) - - visit edit_admin_conference_program_event_type_path(conference2.short_title, conference2.program.event_types.first) - expect(current_path).to eq(edit_admin_conference_program_event_type_path(conference2.short_title, conference2.program.event_types.first)) - - visit admin_conference_program_difficulty_levels_path(conference2.short_title) - expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference2.short_title)) - - visit new_admin_conference_program_difficulty_level_path(conference2.short_title) - expect(current_path).to eq(new_admin_conference_program_difficulty_level_path(conference2.short_title)) - - visit edit_admin_conference_program_difficulty_level_path(conference2.short_title, conference2.program.difficulty_levels.first) - expect(current_path).to eq(edit_admin_conference_program_difficulty_level_path(conference2.short_title, conference2.program.difficulty_levels.first)) - - visit admin_conference_schedules_path(conference2.short_title) - expect(current_path).to eq(admin_conference_schedules_path(conference2.short_title)) - - create(:schedule, program: conference2.program) - visit admin_conference_schedule_path(conference2.short_title, conference2.program.schedules.first) - expect(current_path).to eq(admin_conference_schedule_path(conference2.short_title, conference2.program.schedules.first)) - - visit admin_conference_program_reports_path(conference2.short_title) - expect(current_path).to eq(admin_conference_program_reports_path(conference2.short_title)) - - visit admin_conference_registrations_path(conference2.short_title) - expect(current_path).to eq(admin_conference_registrations_path(conference2.short_title)) - - create(:registration, user: create(:user), conference: conference2) - visit edit_admin_conference_registration_path(conference2.short_title, conference2.registrations.first) - expect(current_path).to eq(root_path) - - visit new_admin_conference_registration_period_path(conference2.short_title) - expect(current_path).to eq(root_path) - - create(:registration_period, conference: conference2) - visit edit_admin_conference_registration_period_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_questions_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_sponsorship_levels_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_sponsorship_level_path(conference2.short_title) - expect(current_path).to eq(root_path) - - create(:sponsorship_level, conference: conference2) - visit edit_admin_conference_sponsorship_level_path(conference2.short_title, conference2.sponsorship_levels.first) - expect(current_path).to eq(root_path) - - visit admin_conference_sponsors_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_sponsor_path(conference2.short_title) - expect(current_path).to eq(root_path) - - create(:sponsor, conference: conference2, sponsorship_level: conference2.sponsorship_levels.first) - visit edit_admin_conference_sponsor_path(conference2.short_title, conference2.sponsors.first) - expect(current_path).to eq(root_path) - - visit admin_conference_tickets_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_ticket_path(conference2.short_title) - expect(current_path).to eq(root_path) - - create(:ticket, conference: conference2) - visit edit_admin_conference_ticket_path(conference2.short_title, conference2.tickets.first) - expect(current_path).to eq(root_path) - - visit admin_conference_campaigns_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_campaign_path(conference2.short_title) - expect(current_path).to eq(root_path) - - create(:campaign, conference: conference2) - visit edit_admin_conference_campaign_path(conference2.short_title, conference2.campaigns.first) - expect(current_path).to eq(root_path) - - visit admin_conference_targets_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_target_path(conference2.short_title) - expect(current_path).to eq(root_path) - - create(:target, conference: conference2) - visit edit_admin_conference_target_path(conference2.short_title, conference2.targets.first) - expect(current_path).to eq(root_path) - - visit admin_conference_program_tracks_path(conference2.short_title) - expect(current_path).to eq(admin_conference_program_tracks_path(conference2.short_title)) - - visit admin_conference_roles_path(conference2.short_title) - expect(current_path).to eq(admin_conference_roles_path(conference2.short_title)) - - visit admin_conference_emails_path(conference2.short_title) - expect(current_path).to eq(admin_conference_emails_path(conference2.short_title)) - - visit admin_conference_resources_path(conference2.short_title) - expect(current_path).to eq(admin_conference_resources_path(conference2.short_title)) - - visit new_admin_conference_resource_path(conference2.short_title) - expect(current_path).to eq(new_admin_conference_resource_path(conference2.short_title)) - - create(:resource, conference: conference2) - visit edit_admin_conference_resource_path(conference2.short_title, conference2.resources.first) - expect(current_path).to eq(edit_admin_conference_resource_path(conference2.short_title, conference2.resources.first)) - - visit admin_revision_history_path - expect(current_path).to eq(root_path) + it_behaves_like 'correct abilities for organizers and organization_admin' end - scenario 'when user is info desk' do - sign_in user_info_desk + context 'when user is organizer' do + before do + sign_in user_organizer + end - visit admin_conference_path(conference3.short_title) - expect(current_path).to eq(admin_conference_path(conference3.short_title)) + scenario 'cannot manage organization' do + visit admin_organizations_path + expect(current_path).to eq(admin_organizations_path) - expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') - expect(page).to_not have_link('Basics', href: "/admin/conferences/#{conference3.short_title}/edit") - expect(page).to have_text('Basics') - expect(page).to_not have_link('Contact', href: "/admin/conferences/#{conference3.short_title}/contact/edit") - expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference3.short_title}/commercials") - expect(page).to_not have_link('Splashpage', href: "/admin/conferences/#{conference3.short_title}/splashpage") - expect(page).to_not have_link('Venue', href: "/admin/conferences/#{conference3.short_title}/venue") - expect(page).to_not have_link('Rooms', href: "/admin/conferences/#{conference3.short_title}/venue/rooms") - expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference3.short_title}/lodgings") - expect(page).to_not have_link('Program', href: "/admin/conferences/#{conference3.short_title}/program") - expect(page).to_not have_link('Call for Papers', href: "/admin/conferences/#{conference2.short_title}/program/cfp") - expect(page).to_not have_link('Events', href: "/admin/conferences/#{conference3.short_title}/program/events") - expect(page).to_not have_link('Tracks', href: "/admin/conferences/#{conference3.short_title}/program/tracks") - expect(page).to_not have_link('Event Types', href: "/admin/conferences/#{conference3.short_title}/program/event_types") - expect(page).to_not have_link('Difficulty Levels', href: "/admin/conferences/#{conference3.short_title}/program/difficulty_levels") - expect(page).to_not have_link('Schedules', href: "/admin/conferences/#{conference3.short_title}/schedules") - expect(page).to_not have_link('Reports', href: "/admin/conferences/#{conference3.short_title}/program/reports") - expect(page).to have_link('Registrations', href: "/admin/conferences/#{conference3.short_title}/registrations") - expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference3.short_title}/registration_period") - expect(page).to have_link('Questions', href: "/admin/conferences/#{conference3.short_title}/questions") - expect(page).to_not have_text('Donations') - expect(page).to_not have_link('Sponsorship Levels', href: "/admin/conferences/#{conference3.short_title}/sponsorship_levels") - expect(page).to_not have_link('Sponsors', href: "/admin/conferences/#{conference3.short_title}/sponsors") - expect(page).to_not have_link('Tickets', href: "/admin/conferences/#{conference3.short_title}/tickets") - expect(page).to_not have_text('Objectives') - expect(page).to_not have_link('Campaigns', href: "/admin/conferences/#{conference3.short_title}/campaigns") - expect(page).to_not have_link('Goals', href: "/admin/conferences/#{conference3.short_title}/targets") - expect(page).to_not have_link('E-Mails', href: "/admin/conferences/#{conference3.short_title}/emails") - expect(page).to have_link('Roles', href: "/admin/conferences/#{conference3.short_title}/roles") - expect(page).to have_link('Resources', href: "/admin/conferences/#{conference3.short_title}/resources") + visit edit_admin_organization_path(organization) + expect(current_path).to eq(root_path) - visit edit_admin_conference_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit new_admin_organization_path + expect(current_path).to eq(root_path) + end - visit edit_admin_conference_contact_path(conference3.short_title) - expect(current_path).to eq(root_path) + it_behaves_like 'correct abilities for organizers and organization_admin' + end - visit admin_conference_commercials_path(conference3.short_title) - expect(current_path).to eq(admin_conference_commercials_path(conference3.short_title)) + shared_examples 'correct abilities for cfps and info_desk' do |role| + scenario 'correct ability' do + if role == 'cfp' + conference = conference2 + elsif role == 'info_desk' + conference = conference3 + end - visit new_admin_conference_splashpage_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_conference_path(conference.short_title) + expect(current_path).to eq(admin_conference_path(conference.short_title)) - visit edit_admin_conference_splashpage_path(conference3.short_title) - expect(current_path).to eq(root_path) + expect(page).to_not have_link('Basics', href: "/admin/conferences/#{conference.short_title}/edit") + expect(page).to have_text('Basics') + expect(page).to_not have_link('Contact', href: "/admin/conferences/#{conference.short_title}/contact/edit") + expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference.short_title}/commercials") + expect(page).to_not have_link('Splashpage', href: "/admin/conferences/#{conference.short_title}/splashpage") + expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference.short_title}/lodgings") + expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period") + expect(page).to_not have_text('Donations') + expect(page).to_not have_link('Sponsorship Levels', href: "/admin/conferences/#{conference.short_title}/sponsorship_levels") + expect(page).to_not have_link('Sponsors', href: "/admin/conferences/#{conference.short_title}/sponsors") + expect(page).to_not have_link('Tickets', href: "/admin/conferences/#{conference.short_title}/tickets") + expect(page).to_not have_text('Objectives') + expect(page).to_not have_link('Campaigns', href: "/admin/conferences/#{conference.short_title}/campaigns") + expect(page).to_not have_link('Goals', href: "/admin/conferences/#{conference.short_title}/targets") + expect(page).to have_link('Roles', href: "/admin/conferences/#{conference.short_title}/roles") + expect(page).to have_link('Resources', href: "/admin/conferences/#{conference.short_title}/resources") - visit new_admin_conference_venue_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_organizations_path + expect(current_path).to eq(admin_organizations_path) - conference3.venue = create(:venue) - visit edit_admin_conference_venue_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit edit_admin_organization_path(organization) + expect(current_path).to eq(root_path) - visit admin_conference_venue_rooms_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit new_admin_organization_path + expect(current_path).to eq(root_path) - create(:room, venue: conference3.venue) - visit edit_admin_conference_venue_room_path(conference3.short_title, conference3.venue.rooms.first) - expect(current_path).to eq(root_path) + visit edit_admin_conference_path(conference.short_title) + expect(current_path).to eq(root_path) - visit admin_conference_lodgings_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit edit_admin_conference_contact_path(conference.short_title) + expect(current_path).to eq(root_path) - visit new_admin_conference_lodging_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_conference_commercials_path(conference.short_title) + expect(current_path).to eq(admin_conference_commercials_path(conference.short_title)) - create(:lodging, conference: conference3) - visit edit_admin_conference_lodging_path(conference3.short_title, conference3.lodgings.first) - expect(current_path).to eq(root_path) + visit new_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq(root_path) - visit new_admin_conference_program_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit edit_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq(root_path) - visit edit_admin_conference_program_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit new_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq(root_path) - visit new_admin_conference_program_cfp_path(conference3.short_title) - expect(current_path).to eq(root_path) + conference.venue = create(:venue) + visit edit_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq(root_path) - visit edit_admin_conference_program_cfp_path(conference3.short_title, conference3.program.cfp) - expect(current_path).to eq(root_path) + visit admin_conference_lodgings_path(conference.short_title) + expect(current_path).to eq(root_path) - visit admin_conference_program_events_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit new_admin_conference_lodging_path(conference.short_title) + expect(current_path).to eq(root_path) - create(:event, program: conference3.program) - visit edit_admin_conference_program_event_path(conference3.short_title, conference3.program.events.first) - expect(current_path).to eq(root_path) + create(:lodging, conference: conference) + visit edit_admin_conference_lodging_path(conference.short_title, conference.lodgings.first) + expect(current_path).to eq(root_path) - visit admin_conference_program_event_types_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit new_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(root_path) - visit new_admin_conference_program_event_type_path(conference3.short_title) - expect(current_path).to eq(root_path) + create(:registration_period, conference: conference) + visit edit_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(root_path) - visit edit_admin_conference_program_event_type_path(conference3.short_title, conference3.program.event_types.first) - expect(current_path).to eq(root_path) + visit admin_conference_sponsorship_levels_path(conference.short_title) + expect(current_path).to eq(root_path) - visit admin_conference_program_difficulty_levels_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit new_admin_conference_sponsorship_level_path(conference.short_title) + expect(current_path).to eq(root_path) - visit new_admin_conference_program_difficulty_level_path(conference3.short_title) - expect(current_path).to eq(root_path) + create(:sponsorship_level, conference: conference) + visit edit_admin_conference_sponsorship_level_path(conference.short_title, conference.sponsorship_levels.first) + expect(current_path).to eq(root_path) - visit edit_admin_conference_program_difficulty_level_path(conference3.short_title, conference3.program.difficulty_levels.first) - expect(current_path).to eq(root_path) + visit admin_conference_sponsors_path(conference.short_title) + expect(current_path).to eq(root_path) - visit admin_conference_schedules_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit new_admin_conference_sponsor_path(conference.short_title) + expect(current_path).to eq(root_path) - create(:schedule, program: conference3.program) - visit admin_conference_schedule_path(conference3.short_title, conference3.program.schedules.first) - expect(current_path).to eq(root_path) + create(:sponsor, conference: conference, sponsorship_level: conference.sponsorship_levels.first) + visit edit_admin_conference_sponsor_path(conference.short_title, conference.sponsors.first) + expect(current_path).to eq(root_path) - visit admin_conference_program_reports_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_conference_tickets_path(conference.short_title) + expect(current_path).to eq(root_path) - visit admin_conference_registrations_path(conference3.short_title) - expect(current_path).to eq(admin_conference_registrations_path(conference3.short_title)) + visit new_admin_conference_ticket_path(conference.short_title) + expect(current_path).to eq(root_path) - create(:registration, user: create(:user), conference: conference3) - visit edit_admin_conference_registration_path(conference3.short_title, conference3.registrations.first) - expect(current_path).to eq(edit_admin_conference_registration_path(conference3.short_title, conference3.registrations.first)) + create(:ticket, conference: conference) + visit edit_admin_conference_ticket_path(conference.short_title, conference.tickets.first) + expect(current_path).to eq(root_path) - visit new_admin_conference_registration_period_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_conference_campaigns_path(conference.short_title) + expect(current_path).to eq(root_path) - create(:registration_period, conference: conference3) - visit edit_admin_conference_registration_period_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit new_admin_conference_campaign_path(conference.short_title) + expect(current_path).to eq(root_path) - visit admin_conference_questions_path(conference3.short_title) - expect(current_path).to eq(admin_conference_questions_path(conference3.short_title)) + create(:campaign, conference: conference) + visit edit_admin_conference_campaign_path(conference.short_title, conference.campaigns.first) + expect(current_path).to eq(root_path) - visit admin_conference_sponsorship_levels_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_conference_targets_path(conference.short_title) + expect(current_path).to eq(root_path) - visit new_admin_conference_sponsorship_level_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit new_admin_conference_target_path(conference.short_title) + expect(current_path).to eq(root_path) - create(:sponsorship_level, conference: conference3) - visit edit_admin_conference_sponsorship_level_path(conference3.short_title, conference3.sponsorship_levels.first) - expect(current_path).to eq(root_path) + create(:target, conference: conference) + visit edit_admin_conference_target_path(conference.short_title, conference.targets.first) + expect(current_path).to eq(root_path) - visit admin_conference_sponsors_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_conference_roles_path(conference.short_title) + expect(current_path).to eq(admin_conference_roles_path(conference.short_title)) - visit new_admin_conference_sponsor_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_conference_resources_path(conference.short_title) + expect(current_path).to eq(admin_conference_resources_path(conference.short_title)) - create(:sponsor, conference: conference3, sponsorship_level: conference3.sponsorship_levels.first) - visit edit_admin_conference_sponsor_path(conference3.short_title, conference3.sponsors.first) - expect(current_path).to eq(root_path) + visit new_admin_conference_resource_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_resource_path(conference.short_title)) - visit admin_conference_tickets_path(conference3.short_title) - expect(current_path).to eq(root_path) + create(:resource, conference: conference) + visit edit_admin_conference_resource_path(conference.short_title, conference.resources.first) + expect(current_path).to eq(edit_admin_conference_resource_path(conference.short_title, conference.resources.first)) - visit new_admin_conference_ticket_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_revision_history_path + expect(current_path).to eq(root_path) + end + end - create(:ticket, conference: conference3) - visit edit_admin_conference_ticket_path(conference3.short_title, conference3.tickets.first) - expect(current_path).to eq(root_path) + context 'when user is cfp' do + before do + sign_in user_cfp + @conference = conference2 + end + scenario 'has correct abilities' do + visit admin_conference_path(conference2.short_title) + expect(current_path).to eq(admin_conference_path(conference2.short_title)) - visit admin_conference_campaigns_path(conference3.short_title) - expect(current_path).to eq(root_path) + expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') + expect(page).to_not have_link('Basics', href: "/admin/conferences/#{conference2.short_title}/edit") + expect(page).to have_text('Basics') + expect(page).to_not have_link('Contact', href: "/admin/conferences/#{conference2.short_title}/contact/edit") + expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference2.short_title}/commercials") + expect(page).to_not have_link('Splashpage', href: "/admin/conferences/#{conference2.short_title}/splashpage") + expect(page).to have_link('Venue', href: "/admin/conferences/#{conference2.short_title}/venue") + expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference2.short_title}/venue/rooms") + expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference2.short_title}/lodgings") + expect(page).to have_link('Program', href: "/admin/conferences/#{conference2.short_title}/program") + expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference2.short_title}/program/cfps") + expect(page).to have_link('Events', href: "/admin/conferences/#{conference2.short_title}/program/events") + expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference2.short_title}/program/tracks") + expect(page).to have_link('Event Types', href: "/admin/conferences/#{conference2.short_title}/program/event_types") + expect(page).to have_link('Difficulty Levels', href: "/admin/conferences/#{conference2.short_title}/program/difficulty_levels") + expect(page).to have_link('Schedules', href: "/admin/conferences/#{conference2.short_title}/schedules") + expect(page).to have_link('Reports', href: "/admin/conferences/#{conference2.short_title}/program/reports") + expect(page).to_not have_link('Registrations', href: "/admin/conferences/#{conference2.short_title}/registrations") + expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference2.short_title}/registration_period") + expect(page).to_not have_link('Questions', href: "/admin/conferences/#{conference2.short_title}/questions") + expect(page).to_not have_text('Donations') + expect(page).to_not have_link('Sponsorship Levels', href: "/admin/conferences/#{conference2.short_title}/supporter_levels") + expect(page).to_not have_link('Sponsors', href: "/admin/conferences/#{conference2.short_title}/sponsors") + expect(page).to_not have_link('Tickets', href: "/admin/conferences/#{conference2.short_title}/tickets") + expect(page).to_not have_text('Objectives') + expect(page).to_not have_link('Campaigns', href: "/admin/conferences/#{conference2.short_title}/campaigns") + expect(page).to_not have_link('Goals', href: "/admin/conferences/#{conference2.short_title}/targets") + expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference2.short_title}/emails") + expect(page).to have_link('Roles', href: "/admin/conferences/#{conference2.short_title}/roles") + expect(page).to have_link('Resources', href: "/admin/conferences/#{conference2.short_title}/resources") - visit new_admin_conference_campaign_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_conference_venue_rooms_path(conference2.short_title) + expect(current_path).to eq(admin_conference_venue_rooms_path(conference2.short_title)) + create(:room, venue: conference2.venue) + visit edit_admin_conference_venue_room_path(conference2.short_title, conference2.venue.rooms.first) + expect(current_path).to eq(edit_admin_conference_venue_room_path(conference2.short_title, conference2.venue.rooms.first)) - create(:campaign, conference: conference3) - visit edit_admin_conference_campaign_path(conference3.short_title, conference3.campaigns.first) - expect(current_path).to eq(root_path) + visit new_admin_conference_program_path(conference2.short_title) + expect(current_path).to eq(new_admin_conference_program_path(conference2.short_title)) - visit admin_conference_targets_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit edit_admin_conference_program_path(conference2.short_title) + expect(current_path).to eq(edit_admin_conference_program_path(conference2.short_title)) - visit new_admin_conference_target_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit new_admin_conference_program_cfp_path(conference2.short_title) + expect(current_path).to eq(new_admin_conference_program_cfp_path(conference2.short_title)) - create(:target, conference: conference3) - visit edit_admin_conference_target_path(conference3.short_title, conference3.targets.first) - expect(current_path).to eq(root_path) + visit edit_admin_conference_program_cfp_path(conference2.short_title) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference2.short_title)) - visit admin_conference_program_tracks_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_conference_program_events_path(conference2.short_title) + expect(current_path).to eq(admin_conference_program_events_path(conference2.short_title)) - visit admin_conference_roles_path(conference3.short_title) - expect(current_path).to eq(admin_conference_roles_path(conference3.short_title)) + create(:event, program: conference2.program) + visit edit_admin_conference_program_event_path(conference2.short_title, conference2.program.events.first) + expect(current_path).to eq(edit_admin_conference_program_event_path(conference2.short_title, conference2.program.events.first)) - visit admin_conference_emails_path(conference3.short_title) - expect(current_path).to eq(root_path) + visit admin_conference_program_event_types_path(conference2.short_title) + expect(current_path).to eq(admin_conference_program_event_types_path(conference2.short_title)) - visit admin_conference_resources_path(conference3.short_title) - expect(current_path).to eq(admin_conference_resources_path(conference3.short_title)) + visit new_admin_conference_program_event_type_path(conference2.short_title) + expect(current_path).to eq(new_admin_conference_program_event_type_path(conference2.short_title)) - visit new_admin_conference_resource_path(conference3.short_title) - expect(current_path).to eq(new_admin_conference_resource_path(conference3.short_title)) + visit edit_admin_conference_program_event_type_path(conference2.short_title, conference2.program.event_types.first) + expect(current_path).to eq(edit_admin_conference_program_event_type_path(conference2.short_title, conference2.program.event_types.first)) - create(:resource, conference: conference3) - visit edit_admin_conference_resource_path(conference3.short_title, conference3.resources.first) - expect(current_path).to eq(edit_admin_conference_resource_path(conference3.short_title, conference3.resources.first)) + visit admin_conference_program_difficulty_levels_path(conference2.short_title) + expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference2.short_title)) - visit admin_revision_history_path - expect(current_path).to eq(root_path) + visit new_admin_conference_program_difficulty_level_path(conference2.short_title) + expect(current_path).to eq(new_admin_conference_program_difficulty_level_path(conference2.short_title)) + + visit edit_admin_conference_program_difficulty_level_path(conference2.short_title, conference2.program.difficulty_levels.first) + expect(current_path).to eq(edit_admin_conference_program_difficulty_level_path(conference2.short_title, conference2.program.difficulty_levels.first)) + + visit admin_conference_schedules_path(conference2.short_title) + expect(current_path).to eq(admin_conference_schedules_path(conference2.short_title)) + + create(:schedule, program: conference2.program) + visit admin_conference_schedule_path(conference2.short_title, conference2.program.schedules.first) + expect(current_path).to eq(admin_conference_schedule_path(conference2.short_title, conference2.program.schedules.first)) + + visit admin_conference_program_reports_path(conference2.short_title) + expect(current_path).to eq(admin_conference_program_reports_path(conference2.short_title)) + + visit admin_conference_registrations_path(conference2.short_title) + expect(current_path).to eq(admin_conference_registrations_path(conference2.short_title)) + + create(:registration, user: create(:user), conference: conference2) + visit edit_admin_conference_registration_path(conference2.short_title, conference2.registrations.first) + expect(current_path).to eq(root_path) + + visit new_admin_conference_registration_period_path(conference2.short_title) + expect(current_path).to eq(root_path) + + create(:registration_period, conference: conference2) + visit edit_admin_conference_registration_period_path(conference2.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_questions_path(conference2.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_program_tracks_path(conference2.short_title) + expect(current_path).to eq(admin_conference_program_tracks_path(conference2.short_title)) + + visit admin_conference_roles_path(conference2.short_title) + expect(current_path).to eq(admin_conference_roles_path(conference2.short_title)) + + visit admin_conference_emails_path(conference2.short_title) + expect(current_path).to eq(admin_conference_emails_path(conference2.short_title)) + end + + it_behaves_like 'correct abilities for cfps and info_desk', 'cfp' + end + + context 'when user is info desk' do + before do + sign_in user_info_desk + end + + scenario 'has correct abilities' do + visit admin_conference_path(conference3.short_title) + expect(current_path).to eq(admin_conference_path(conference3.short_title)) + + expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') + expect(page).to_not have_link('Venue', href: "/admin/conferences/#{conference3.short_title}/venue") + expect(page).to_not have_link('Rooms', href: "/admin/conferences/#{conference3.short_title}/venue/rooms") + expect(page).to_not have_link('Program', href: "/admin/conferences/#{conference3.short_title}/program") + expect(page).to_not have_link('Call for Papers', href: "/admin/conferences/#{conference2.short_title}/program/cfps") + expect(page).to_not have_link('Events', href: "/admin/conferences/#{conference3.short_title}/program/events") + expect(page).to_not have_link('Tracks', href: "/admin/conferences/#{conference3.short_title}/program/tracks") + expect(page).to_not have_link('Event Types', href: "/admin/conferences/#{conference3.short_title}/program/event_types") + expect(page).to_not have_link('Difficulty Levels', href: "/admin/conferences/#{conference3.short_title}/program/difficulty_levels") + expect(page).to_not have_link('Schedules', href: "/admin/conferences/#{conference3.short_title}/schedules") + expect(page).to_not have_link('Reports', href: "/admin/conferences/#{conference3.short_title}/program/reports") + expect(page).to have_link('Registrations', href: "/admin/conferences/#{conference3.short_title}/registrations") + expect(page).to have_link('Questions', href: "/admin/conferences/#{conference3.short_title}/questions") + expect(page).to_not have_link('E-Mails', href: "/admin/conferences/#{conference3.short_title}/emails") + + visit admin_conference_venue_rooms_path(conference3.short_title) + expect(current_path).to eq(root_path) + + create(:room, venue: conference3.venue) + visit edit_admin_conference_venue_room_path(conference3.short_title, conference3.venue.rooms.first) + expect(current_path).to eq(root_path) + + visit new_admin_conference_program_path(conference3.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_program_path(conference3.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_program_cfp_path(conference3.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_program_cfp_path(conference3.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_program_events_path(conference3.short_title) + expect(current_path).to eq(root_path) + + create(:event, program: conference3.program) + visit edit_admin_conference_program_event_path(conference3.short_title, conference3.program.events.first) + expect(current_path).to eq(root_path) + + visit admin_conference_program_event_types_path(conference3.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_program_event_type_path(conference3.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_program_event_type_path(conference3.short_title, conference3.program.event_types.first) + expect(current_path).to eq(root_path) + + visit admin_conference_program_difficulty_levels_path(conference3.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_program_difficulty_level_path(conference3.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_program_difficulty_level_path(conference3.short_title, conference3.program.difficulty_levels.first) + expect(current_path).to eq(root_path) + + visit admin_conference_schedules_path(conference3.short_title) + expect(current_path).to eq(root_path) + + create(:schedule, program: conference3.program) + visit admin_conference_schedule_path(conference3.short_title, conference3.program.schedules.first) + expect(current_path).to eq(root_path) + + visit admin_conference_program_reports_path(conference3.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_registrations_path(conference3.short_title) + expect(current_path).to eq(admin_conference_registrations_path(conference3.short_title)) + + create(:registration, user: create(:user), conference: conference3) + visit edit_admin_conference_registration_path(conference3.short_title, conference3.registrations.first) + expect(current_path).to eq(edit_admin_conference_registration_path(conference3.short_title, conference3.registrations.first)) + + visit admin_conference_questions_path(conference3.short_title) + expect(current_path).to eq(admin_conference_questions_path(conference3.short_title)) + + visit admin_conference_program_tracks_path(conference3.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_emails_path(conference3.short_title) + expect(current_path).to eq(root_path) + end + + it_behaves_like 'correct abilities for cfps and info_desk', 'info_desk' end end diff --git a/spec/features/organization_spec.rb b/spec/features/organization_spec.rb new file mode 100644 index 00000000..72fee466 --- /dev/null +++ b/spec/features/organization_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +feature Organization do + let!(:organization) { create(:organization) } + let!(:organization_admin_role) { Role.find_by(name: 'organization_admin', resource: organization) } + let(:organization_admin) { create(:user, role_ids: [organization_admin_role.id]) } + let(:admin_user) { create(:admin) } + + shared_examples 'successfully updates a organization' do + scenario 'updates a exsisting organization', feature: true, js: true do + visit edit_admin_organization_path(organization) + fill_in 'organization_name', with: 'changed name' + + click_button 'Update Organization' + + organization.reload + expect(flash).to eq('Organization successfully updated') + expect(organization.name).to eq('changed name') + end + end + + context 'signed in as site admin' do + before do + sign_in admin_user + end + scenario 'creates a new organization', feature: true, js: true do + visit new_admin_organization_path + fill_in 'organization_name', with: 'Organization name' + + click_button 'Create Organization' + + expect(flash).to eq('Organization successfully created') + expect(Organization.last.name).to eq('Organization name') + end + + it_behaves_like 'successfully updates a organization' + end + + context 'signed in as organization admin' do + before do + sign_in organization_admin + end + scenario "can't create new organization", feature: true, js: true do + visit new_admin_organization_path + + expect(flash).to eq('You are not authorized to access this page.') + end + + it_behaves_like 'successfully updates a organization' + end +end From 3daa12f83fdbc9a44ea6c14d7843501262478721 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 28 Jun 2017 08:05:04 +0530 Subject: [PATCH 054/237] fix tests for cfps after rebase --- spec/features/ability_spec.rb | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/spec/features/ability_spec.rb b/spec/features/ability_spec.rb index 41775de4..915ce401 100644 --- a/spec/features/ability_spec.rb +++ b/spec/features/ability_spec.rb @@ -114,12 +114,12 @@ feature 'Has correct abilities' do visit new_admin_conference_program_cfp_path(conference1.short_title) expect(current_path).to eq root_path - + conference1.program.cfp.destroy! visit new_admin_conference_program_cfp_path(conference1.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference1.short_title) create(:cfp, program: conference1.program) - + visit edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp) expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp)) @@ -484,13 +484,15 @@ feature 'Has correct abilities' do expect(current_path).to eq(edit_admin_conference_program_path(conference2.short_title)) visit new_admin_conference_program_cfp_path(conference2.short_title) - expect(current_path).to eq(new_admin_conference_program_cfp_path(conference2.short_title)) + expect(current_path).to eq root_path - visit edit_admin_conference_program_cfp_path(conference2.short_title) - expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference2.short_title)) + conference2.program.cfp.destroy! + visit new_admin_conference_program_cfp_path(conference2.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference2.short_title) + create(:cfp, program: conference2.program) - visit admin_conference_program_events_path(conference2.short_title) - expect(current_path).to eq(admin_conference_program_events_path(conference2.short_title)) + visit edit_admin_conference_program_cfp_path(conference2.short_title, conference2.program.cfp) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference2.short_title, conference2.program.cfp)) create(:event, program: conference2.program) visit edit_admin_conference_program_event_path(conference2.short_title, conference2.program.events.first) @@ -592,9 +594,14 @@ feature 'Has correct abilities' do expect(current_path).to eq(root_path) visit new_admin_conference_program_cfp_path(conference3.short_title) - expect(current_path).to eq(root_path) + expect(current_path).to eq root_path - visit edit_admin_conference_program_cfp_path(conference3.short_title) + conference1.program.cfp.destroy! + visit new_admin_conference_program_cfp_path(conference3.short_title) + expect(current_path).to eq root_path + create(:cfp, program: conference1.program) + + visit edit_admin_conference_program_cfp_path(conference3.short_title, conference3.program.cfp) expect(current_path).to eq(root_path) visit admin_conference_program_events_path(conference3.short_title) From 651abcab87cf1699fba41f9c31eb1a314046059b Mon Sep 17 00:00:00 2001 From: shlok007 Date: Fri, 30 Jun 2017 09:18:17 +0530 Subject: [PATCH 055/237] split feature tests for abilities and suggested changes --- app/models/ability.rb | 73 +- spec/features/ability_spec.rb | 661 ------------------ spec/features/cfp_ability_spec.rb | 250 +++++++ spec/features/info_desk_ability_spec.rb | 246 +++++++ .../organization_admin_ability_spec.rb | 240 +++++++ spec/features/organizer_ability_spec.rb | 247 +++++++ spec/features/user_ability_spec.rb | 21 + spec/models/ability_spec.rb | 42 +- 8 files changed, 1059 insertions(+), 721 deletions(-) delete mode 100644 spec/features/ability_spec.rb create mode 100644 spec/features/cfp_ability_spec.rb create mode 100644 spec/features/info_desk_ability_spec.rb create mode 100644 spec/features/organization_admin_ability_spec.rb create mode 100644 spec/features/organizer_ability_spec.rb create mode 100644 spec/features/user_ability_spec.rb diff --git a/app/models/ability.rb b/app/models/ability.rb index 37090a49..8185fadd 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -154,10 +154,7 @@ class Ability can :manage, Organization, id: org_ids_for_organization_admin can :new, Conference can :manage, Conference, organization_id: org_ids_for_organization_admin - conf_ids_for_organization_admin = [] - org_ids_for_organization_admin.each do |org_id| - conf_ids_for_organization_admin += Organization.find(org_id).conferences.pluck(:id) - end + conf_ids_for_organization_admin = Conference.where(organization_id: org_ids_for_organization_admin).pluck(:id) can [:index, :show], Role can [:edit, :update], Role do |role| role.resource_type == 'Organization' && (org_ids_for_organization_admin.include? role.resource_id) @@ -168,44 +165,44 @@ class Ability 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' - conf_ids_for_organization_admin_and_organizer = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq - can :manage, Resource, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, Conference, id: conf_ids_for_organization_admin_and_organizer - can :manage, Splashpage, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, Contact, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, EmailSettings, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, Campaign, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, Target, conference_id: conf_ids_for_organization_admin_and_organizer + conf_ids = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq + can :manage, Resource, conference_id: conf_ids + can :manage, Conference, id: conf_ids + can :manage, Splashpage, conference_id: conf_ids + can :manage, Contact, conference_id: conf_ids + can :manage, EmailSettings, conference_id: conf_ids + can :manage, Campaign, conference_id: conf_ids + can :manage, Target, conference_id: conf_ids can :manage, Commercial, commercialable_type: 'Conference', - commercialable_id: conf_ids_for_organization_admin_and_organizer - can :manage, Registration, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, RegistrationPeriod, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, Question, conference_id: conf_ids_for_organization_admin_and_organizer + commercialable_id: conf_ids + can :manage, Registration, conference_id: conf_ids + can :manage, RegistrationPeriod, conference_id: conf_ids + can :manage, Question, conference_id: conf_ids can :manage, Question do |question| - !(question.conferences.pluck(:id) & conf_ids_for_organization_admin_and_organizer).empty? + !(question.conferences.pluck(:id) & conf_ids).empty? end - can :manage, Vposition, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, Vday, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, Program, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, Schedule, program: { conference_id: conf_ids_for_organization_admin_and_organizer } - can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids_for_organization_admin_and_organizer } } - can :manage, Cfp, program: { conference_id: conf_ids_for_organization_admin_and_organizer} - can :manage, Event, program: { conference_id: conf_ids_for_organization_admin_and_organizer} - can :manage, EventType, program: { conference_id: conf_ids_for_organization_admin_and_organizer} - can :manage, Track, program: { conference_id: conf_ids_for_organization_admin_and_organizer} - can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_organization_admin_and_organizer} + can :manage, Vposition, conference_id: conf_ids + can :manage, Vday, conference_id: conf_ids + can :manage, Program, conference_id: conf_ids + can :manage, Schedule, program: { conference_id: conf_ids } + can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids } } + 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, Track, program: { conference_id: conf_ids} + can :manage, DifficultyLevel, program: { conference_id: conf_ids} can :manage, Commercial, commercialable_type: 'Event', - commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organization_admin_and_organizer).pluck(:id)).pluck(:id) - can :manage, Venue, conference_id: conf_ids_for_organization_admin_and_organizer + commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id) + can :manage, Venue, conference_id: conf_ids can :manage, Commercial, commercialable_type: 'Venue', - commercialable_id: Venue.where(conference_id: conf_ids_for_organization_admin_and_organizer).pluck(:id) - can :manage, Lodging, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, Room, venue: { conference_id: conf_ids_for_organization_admin_and_organizer} - can :manage, Sponsor, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, SponsorshipLevel, conference_id: conf_ids_for_organization_admin_and_organizer - can :manage, Ticket, conference_id: conf_ids_for_organization_admin_and_organizer + commercialable_id: Venue.where(conference_id: conf_ids).pluck(:id) + can :manage, Lodging, conference_id: conf_ids + can :manage, Room, venue: { conference_id: conf_ids} + can :manage, Sponsor, conference_id: conf_ids + can :manage, SponsorshipLevel, conference_id: conf_ids + can :manage, Ticket, conference_id: conf_ids can :index, Comment, commentable_type: 'Event', - commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organization_admin_and_organizer).pluck(:id)).pluck(:id) + commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id) # Abilities for Role (Conference resource) can [:index, :show], Role do |role| @@ -213,11 +210,11 @@ class Ability end can [:edit, :update, :toggle_user], Role do |role| - role.resource_type == 'Conference' && (conf_ids_for_organization_admin_and_organizer.include? role.resource_id) + role.resource_type == 'Conference' && (conf_ids.include? role.resource_id) end can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| - version.item_type == 'User' || (conf_ids_for_organization_admin_and_organizer.include? version.conference_id) + version.item_type == 'User' || (conf_ids.include? version.conference_id) end end diff --git a/spec/features/ability_spec.rb b/spec/features/ability_spec.rb deleted file mode 100644 index 915ce401..00000000 --- a/spec/features/ability_spec.rb +++ /dev/null @@ -1,661 +0,0 @@ -require 'spec_helper' - -feature 'Has correct abilities' do - - let(:organization) { create(:organization) } - # It is necessary to use bang version of let to build roles before user - let(:conference1) { create(:full_conference, organization: organization) } # user is organizer - let(:conference2) { create(:full_conference, organization: organization) } # user is cfp - let(:conference3) { create(:full_conference, organization: organization) } # user is info_desk - let(:conference6) { create(:conference, organization: organization) } # user is organizer, venue is not set by default - - let(:role_organization_admin) { Role.find_by(name: 'organization_admin', resource: organization) } - let(:role_organizer_conf1) { Role.find_by(name: 'organizer', resource: conference1) } - let(:role_organizer_conf6) { Role.find_by(name: 'organizer', resource: conference6) } - let(:role_cfp) { Role.find_by(name: 'cfp', resource: conference2) } - let(:role_info_desk) { Role.find_by(name: 'info_desk', resource: conference3) } - - let(:user) { create(:user) } - let(:user_organization_admin) { create(:user, role_ids: [role_organization_admin.id]) } - let(:user_organizer) { create(:user, role_ids: [role_organizer_conf1.id, role_organizer_conf6.id]) } - let(:user_cfp) { create(:user, role_ids: [role_cfp.id]) } - let(:user_info_desk) { create(:user, role_ids: [role_info_desk.id]) } - - scenario 'when user has no role' do - sign_in user - - visit admin_conference_path(conference1.short_title) - expect(current_path).to eq root_path - expect(flash).to eq 'You are not authorized to access this page.' - end - - shared_examples 'correct abilities for organizers and organization_admin' do - scenario 'for conference attributes' do - visit admin_conference_path(conference1.short_title) - expect(current_path).to eq(admin_conference_path(conference1.short_title)) - - expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') - expect(page).to have_link('Basics', href: "/admin/conferences/#{conference1.short_title}/edit") - expect(page).to have_link('Contact', href: "/admin/conferences/#{conference1.short_title}/contact/edit") - expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference1.short_title}/commercials") - expect(page).to have_link('Splashpage', href: "/admin/conferences/#{conference1.short_title}/splashpage") - expect(page).to have_link('Venue', href: "/admin/conferences/#{conference1.short_title}/venue") - expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference1.short_title}/venue/rooms") - expect(page).to have_link('Lodgings', href: "/admin/conferences/#{conference1.short_title}/lodgings") - expect(page).to have_link('Program', href: "/admin/conferences/#{conference1.short_title}/program") - expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference1.short_title}/program/cfps") - expect(page).to have_link('Events', href: "/admin/conferences/#{conference1.short_title}/program/events") - expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference1.short_title}/program/tracks") - expect(page).to have_link('Event Types', href: "/admin/conferences/#{conference1.short_title}/program/event_types") - expect(page).to have_link('Difficulty Levels', href: "/admin/conferences/#{conference1.short_title}/program/difficulty_levels") - expect(page).to have_link('Schedules', href: "/admin/conferences/#{conference1.short_title}/schedules") - expect(page).to have_link('Reports', href: "/admin/conferences/#{conference1.short_title}/program/reports") - expect(page).to have_link('Registrations', href: "/admin/conferences/#{conference1.short_title}/registrations") - expect(page).to have_link('Registration Period', href: "/admin/conferences/#{conference1.short_title}/registration_period") - expect(page).to have_link('Questions', href: "/admin/conferences/#{conference1.short_title}/questions") - expect(page).to have_text('Donations') - expect(page).to have_link('Sponsorship Levels', href: "/admin/conferences/#{conference1.short_title}/sponsorship_levels") - expect(page).to have_link('Sponsors', href: "/admin/conferences/#{conference1.short_title}/sponsors") - expect(page).to have_link('Tickets', href: "/admin/conferences/#{conference1.short_title}/tickets") - expect(page).to have_text('Objectives') - expect(page).to have_link('Campaigns', href: "/admin/conferences/#{conference1.short_title}/campaigns") - expect(page).to have_link('Goals', href: "/admin/conferences/#{conference1.short_title}/targets") - expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference1.short_title}/emails") - expect(page).to have_link('Roles', href: "/admin/conferences/#{conference1.short_title}/roles") - expect(page).to have_link('Resources', href: "/admin/conferences/#{conference1.short_title}/resources") - - visit admin_conference_path(conference6.short_title) - expect(page).to have_link('Add venue', href: "/admin/conferences/#{conference6.short_title}/venue/new") - - visit edit_admin_conference_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_path(conference1.short_title)) - - visit edit_admin_conference_contact_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_contact_path(conference1.short_title)) - - visit admin_conference_commercials_path(conference1.short_title) - expect(current_path).to eq(admin_conference_commercials_path(conference1.short_title)) - - visit new_admin_conference_splashpage_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_splashpage_path(conference1.short_title)) - - visit edit_admin_conference_splashpage_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_splashpage_path(conference1.short_title)) - - visit new_admin_conference_venue_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_venue_path(conference1.short_title)) - - conference1.venue = create(:venue) - visit edit_admin_conference_venue_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_venue_path(conference1.short_title)) - - visit admin_conference_venue_rooms_path(conference1.short_title) - expect(current_path).to eq(admin_conference_venue_rooms_path(conference1.short_title)) - - create(:room, venue: conference1.venue) - visit edit_admin_conference_venue_room_path(conference1.short_title, conference1.venue.rooms.first) - expect(current_path).to eq(edit_admin_conference_venue_room_path(conference1.short_title, conference1.venue.rooms.first)) - - visit admin_conference_lodgings_path(conference1.short_title) - expect(current_path).to eq(admin_conference_lodgings_path(conference1.short_title)) - - visit new_admin_conference_lodging_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_lodging_path(conference1.short_title)) - - create(:lodging, conference: conference1) - visit edit_admin_conference_lodging_path(conference1.short_title, conference1.lodgings.first) - expect(current_path).to eq(edit_admin_conference_lodging_path(conference1.short_title, conference1.lodgings.first)) - - visit new_admin_conference_program_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_program_path(conference1.short_title)) - - visit edit_admin_conference_program_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_program_path(conference1.short_title)) - - visit new_admin_conference_program_cfp_path(conference1.short_title) - expect(current_path).to eq root_path - - conference1.program.cfp.destroy! - visit new_admin_conference_program_cfp_path(conference1.short_title) - expect(current_path).to eq new_admin_conference_program_cfp_path(conference1.short_title) - create(:cfp, program: conference1.program) - - visit edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp) - expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference1.short_title, conference1.program.cfp)) - - visit admin_conference_program_events_path(conference1.short_title) - expect(current_path).to eq(admin_conference_program_events_path(conference1.short_title)) - - create(:event, program: conference1.program) - visit edit_admin_conference_program_event_path(conference1.short_title, conference1.program.events.first) - expect(current_path).to eq(edit_admin_conference_program_event_path(conference1.short_title, conference1.program.events.first)) - - visit admin_conference_program_event_types_path(conference1.short_title) - expect(current_path).to eq(admin_conference_program_event_types_path(conference1.short_title)) - - visit new_admin_conference_program_event_type_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_program_event_type_path(conference1.short_title)) - - visit edit_admin_conference_program_event_type_path(conference1.short_title, conference1.program.event_types.first) - expect(current_path).to eq(edit_admin_conference_program_event_type_path(conference1.short_title, conference1.program.event_types.first)) - - visit admin_conference_program_difficulty_levels_path(conference1.short_title) - expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference1.short_title)) - - visit new_admin_conference_program_difficulty_level_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_program_difficulty_level_path(conference1.short_title)) - - visit edit_admin_conference_program_difficulty_level_path(conference1.short_title, conference1.program.difficulty_levels.first) - expect(current_path).to eq(edit_admin_conference_program_difficulty_level_path(conference1.short_title, conference1.program.difficulty_levels.first)) - - visit admin_conference_schedules_path(conference1.short_title) - expect(current_path).to eq(admin_conference_schedules_path(conference1.short_title)) - - create(:schedule, program: conference1.program) - visit admin_conference_schedule_path(conference1.short_title, conference1.program.schedules.first) - expect(current_path).to eq(admin_conference_schedule_path(conference1.short_title, conference1.program.schedules.first)) - - visit admin_conference_program_reports_path(conference1.short_title) - expect(current_path).to eq(admin_conference_program_reports_path(conference1.short_title)) - - visit admin_conference_registrations_path(conference1.short_title) - expect(current_path).to eq(admin_conference_registrations_path(conference1.short_title)) - - create(:registration, user: create(:user), conference: conference1) - visit edit_admin_conference_registration_path(conference1.short_title, conference1.registrations.first) - expect(current_path).to eq(edit_admin_conference_registration_path(conference1.short_title, conference1.registrations.first)) - - visit new_admin_conference_registration_period_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_registration_period_path(conference1.short_title)) - - create(:registration_period, conference: conference1) - visit edit_admin_conference_registration_period_path(conference1.short_title) - expect(current_path).to eq(edit_admin_conference_registration_period_path(conference1.short_title)) - - visit admin_conference_questions_path(conference1.short_title) - expect(current_path).to eq(admin_conference_questions_path(conference1.short_title)) - - visit admin_conference_sponsorship_levels_path(conference1.short_title) - expect(current_path).to eq(admin_conference_sponsorship_levels_path(conference1.short_title)) - - visit new_admin_conference_sponsorship_level_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_sponsorship_level_path(conference1.short_title)) - - create(:sponsorship_level, conference: conference1) - visit edit_admin_conference_sponsorship_level_path(conference1.short_title, conference1.sponsorship_levels.first) - expect(current_path).to eq(edit_admin_conference_sponsorship_level_path(conference1.short_title, conference1.sponsorship_levels.first)) - - visit admin_conference_sponsors_path(conference1.short_title) - expect(current_path).to eq(admin_conference_sponsors_path(conference1.short_title)) - - visit new_admin_conference_sponsor_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_sponsor_path(conference1.short_title)) - - create(:sponsor, conference: conference1, sponsorship_level: conference1.sponsorship_levels.first) - visit edit_admin_conference_sponsor_path(conference1.short_title, conference1.sponsors.first) - expect(current_path).to eq(edit_admin_conference_sponsor_path(conference1.short_title, conference1.sponsors.first)) - - visit admin_conference_tickets_path(conference1.short_title) - expect(current_path).to eq(admin_conference_tickets_path(conference1.short_title)) - - visit new_admin_conference_ticket_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_ticket_path(conference1.short_title)) - - create(:ticket, conference: conference1) - visit edit_admin_conference_ticket_path(conference1.short_title, conference1.tickets.first) - expect(current_path).to eq(edit_admin_conference_ticket_path(conference1.short_title, conference1.tickets.first)) - - visit admin_conference_campaigns_path(conference1.short_title) - expect(current_path).to eq(admin_conference_campaigns_path(conference1.short_title)) - - visit new_admin_conference_campaign_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_campaign_path(conference1.short_title)) - - create(:campaign, conference: conference1) - visit edit_admin_conference_campaign_path(conference1.short_title, conference1.campaigns.first) - expect(current_path).to eq(edit_admin_conference_campaign_path(conference1.short_title, conference1.campaigns.first)) - - visit admin_conference_targets_path(conference1.short_title) - expect(current_path).to eq(admin_conference_targets_path(conference1.short_title)) - - visit new_admin_conference_target_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_target_path(conference1.short_title)) - - create(:target, conference: conference1) - visit edit_admin_conference_target_path(conference1.short_title, conference1.targets.first) - expect(current_path).to eq(edit_admin_conference_target_path(conference1.short_title, conference1.targets.first)) - - visit admin_conference_program_tracks_path(conference1.short_title) - expect(current_path).to eq(admin_conference_program_tracks_path(conference1.short_title)) - - visit admin_conference_roles_path(conference1.short_title) - expect(current_path).to eq(admin_conference_roles_path(conference1.short_title)) - - visit admin_conference_emails_path(conference1.short_title) - expect(current_path).to eq(admin_conference_emails_path(conference1.short_title)) - - visit admin_conference_resources_path(conference1.short_title) - expect(current_path).to eq(admin_conference_resources_path(conference1.short_title)) - - visit new_admin_conference_resource_path(conference1.short_title) - expect(current_path).to eq(new_admin_conference_resource_path(conference1.short_title)) - - create(:resource, conference: conference1) - visit edit_admin_conference_resource_path(conference1.short_title, conference1.resources.first) - expect(current_path).to eq(edit_admin_conference_resource_path(conference1.short_title, conference1.resources.first)) - - visit admin_revision_history_path - expect(current_path).to eq(admin_revision_history_path) - end - end - - context 'when user is organization_admin' do - before do - sign_in user_organization_admin - end - - scenario 'can manage organization' do - visit admin_organizations_path - expect(current_path).to eq(admin_organizations_path) - - visit edit_admin_organization_path(organization) - expect(current_path).to eq(edit_admin_organization_path(organization)) - - visit new_admin_organization_path - expect(current_path).to eq(root_path) - end - - it_behaves_like 'correct abilities for organizers and organization_admin' - end - - context 'when user is organizer' do - before do - sign_in user_organizer - end - - scenario 'cannot manage organization' do - visit admin_organizations_path - expect(current_path).to eq(admin_organizations_path) - - visit edit_admin_organization_path(organization) - expect(current_path).to eq(root_path) - - visit new_admin_organization_path - expect(current_path).to eq(root_path) - end - - it_behaves_like 'correct abilities for organizers and organization_admin' - end - - shared_examples 'correct abilities for cfps and info_desk' do |role| - scenario 'correct ability' do - if role == 'cfp' - conference = conference2 - elsif role == 'info_desk' - conference = conference3 - end - - visit admin_conference_path(conference.short_title) - expect(current_path).to eq(admin_conference_path(conference.short_title)) - - expect(page).to_not have_link('Basics', href: "/admin/conferences/#{conference.short_title}/edit") - expect(page).to have_text('Basics') - expect(page).to_not have_link('Contact', href: "/admin/conferences/#{conference.short_title}/contact/edit") - expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference.short_title}/commercials") - expect(page).to_not have_link('Splashpage', href: "/admin/conferences/#{conference.short_title}/splashpage") - expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference.short_title}/lodgings") - expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period") - expect(page).to_not have_text('Donations') - expect(page).to_not have_link('Sponsorship Levels', href: "/admin/conferences/#{conference.short_title}/sponsorship_levels") - expect(page).to_not have_link('Sponsors', href: "/admin/conferences/#{conference.short_title}/sponsors") - expect(page).to_not have_link('Tickets', href: "/admin/conferences/#{conference.short_title}/tickets") - expect(page).to_not have_text('Objectives') - expect(page).to_not have_link('Campaigns', href: "/admin/conferences/#{conference.short_title}/campaigns") - expect(page).to_not have_link('Goals', href: "/admin/conferences/#{conference.short_title}/targets") - expect(page).to have_link('Roles', href: "/admin/conferences/#{conference.short_title}/roles") - expect(page).to have_link('Resources', href: "/admin/conferences/#{conference.short_title}/resources") - - visit admin_organizations_path - expect(current_path).to eq(admin_organizations_path) - - visit edit_admin_organization_path(organization) - expect(current_path).to eq(root_path) - - visit new_admin_organization_path - expect(current_path).to eq(root_path) - - visit edit_admin_conference_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit edit_admin_conference_contact_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_commercials_path(conference.short_title) - expect(current_path).to eq(admin_conference_commercials_path(conference.short_title)) - - visit new_admin_conference_splashpage_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit edit_admin_conference_splashpage_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_venue_path(conference.short_title) - expect(current_path).to eq(root_path) - - conference.venue = create(:venue) - visit edit_admin_conference_venue_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_lodgings_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_lodging_path(conference.short_title) - expect(current_path).to eq(root_path) - - create(:lodging, conference: conference) - visit edit_admin_conference_lodging_path(conference.short_title, conference.lodgings.first) - expect(current_path).to eq(root_path) - - visit new_admin_conference_registration_period_path(conference.short_title) - expect(current_path).to eq(root_path) - - create(:registration_period, conference: conference) - visit edit_admin_conference_registration_period_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_sponsorship_levels_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_sponsorship_level_path(conference.short_title) - expect(current_path).to eq(root_path) - - create(:sponsorship_level, conference: conference) - visit edit_admin_conference_sponsorship_level_path(conference.short_title, conference.sponsorship_levels.first) - expect(current_path).to eq(root_path) - - visit admin_conference_sponsors_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_sponsor_path(conference.short_title) - expect(current_path).to eq(root_path) - - create(:sponsor, conference: conference, sponsorship_level: conference.sponsorship_levels.first) - visit edit_admin_conference_sponsor_path(conference.short_title, conference.sponsors.first) - expect(current_path).to eq(root_path) - - visit admin_conference_tickets_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_ticket_path(conference.short_title) - expect(current_path).to eq(root_path) - - create(:ticket, conference: conference) - visit edit_admin_conference_ticket_path(conference.short_title, conference.tickets.first) - expect(current_path).to eq(root_path) - - visit admin_conference_campaigns_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_campaign_path(conference.short_title) - expect(current_path).to eq(root_path) - - create(:campaign, conference: conference) - visit edit_admin_conference_campaign_path(conference.short_title, conference.campaigns.first) - expect(current_path).to eq(root_path) - - visit admin_conference_targets_path(conference.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_target_path(conference.short_title) - expect(current_path).to eq(root_path) - - create(:target, conference: conference) - visit edit_admin_conference_target_path(conference.short_title, conference.targets.first) - expect(current_path).to eq(root_path) - - visit admin_conference_roles_path(conference.short_title) - expect(current_path).to eq(admin_conference_roles_path(conference.short_title)) - - visit admin_conference_resources_path(conference.short_title) - expect(current_path).to eq(admin_conference_resources_path(conference.short_title)) - - visit new_admin_conference_resource_path(conference.short_title) - expect(current_path).to eq(new_admin_conference_resource_path(conference.short_title)) - - create(:resource, conference: conference) - visit edit_admin_conference_resource_path(conference.short_title, conference.resources.first) - expect(current_path).to eq(edit_admin_conference_resource_path(conference.short_title, conference.resources.first)) - - visit admin_revision_history_path - expect(current_path).to eq(root_path) - end - end - - context 'when user is cfp' do - before do - sign_in user_cfp - @conference = conference2 - end - scenario 'has correct abilities' do - visit admin_conference_path(conference2.short_title) - expect(current_path).to eq(admin_conference_path(conference2.short_title)) - - expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') - expect(page).to_not have_link('Basics', href: "/admin/conferences/#{conference2.short_title}/edit") - expect(page).to have_text('Basics') - expect(page).to_not have_link('Contact', href: "/admin/conferences/#{conference2.short_title}/contact/edit") - expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference2.short_title}/commercials") - expect(page).to_not have_link('Splashpage', href: "/admin/conferences/#{conference2.short_title}/splashpage") - expect(page).to have_link('Venue', href: "/admin/conferences/#{conference2.short_title}/venue") - expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference2.short_title}/venue/rooms") - expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference2.short_title}/lodgings") - expect(page).to have_link('Program', href: "/admin/conferences/#{conference2.short_title}/program") - expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference2.short_title}/program/cfps") - expect(page).to have_link('Events', href: "/admin/conferences/#{conference2.short_title}/program/events") - expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference2.short_title}/program/tracks") - expect(page).to have_link('Event Types', href: "/admin/conferences/#{conference2.short_title}/program/event_types") - expect(page).to have_link('Difficulty Levels', href: "/admin/conferences/#{conference2.short_title}/program/difficulty_levels") - expect(page).to have_link('Schedules', href: "/admin/conferences/#{conference2.short_title}/schedules") - expect(page).to have_link('Reports', href: "/admin/conferences/#{conference2.short_title}/program/reports") - expect(page).to_not have_link('Registrations', href: "/admin/conferences/#{conference2.short_title}/registrations") - expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference2.short_title}/registration_period") - expect(page).to_not have_link('Questions', href: "/admin/conferences/#{conference2.short_title}/questions") - expect(page).to_not have_text('Donations') - expect(page).to_not have_link('Sponsorship Levels', href: "/admin/conferences/#{conference2.short_title}/supporter_levels") - expect(page).to_not have_link('Sponsors', href: "/admin/conferences/#{conference2.short_title}/sponsors") - expect(page).to_not have_link('Tickets', href: "/admin/conferences/#{conference2.short_title}/tickets") - expect(page).to_not have_text('Objectives') - expect(page).to_not have_link('Campaigns', href: "/admin/conferences/#{conference2.short_title}/campaigns") - expect(page).to_not have_link('Goals', href: "/admin/conferences/#{conference2.short_title}/targets") - expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference2.short_title}/emails") - expect(page).to have_link('Roles', href: "/admin/conferences/#{conference2.short_title}/roles") - expect(page).to have_link('Resources', href: "/admin/conferences/#{conference2.short_title}/resources") - - visit admin_conference_venue_rooms_path(conference2.short_title) - expect(current_path).to eq(admin_conference_venue_rooms_path(conference2.short_title)) - create(:room, venue: conference2.venue) - visit edit_admin_conference_venue_room_path(conference2.short_title, conference2.venue.rooms.first) - expect(current_path).to eq(edit_admin_conference_venue_room_path(conference2.short_title, conference2.venue.rooms.first)) - - visit new_admin_conference_program_path(conference2.short_title) - expect(current_path).to eq(new_admin_conference_program_path(conference2.short_title)) - - visit edit_admin_conference_program_path(conference2.short_title) - expect(current_path).to eq(edit_admin_conference_program_path(conference2.short_title)) - - visit new_admin_conference_program_cfp_path(conference2.short_title) - expect(current_path).to eq root_path - - conference2.program.cfp.destroy! - visit new_admin_conference_program_cfp_path(conference2.short_title) - expect(current_path).to eq new_admin_conference_program_cfp_path(conference2.short_title) - create(:cfp, program: conference2.program) - - visit edit_admin_conference_program_cfp_path(conference2.short_title, conference2.program.cfp) - expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference2.short_title, conference2.program.cfp)) - - create(:event, program: conference2.program) - visit edit_admin_conference_program_event_path(conference2.short_title, conference2.program.events.first) - expect(current_path).to eq(edit_admin_conference_program_event_path(conference2.short_title, conference2.program.events.first)) - - visit admin_conference_program_event_types_path(conference2.short_title) - expect(current_path).to eq(admin_conference_program_event_types_path(conference2.short_title)) - - visit new_admin_conference_program_event_type_path(conference2.short_title) - expect(current_path).to eq(new_admin_conference_program_event_type_path(conference2.short_title)) - - visit edit_admin_conference_program_event_type_path(conference2.short_title, conference2.program.event_types.first) - expect(current_path).to eq(edit_admin_conference_program_event_type_path(conference2.short_title, conference2.program.event_types.first)) - - visit admin_conference_program_difficulty_levels_path(conference2.short_title) - expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference2.short_title)) - - visit new_admin_conference_program_difficulty_level_path(conference2.short_title) - expect(current_path).to eq(new_admin_conference_program_difficulty_level_path(conference2.short_title)) - - visit edit_admin_conference_program_difficulty_level_path(conference2.short_title, conference2.program.difficulty_levels.first) - expect(current_path).to eq(edit_admin_conference_program_difficulty_level_path(conference2.short_title, conference2.program.difficulty_levels.first)) - - visit admin_conference_schedules_path(conference2.short_title) - expect(current_path).to eq(admin_conference_schedules_path(conference2.short_title)) - - create(:schedule, program: conference2.program) - visit admin_conference_schedule_path(conference2.short_title, conference2.program.schedules.first) - expect(current_path).to eq(admin_conference_schedule_path(conference2.short_title, conference2.program.schedules.first)) - - visit admin_conference_program_reports_path(conference2.short_title) - expect(current_path).to eq(admin_conference_program_reports_path(conference2.short_title)) - - visit admin_conference_registrations_path(conference2.short_title) - expect(current_path).to eq(admin_conference_registrations_path(conference2.short_title)) - - create(:registration, user: create(:user), conference: conference2) - visit edit_admin_conference_registration_path(conference2.short_title, conference2.registrations.first) - expect(current_path).to eq(root_path) - - visit new_admin_conference_registration_period_path(conference2.short_title) - expect(current_path).to eq(root_path) - - create(:registration_period, conference: conference2) - visit edit_admin_conference_registration_period_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_questions_path(conference2.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_program_tracks_path(conference2.short_title) - expect(current_path).to eq(admin_conference_program_tracks_path(conference2.short_title)) - - visit admin_conference_roles_path(conference2.short_title) - expect(current_path).to eq(admin_conference_roles_path(conference2.short_title)) - - visit admin_conference_emails_path(conference2.short_title) - expect(current_path).to eq(admin_conference_emails_path(conference2.short_title)) - end - - it_behaves_like 'correct abilities for cfps and info_desk', 'cfp' - end - - context 'when user is info desk' do - before do - sign_in user_info_desk - end - - scenario 'has correct abilities' do - visit admin_conference_path(conference3.short_title) - expect(current_path).to eq(admin_conference_path(conference3.short_title)) - - expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') - expect(page).to_not have_link('Venue', href: "/admin/conferences/#{conference3.short_title}/venue") - expect(page).to_not have_link('Rooms', href: "/admin/conferences/#{conference3.short_title}/venue/rooms") - expect(page).to_not have_link('Program', href: "/admin/conferences/#{conference3.short_title}/program") - expect(page).to_not have_link('Call for Papers', href: "/admin/conferences/#{conference2.short_title}/program/cfps") - expect(page).to_not have_link('Events', href: "/admin/conferences/#{conference3.short_title}/program/events") - expect(page).to_not have_link('Tracks', href: "/admin/conferences/#{conference3.short_title}/program/tracks") - expect(page).to_not have_link('Event Types', href: "/admin/conferences/#{conference3.short_title}/program/event_types") - expect(page).to_not have_link('Difficulty Levels', href: "/admin/conferences/#{conference3.short_title}/program/difficulty_levels") - expect(page).to_not have_link('Schedules', href: "/admin/conferences/#{conference3.short_title}/schedules") - expect(page).to_not have_link('Reports', href: "/admin/conferences/#{conference3.short_title}/program/reports") - expect(page).to have_link('Registrations', href: "/admin/conferences/#{conference3.short_title}/registrations") - expect(page).to have_link('Questions', href: "/admin/conferences/#{conference3.short_title}/questions") - expect(page).to_not have_link('E-Mails', href: "/admin/conferences/#{conference3.short_title}/emails") - - visit admin_conference_venue_rooms_path(conference3.short_title) - expect(current_path).to eq(root_path) - - create(:room, venue: conference3.venue) - visit edit_admin_conference_venue_room_path(conference3.short_title, conference3.venue.rooms.first) - expect(current_path).to eq(root_path) - - visit new_admin_conference_program_path(conference3.short_title) - expect(current_path).to eq(root_path) - - visit edit_admin_conference_program_path(conference3.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_program_cfp_path(conference3.short_title) - expect(current_path).to eq root_path - - conference1.program.cfp.destroy! - visit new_admin_conference_program_cfp_path(conference3.short_title) - expect(current_path).to eq root_path - create(:cfp, program: conference1.program) - - visit edit_admin_conference_program_cfp_path(conference3.short_title, conference3.program.cfp) - expect(current_path).to eq(root_path) - - visit admin_conference_program_events_path(conference3.short_title) - expect(current_path).to eq(root_path) - - create(:event, program: conference3.program) - visit edit_admin_conference_program_event_path(conference3.short_title, conference3.program.events.first) - expect(current_path).to eq(root_path) - - visit admin_conference_program_event_types_path(conference3.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_program_event_type_path(conference3.short_title) - expect(current_path).to eq(root_path) - - visit edit_admin_conference_program_event_type_path(conference3.short_title, conference3.program.event_types.first) - expect(current_path).to eq(root_path) - - visit admin_conference_program_difficulty_levels_path(conference3.short_title) - expect(current_path).to eq(root_path) - - visit new_admin_conference_program_difficulty_level_path(conference3.short_title) - expect(current_path).to eq(root_path) - - visit edit_admin_conference_program_difficulty_level_path(conference3.short_title, conference3.program.difficulty_levels.first) - expect(current_path).to eq(root_path) - - visit admin_conference_schedules_path(conference3.short_title) - expect(current_path).to eq(root_path) - - create(:schedule, program: conference3.program) - visit admin_conference_schedule_path(conference3.short_title, conference3.program.schedules.first) - expect(current_path).to eq(root_path) - - visit admin_conference_program_reports_path(conference3.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_registrations_path(conference3.short_title) - expect(current_path).to eq(admin_conference_registrations_path(conference3.short_title)) - - create(:registration, user: create(:user), conference: conference3) - visit edit_admin_conference_registration_path(conference3.short_title, conference3.registrations.first) - expect(current_path).to eq(edit_admin_conference_registration_path(conference3.short_title, conference3.registrations.first)) - - visit admin_conference_questions_path(conference3.short_title) - expect(current_path).to eq(admin_conference_questions_path(conference3.short_title)) - - visit admin_conference_program_tracks_path(conference3.short_title) - expect(current_path).to eq(root_path) - - visit admin_conference_emails_path(conference3.short_title) - expect(current_path).to eq(root_path) - end - - it_behaves_like 'correct abilities for cfps and info_desk', 'info_desk' - end -end diff --git a/spec/features/cfp_ability_spec.rb b/spec/features/cfp_ability_spec.rb new file mode 100644 index 00000000..52725527 --- /dev/null +++ b/spec/features/cfp_ability_spec.rb @@ -0,0 +1,250 @@ +require 'spec_helper' + +feature 'Has correct abilities' do + + let(:organization) { create(:organization) } + # It is necessary to use bang version of let to build roles before user + let(:conference) { create(:full_conference, organization: organization) } # user is cfp + let(:role_cfp) { Role.find_by(name: 'cfp', resource: conference) } + let(:user_cfp) { create(:user, role_ids: [role_cfp.id]) } + + context 'when user is cfp' do + before do + sign_in user_cfp + end + + scenario 'for organization and conference attributes' do + visit admin_conference_path(conference.short_title) + expect(current_path).to eq(admin_conference_path(conference.short_title)) + + expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') + expect(page).to_not have_link('Basics', href: "/admin/conferences/#{conference.short_title}/edit") + expect(page).to have_text('Basics') + expect(page).to_not have_link('Contact', href: "/admin/conferences/#{conference.short_title}/contact/edit") + expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference.short_title}/commercials") + expect(page).to_not have_link('Splashpage', href: "/admin/conferences/#{conference.short_title}/splashpage") + expect(page).to have_link('Venue', href: "/admin/conferences/#{conference.short_title}/venue") + expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference.short_title}/venue/rooms") + expect(page).to have_link('Program', href: "/admin/conferences/#{conference.short_title}/program") + expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference.short_title}/program/cfps") + 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('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") + expect(page).to_not have_link('Registrations', href: "/admin/conferences/#{conference.short_title}/registrations") + expect(page).to_not have_link('Questions', href: "/admin/conferences/#{conference.short_title}/questions") + expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference.short_title}/emails") + expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference.short_title}/lodgings") + expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period") + expect(page).to_not have_text('Donations') + expect(page).to_not have_link('Sponsorship Levels', href: "/admin/conferences/#{conference.short_title}/sponsorship_levels") + expect(page).to_not have_link('Sponsors', href: "/admin/conferences/#{conference.short_title}/sponsors") + expect(page).to_not have_link('Tickets', href: "/admin/conferences/#{conference.short_title}/tickets") + expect(page).to_not have_text('Objectives') + expect(page).to_not have_link('Campaigns', href: "/admin/conferences/#{conference.short_title}/campaigns") + expect(page).to_not have_link('Goals', href: "/admin/conferences/#{conference.short_title}/targets") + expect(page).to have_link('Roles', href: "/admin/conferences/#{conference.short_title}/roles") + expect(page).to have_link('Resources', href: "/admin/conferences/#{conference.short_title}/resources") + + visit admin_conference_venue_rooms_path(conference.short_title) + expect(current_path).to eq(admin_conference_venue_rooms_path(conference.short_title)) + create(:room, venue: conference.venue) + visit edit_admin_conference_venue_room_path(conference.short_title, conference.venue.rooms.first) + expect(current_path).to eq(edit_admin_conference_venue_room_path(conference.short_title, conference.venue.rooms.first)) + + visit new_admin_conference_program_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_path(conference.short_title)) + + visit edit_admin_conference_program_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_program_path(conference.short_title)) + + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq root_path + + conference.program.cfp.destroy! + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) + create(:cfp, program: conference.program) + + visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + + create(:event, program: conference.program) + visit edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first) + expect(current_path).to eq(edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first)) + + visit admin_conference_program_event_types_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_event_types_path(conference.short_title)) + + visit new_admin_conference_program_event_type_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_event_type_path(conference.short_title)) + + 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_difficulty_levels_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference.short_title)) + + visit new_admin_conference_program_difficulty_level_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_difficulty_level_path(conference.short_title)) + + visit edit_admin_conference_program_difficulty_level_path(conference.short_title, conference.program.difficulty_levels.first) + expect(current_path).to eq(edit_admin_conference_program_difficulty_level_path(conference.short_title, conference.program.difficulty_levels.first)) + + visit admin_conference_schedules_path(conference.short_title) + expect(current_path).to eq(admin_conference_schedules_path(conference.short_title)) + + create(:schedule, program: conference.program) + visit admin_conference_schedule_path(conference.short_title, conference.program.schedules.first) + expect(current_path).to eq(admin_conference_schedule_path(conference.short_title, conference.program.schedules.first)) + + visit admin_conference_program_reports_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_reports_path(conference.short_title)) + + visit admin_conference_registrations_path(conference.short_title) + expect(current_path).to eq(admin_conference_registrations_path(conference.short_title)) + + create(:registration, user: create(:user), conference: conference) + visit edit_admin_conference_registration_path(conference.short_title, conference.registrations.first) + expect(current_path).to eq(root_path) + + visit new_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:registration_period, conference: conference) + visit edit_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_questions_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_program_tracks_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_tracks_path(conference.short_title)) + + visit admin_conference_roles_path(conference.short_title) + expect(current_path).to eq(admin_conference_roles_path(conference.short_title)) + + visit admin_conference_emails_path(conference.short_title) + expect(current_path).to eq(admin_conference_emails_path(conference.short_title)) + + visit admin_conference_path(conference.short_title) + expect(current_path).to eq(admin_conference_path(conference.short_title)) + + visit admin_organizations_path + expect(current_path).to eq(admin_organizations_path) + + visit edit_admin_organization_path(organization) + expect(current_path).to eq(root_path) + + visit new_admin_organization_path + expect(current_path).to eq(root_path) + + visit edit_admin_conference_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_contact_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_commercials_path(conference.short_title) + expect(current_path).to eq(admin_conference_commercials_path(conference.short_title)) + + visit new_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq(root_path) + + conference.venue = create(:venue) + visit edit_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_lodgings_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_lodging_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:lodging, conference: conference) + visit edit_admin_conference_lodging_path(conference.short_title, conference.lodgings.first) + expect(current_path).to eq(root_path) + + visit new_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:registration_period, conference: conference) + visit edit_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_sponsorship_levels_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_sponsorship_level_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:sponsorship_level, conference: conference) + visit edit_admin_conference_sponsorship_level_path(conference.short_title, conference.sponsorship_levels.first) + expect(current_path).to eq(root_path) + + visit admin_conference_sponsors_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_sponsor_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:sponsor, conference: conference, sponsorship_level: conference.sponsorship_levels.first) + visit edit_admin_conference_sponsor_path(conference.short_title, conference.sponsors.first) + expect(current_path).to eq(root_path) + + visit admin_conference_tickets_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_ticket_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:ticket, conference: conference) + visit edit_admin_conference_ticket_path(conference.short_title, conference.tickets.first) + expect(current_path).to eq(root_path) + + visit admin_conference_campaigns_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_campaign_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:campaign, conference: conference) + visit edit_admin_conference_campaign_path(conference.short_title, conference.campaigns.first) + expect(current_path).to eq(root_path) + + visit admin_conference_targets_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_target_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:target, conference: conference) + visit edit_admin_conference_target_path(conference.short_title, conference.targets.first) + expect(current_path).to eq(root_path) + + visit admin_conference_roles_path(conference.short_title) + expect(current_path).to eq(admin_conference_roles_path(conference.short_title)) + + visit admin_conference_resources_path(conference.short_title) + expect(current_path).to eq(admin_conference_resources_path(conference.short_title)) + + visit new_admin_conference_resource_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_resource_path(conference.short_title)) + + create(:resource, conference: conference) + visit edit_admin_conference_resource_path(conference.short_title, conference.resources.first) + expect(current_path).to eq(edit_admin_conference_resource_path(conference.short_title, conference.resources.first)) + + visit admin_revision_history_path + expect(current_path).to eq(root_path) + end + end +end diff --git a/spec/features/info_desk_ability_spec.rb b/spec/features/info_desk_ability_spec.rb new file mode 100644 index 00000000..d7b0b909 --- /dev/null +++ b/spec/features/info_desk_ability_spec.rb @@ -0,0 +1,246 @@ +require 'spec_helper' + +feature 'Has correct abilities' do + + let(:organization) { create(:organization) } + # It is necessary to use bang version of let to build roles before user + let(:conference) { create(:full_conference, organization: organization) } # user is info_desk + + let(:role_info_desk) { Role.find_by(name: 'info_desk', resource: conference) } + + let(:user_info_desk) { create(:user, role_ids: [role_info_desk.id]) } + + context 'when user is info desk' do + before do + sign_in user_info_desk + end + + scenario 'for organization and conference attributes' do + visit admin_conference_path(conference.short_title) + expect(current_path).to eq(admin_conference_path(conference.short_title)) + + expect(page).to_not have_link('Basics', href: "/admin/conferences/#{conference.short_title}/edit") + expect(page).to have_text('Basics') + expect(page).to_not have_link('Contact', href: "/admin/conferences/#{conference.short_title}/contact/edit") + expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference.short_title}/commercials") + expect(page).to_not have_link('Splashpage', href: "/admin/conferences/#{conference.short_title}/splashpage") + expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference.short_title}/lodgings") + expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period") + expect(page).to_not have_text('Donations') + expect(page).to_not have_link('Sponsorship Levels', href: "/admin/conferences/#{conference.short_title}/sponsorship_levels") + expect(page).to_not have_link('Sponsors', href: "/admin/conferences/#{conference.short_title}/sponsors") + expect(page).to_not have_link('Tickets', href: "/admin/conferences/#{conference.short_title}/tickets") + expect(page).to_not have_text('Objectives') + expect(page).to_not have_link('Campaigns', href: "/admin/conferences/#{conference.short_title}/campaigns") + expect(page).to_not have_link('Goals', href: "/admin/conferences/#{conference.short_title}/targets") + expect(page).to have_link('Roles', href: "/admin/conferences/#{conference.short_title}/roles") + expect(page).to have_link('Resources', href: "/admin/conferences/#{conference.short_title}/resources") + expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') + expect(page).to_not have_link('Venue', href: "/admin/conferences/#{conference.short_title}/venue") + expect(page).to_not have_link('Rooms', href: "/admin/conferences/#{conference.short_title}/venue/rooms") + expect(page).to_not have_link('Program', href: "/admin/conferences/#{conference.short_title}/program") + expect(page).to_not have_link('Call for Papers', href: "/admin/conferences/#{conference.short_title}/program/cfps") + expect(page).to_not have_link('Events', href: "/admin/conferences/#{conference.short_title}/program/events") + expect(page).to_not have_link('Tracks', href: "/admin/conferences/#{conference.short_title}/program/tracks") + expect(page).to_not have_link('Event Types', href: "/admin/conferences/#{conference.short_title}/program/event_types") + expect(page).to_not have_link('Difficulty Levels', href: "/admin/conferences/#{conference.short_title}/program/difficulty_levels") + expect(page).to_not have_link('Schedules', href: "/admin/conferences/#{conference.short_title}/schedules") + expect(page).to_not have_link('Reports', href: "/admin/conferences/#{conference.short_title}/program/reports") + expect(page).to have_link('Registrations', href: "/admin/conferences/#{conference.short_title}/registrations") + expect(page).to have_link('Questions', href: "/admin/conferences/#{conference.short_title}/questions") + expect(page).to_not have_link('E-Mails', href: "/admin/conferences/#{conference.short_title}/emails") + + visit admin_organizations_path + expect(current_path).to eq(admin_organizations_path) + + visit edit_admin_organization_path(organization) + expect(current_path).to eq(root_path) + + visit new_admin_organization_path + expect(current_path).to eq(root_path) + + visit edit_admin_conference_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_contact_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_commercials_path(conference.short_title) + expect(current_path).to eq(admin_conference_commercials_path(conference.short_title)) + + visit new_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq(root_path) + + conference.venue = create(:venue) + visit edit_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_lodgings_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_lodging_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:lodging, conference: conference) + visit edit_admin_conference_lodging_path(conference.short_title, conference.lodgings.first) + expect(current_path).to eq(root_path) + + visit new_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:registration_period, conference: conference) + visit edit_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_sponsorship_levels_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_sponsorship_level_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:sponsorship_level, conference: conference) + visit edit_admin_conference_sponsorship_level_path(conference.short_title, conference.sponsorship_levels.first) + expect(current_path).to eq(root_path) + + visit admin_conference_sponsors_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_sponsor_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:sponsor, conference: conference, sponsorship_level: conference.sponsorship_levels.first) + visit edit_admin_conference_sponsor_path(conference.short_title, conference.sponsors.first) + expect(current_path).to eq(root_path) + + visit admin_conference_tickets_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_ticket_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:ticket, conference: conference) + visit edit_admin_conference_ticket_path(conference.short_title, conference.tickets.first) + expect(current_path).to eq(root_path) + + visit admin_conference_campaigns_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_campaign_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:campaign, conference: conference) + visit edit_admin_conference_campaign_path(conference.short_title, conference.campaigns.first) + expect(current_path).to eq(root_path) + + visit admin_conference_targets_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_target_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:target, conference: conference) + visit edit_admin_conference_target_path(conference.short_title, conference.targets.first) + expect(current_path).to eq(root_path) + + visit admin_conference_roles_path(conference.short_title) + expect(current_path).to eq(admin_conference_roles_path(conference.short_title)) + + visit admin_conference_resources_path(conference.short_title) + expect(current_path).to eq(admin_conference_resources_path(conference.short_title)) + + visit new_admin_conference_resource_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_resource_path(conference.short_title)) + + create(:resource, conference: conference) + visit edit_admin_conference_resource_path(conference.short_title, conference.resources.first) + expect(current_path).to eq(edit_admin_conference_resource_path(conference.short_title, conference.resources.first)) + + visit admin_revision_history_path + expect(current_path).to eq(root_path) + + visit admin_conference_path(conference.short_title) + expect(current_path).to eq(admin_conference_path(conference.short_title)) + + visit admin_conference_venue_rooms_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:room, venue: conference.venue) + visit edit_admin_conference_venue_room_path(conference.short_title, conference.venue.rooms.first) + expect(current_path).to eq(root_path) + + visit new_admin_conference_program_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_program_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq root_path + + conference.program.cfp.destroy! + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq root_path + create(:cfp, program: conference.program) + + visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) + expect(current_path).to eq(root_path) + + visit admin_conference_program_events_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:event, program: conference.program) + visit edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first) + expect(current_path).to eq(root_path) + + visit admin_conference_program_event_types_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_program_event_type_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_program_event_type_path(conference.short_title, conference.program.event_types.first) + expect(current_path).to eq(root_path) + + visit admin_conference_program_difficulty_levels_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit new_admin_conference_program_difficulty_level_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit edit_admin_conference_program_difficulty_level_path(conference.short_title, conference.program.difficulty_levels.first) + expect(current_path).to eq(root_path) + + visit admin_conference_schedules_path(conference.short_title) + expect(current_path).to eq(root_path) + + create(:schedule, program: conference.program) + visit admin_conference_schedule_path(conference.short_title, conference.program.schedules.first) + expect(current_path).to eq(root_path) + + visit admin_conference_program_reports_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_registrations_path(conference.short_title) + expect(current_path).to eq(admin_conference_registrations_path(conference.short_title)) + + create(:registration, user: create(:user), conference: conference) + visit edit_admin_conference_registration_path(conference.short_title, conference.registrations.first) + expect(current_path).to eq(edit_admin_conference_registration_path(conference.short_title, conference.registrations.first)) + + visit admin_conference_questions_path(conference.short_title) + expect(current_path).to eq(admin_conference_questions_path(conference.short_title)) + + visit admin_conference_program_tracks_path(conference.short_title) + expect(current_path).to eq(root_path) + + visit admin_conference_emails_path(conference.short_title) + expect(current_path).to eq(root_path) + end + end +end diff --git a/spec/features/organization_admin_ability_spec.rb b/spec/features/organization_admin_ability_spec.rb new file mode 100644 index 00000000..5a247dd8 --- /dev/null +++ b/spec/features/organization_admin_ability_spec.rb @@ -0,0 +1,240 @@ +require 'spec_helper' + +feature 'Has correct abilities' do + let(:organization) { create(:organization) } + let(:conference) { create(:full_conference, organization: organization) } # user is organization_admin + let(:role_organization_admin) { Role.find_by(name: 'organization_admin', resource: organization) } + let(:user_organization_admin) { create(:user, role_ids: [role_organization_admin.id]) } + + context 'when user is organization_admin' do + before do + sign_in user_organization_admin + end + + scenario 'for organization attributes' do + visit admin_organizations_path + expect(current_path).to eq(admin_organizations_path) + + visit edit_admin_organization_path(organization) + expect(current_path).to eq(edit_admin_organization_path(organization)) + + visit new_admin_organization_path + expect(current_path).to eq(root_path) + end + + scenario 'for conference attributes' do + visit admin_conference_path(conference.short_title) + expect(current_path).to eq(admin_conference_path(conference.short_title)) + + expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') + expect(page).to have_link('Basics', href: "/admin/conferences/#{conference.short_title}/edit") + expect(page).to have_link('Contact', href: "/admin/conferences/#{conference.short_title}/contact/edit") + expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference.short_title}/commercials") + expect(page).to have_link('Splashpage', href: "/admin/conferences/#{conference.short_title}/splashpage") + expect(page).to have_link('Venue', href: "/admin/conferences/#{conference.short_title}/venue") + expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference.short_title}/venue/rooms") + expect(page).to have_link('Lodgings', href: "/admin/conferences/#{conference.short_title}/lodgings") + expect(page).to have_link('Program', href: "/admin/conferences/#{conference.short_title}/program") + expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference.short_title}/program/cfps") + 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('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") + expect(page).to have_link('Registrations', href: "/admin/conferences/#{conference.short_title}/registrations") + expect(page).to have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period") + expect(page).to have_link('Questions', href: "/admin/conferences/#{conference.short_title}/questions") + expect(page).to have_text('Donations') + expect(page).to have_link('Sponsorship Levels', href: "/admin/conferences/#{conference.short_title}/sponsorship_levels") + expect(page).to have_link('Sponsors', href: "/admin/conferences/#{conference.short_title}/sponsors") + expect(page).to have_link('Tickets', href: "/admin/conferences/#{conference.short_title}/tickets") + expect(page).to have_text('Objectives') + expect(page).to have_link('Campaigns', href: "/admin/conferences/#{conference.short_title}/campaigns") + expect(page).to have_link('Goals', href: "/admin/conferences/#{conference.short_title}/targets") + expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference.short_title}/emails") + expect(page).to have_link('Roles', href: "/admin/conferences/#{conference.short_title}/roles") + expect(page).to have_link('Resources', href: "/admin/conferences/#{conference.short_title}/resources") + + visit edit_admin_conference_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_path(conference.short_title)) + + visit edit_admin_conference_contact_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_contact_path(conference.short_title)) + + visit admin_conference_commercials_path(conference.short_title) + expect(current_path).to eq(admin_conference_commercials_path(conference.short_title)) + + visit new_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_splashpage_path(conference.short_title)) + + visit edit_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_splashpage_path(conference.short_title)) + + visit new_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_venue_path(conference.short_title)) + + conference.venue = create(:venue) + visit edit_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_venue_path(conference.short_title)) + + visit admin_conference_venue_rooms_path(conference.short_title) + expect(current_path).to eq(admin_conference_venue_rooms_path(conference.short_title)) + + create(:room, venue: conference.venue) + visit edit_admin_conference_venue_room_path(conference.short_title, conference.venue.rooms.first) + expect(current_path).to eq(edit_admin_conference_venue_room_path(conference.short_title, conference.venue.rooms.first)) + + visit admin_conference_lodgings_path(conference.short_title) + expect(current_path).to eq(admin_conference_lodgings_path(conference.short_title)) + + visit new_admin_conference_lodging_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_lodging_path(conference.short_title)) + + create(:lodging, conference: conference) + visit edit_admin_conference_lodging_path(conference.short_title, conference.lodgings.first) + expect(current_path).to eq(edit_admin_conference_lodging_path(conference.short_title, conference.lodgings.first)) + + visit new_admin_conference_program_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_path(conference.short_title)) + + visit edit_admin_conference_program_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_program_path(conference.short_title)) + + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq root_path + + conference.program.cfp.destroy! + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) + create(:cfp, program: conference.program) + + visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + + visit admin_conference_program_events_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_events_path(conference.short_title)) + + create(:event, program: conference.program) + visit edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first) + expect(current_path).to eq(edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first)) + + visit admin_conference_program_event_types_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_event_types_path(conference.short_title)) + + visit new_admin_conference_program_event_type_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_event_type_path(conference.short_title)) + + 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_difficulty_levels_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference.short_title)) + + visit new_admin_conference_program_difficulty_level_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_difficulty_level_path(conference.short_title)) + + visit edit_admin_conference_program_difficulty_level_path(conference.short_title, conference.program.difficulty_levels.first) + expect(current_path).to eq(edit_admin_conference_program_difficulty_level_path(conference.short_title, conference.program.difficulty_levels.first)) + + visit admin_conference_schedules_path(conference.short_title) + expect(current_path).to eq(admin_conference_schedules_path(conference.short_title)) + + create(:schedule, program: conference.program) + visit admin_conference_schedule_path(conference.short_title, conference.program.schedules.first) + expect(current_path).to eq(admin_conference_schedule_path(conference.short_title, conference.program.schedules.first)) + + visit admin_conference_program_reports_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_reports_path(conference.short_title)) + + visit admin_conference_registrations_path(conference.short_title) + expect(current_path).to eq(admin_conference_registrations_path(conference.short_title)) + + create(:registration, user: create(:user), conference: conference) + visit edit_admin_conference_registration_path(conference.short_title, conference.registrations.first) + expect(current_path).to eq(edit_admin_conference_registration_path(conference.short_title, conference.registrations.first)) + + visit new_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_registration_period_path(conference.short_title)) + + create(:registration_period, conference: conference) + visit edit_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_registration_period_path(conference.short_title)) + + visit admin_conference_questions_path(conference.short_title) + expect(current_path).to eq(admin_conference_questions_path(conference.short_title)) + + visit admin_conference_sponsorship_levels_path(conference.short_title) + expect(current_path).to eq(admin_conference_sponsorship_levels_path(conference.short_title)) + + visit new_admin_conference_sponsorship_level_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_sponsorship_level_path(conference.short_title)) + + create(:sponsorship_level, conference: conference) + visit edit_admin_conference_sponsorship_level_path(conference.short_title, conference.sponsorship_levels.first) + expect(current_path).to eq(edit_admin_conference_sponsorship_level_path(conference.short_title, conference.sponsorship_levels.first)) + + visit admin_conference_sponsors_path(conference.short_title) + expect(current_path).to eq(admin_conference_sponsors_path(conference.short_title)) + + visit new_admin_conference_sponsor_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_sponsor_path(conference.short_title)) + + create(:sponsor, conference: conference, sponsorship_level: conference.sponsorship_levels.first) + visit edit_admin_conference_sponsor_path(conference.short_title, conference.sponsors.first) + expect(current_path).to eq(edit_admin_conference_sponsor_path(conference.short_title, conference.sponsors.first)) + + visit admin_conference_tickets_path(conference.short_title) + expect(current_path).to eq(admin_conference_tickets_path(conference.short_title)) + + visit new_admin_conference_ticket_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_ticket_path(conference.short_title)) + + create(:ticket, conference: conference) + visit edit_admin_conference_ticket_path(conference.short_title, conference.tickets.first) + expect(current_path).to eq(edit_admin_conference_ticket_path(conference.short_title, conference.tickets.first)) + + visit admin_conference_campaigns_path(conference.short_title) + expect(current_path).to eq(admin_conference_campaigns_path(conference.short_title)) + + visit new_admin_conference_campaign_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_campaign_path(conference.short_title)) + + create(:campaign, conference: conference) + visit edit_admin_conference_campaign_path(conference.short_title, conference.campaigns.first) + expect(current_path).to eq(edit_admin_conference_campaign_path(conference.short_title, conference.campaigns.first)) + + visit admin_conference_targets_path(conference.short_title) + expect(current_path).to eq(admin_conference_targets_path(conference.short_title)) + + visit new_admin_conference_target_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_target_path(conference.short_title)) + + create(:target, conference: conference) + visit edit_admin_conference_target_path(conference.short_title, conference.targets.first) + expect(current_path).to eq(edit_admin_conference_target_path(conference.short_title, conference.targets.first)) + + visit admin_conference_program_tracks_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_tracks_path(conference.short_title)) + + visit admin_conference_roles_path(conference.short_title) + expect(current_path).to eq(admin_conference_roles_path(conference.short_title)) + + visit admin_conference_emails_path(conference.short_title) + expect(current_path).to eq(admin_conference_emails_path(conference.short_title)) + + visit admin_conference_resources_path(conference.short_title) + expect(current_path).to eq(admin_conference_resources_path(conference.short_title)) + + visit new_admin_conference_resource_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_resource_path(conference.short_title)) + + create(:resource, conference: conference) + visit edit_admin_conference_resource_path(conference.short_title, conference.resources.first) + expect(current_path).to eq(edit_admin_conference_resource_path(conference.short_title, conference.resources.first)) + + visit admin_revision_history_path + expect(current_path).to eq(admin_revision_history_path) + end + end +end diff --git a/spec/features/organizer_ability_spec.rb b/spec/features/organizer_ability_spec.rb new file mode 100644 index 00000000..9604fad6 --- /dev/null +++ b/spec/features/organizer_ability_spec.rb @@ -0,0 +1,247 @@ +require 'spec_helper' + +feature 'Has correct abilities' do + + let(:organization) { create(:organization) } + # It is necessary to use bang version of let to build roles before user + let(:conference) { create(:full_conference, organization: organization) } # user is organizer + let(:other_conference) { create(:conference, organization: organization) } # user is organizer, venue is not set by default + let(:role_organizer_conf) { Role.find_by(name: 'organizer', resource: conference) } + let(:role_organizer_other_conf) { Role.find_by(name: 'organizer', resource: other_conference) } + let(:user_organizer) { create(:user, role_ids: [role_organizer_conf.id, role_organizer_other_conf.id]) } + + context 'when user is organizer' do + before do + sign_in user_organizer + end + + scenario 'for organization attributes' do + visit admin_organizations_path + expect(current_path).to eq(admin_organizations_path) + + visit edit_admin_organization_path(organization) + expect(current_path).to eq(root_path) + + visit new_admin_organization_path + expect(current_path).to eq(root_path) + end + + scenario 'for conference attributes' do + visit admin_conference_path(conference.short_title) + expect(current_path).to eq(admin_conference_path(conference.short_title)) + + expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') + expect(page).to have_link('Basics', href: "/admin/conferences/#{conference.short_title}/edit") + expect(page).to have_link('Contact', href: "/admin/conferences/#{conference.short_title}/contact/edit") + expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference.short_title}/commercials") + expect(page).to have_link('Splashpage', href: "/admin/conferences/#{conference.short_title}/splashpage") + expect(page).to have_link('Venue', href: "/admin/conferences/#{conference.short_title}/venue") + expect(page).to have_link('Rooms', href: "/admin/conferences/#{conference.short_title}/venue/rooms") + expect(page).to have_link('Lodgings', href: "/admin/conferences/#{conference.short_title}/lodgings") + expect(page).to have_link('Program', href: "/admin/conferences/#{conference.short_title}/program") + expect(page).to have_link('Call for Papers', href: "/admin/conferences/#{conference.short_title}/program/cfps") + 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('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") + expect(page).to have_link('Registrations', href: "/admin/conferences/#{conference.short_title}/registrations") + expect(page).to have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period") + expect(page).to have_link('Questions', href: "/admin/conferences/#{conference.short_title}/questions") + expect(page).to have_text('Donations') + expect(page).to have_link('Sponsorship Levels', href: "/admin/conferences/#{conference.short_title}/sponsorship_levels") + expect(page).to have_link('Sponsors', href: "/admin/conferences/#{conference.short_title}/sponsors") + expect(page).to have_link('Tickets', href: "/admin/conferences/#{conference.short_title}/tickets") + expect(page).to have_text('Objectives') + expect(page).to have_link('Campaigns', href: "/admin/conferences/#{conference.short_title}/campaigns") + expect(page).to have_link('Goals', href: "/admin/conferences/#{conference.short_title}/targets") + expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference.short_title}/emails") + expect(page).to have_link('Roles', href: "/admin/conferences/#{conference.short_title}/roles") + expect(page).to have_link('Resources', href: "/admin/conferences/#{conference.short_title}/resources") + + visit admin_conference_path(other_conference.short_title) + expect(page).to have_link('Add venue', href: "/admin/conferences/#{other_conference.short_title}/venue/new") + + visit edit_admin_conference_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_path(conference.short_title)) + + visit edit_admin_conference_contact_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_contact_path(conference.short_title)) + + visit admin_conference_commercials_path(conference.short_title) + expect(current_path).to eq(admin_conference_commercials_path(conference.short_title)) + + visit new_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_splashpage_path(conference.short_title)) + + visit edit_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_splashpage_path(conference.short_title)) + + visit new_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_venue_path(conference.short_title)) + + conference.venue = create(:venue) + visit edit_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_venue_path(conference.short_title)) + + visit admin_conference_venue_rooms_path(conference.short_title) + expect(current_path).to eq(admin_conference_venue_rooms_path(conference.short_title)) + + create(:room, venue: conference.venue) + visit edit_admin_conference_venue_room_path(conference.short_title, conference.venue.rooms.first) + expect(current_path).to eq(edit_admin_conference_venue_room_path(conference.short_title, conference.venue.rooms.first)) + + visit admin_conference_lodgings_path(conference.short_title) + expect(current_path).to eq(admin_conference_lodgings_path(conference.short_title)) + + visit new_admin_conference_lodging_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_lodging_path(conference.short_title)) + + create(:lodging, conference: conference) + visit edit_admin_conference_lodging_path(conference.short_title, conference.lodgings.first) + expect(current_path).to eq(edit_admin_conference_lodging_path(conference.short_title, conference.lodgings.first)) + + visit new_admin_conference_program_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_path(conference.short_title)) + + visit edit_admin_conference_program_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_program_path(conference.short_title)) + + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq root_path + + conference.program.cfp.destroy! + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) + create(:cfp, program: conference.program) + + visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + + visit admin_conference_program_events_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_events_path(conference.short_title)) + + create(:event, program: conference.program) + visit edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first) + expect(current_path).to eq(edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first)) + + visit admin_conference_program_event_types_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_event_types_path(conference.short_title)) + + visit new_admin_conference_program_event_type_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_event_type_path(conference.short_title)) + + 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_difficulty_levels_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_difficulty_levels_path(conference.short_title)) + + visit new_admin_conference_program_difficulty_level_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_difficulty_level_path(conference.short_title)) + + visit edit_admin_conference_program_difficulty_level_path(conference.short_title, conference.program.difficulty_levels.first) + expect(current_path).to eq(edit_admin_conference_program_difficulty_level_path(conference.short_title, conference.program.difficulty_levels.first)) + + visit admin_conference_schedules_path(conference.short_title) + expect(current_path).to eq(admin_conference_schedules_path(conference.short_title)) + + create(:schedule, program: conference.program) + visit admin_conference_schedule_path(conference.short_title, conference.program.schedules.first) + expect(current_path).to eq(admin_conference_schedule_path(conference.short_title, conference.program.schedules.first)) + + visit admin_conference_program_reports_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_reports_path(conference.short_title)) + + visit admin_conference_registrations_path(conference.short_title) + expect(current_path).to eq(admin_conference_registrations_path(conference.short_title)) + + create(:registration, user: create(:user), conference: conference) + visit edit_admin_conference_registration_path(conference.short_title, conference.registrations.first) + expect(current_path).to eq(edit_admin_conference_registration_path(conference.short_title, conference.registrations.first)) + + visit new_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_registration_period_path(conference.short_title)) + + create(:registration_period, conference: conference) + visit edit_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq(edit_admin_conference_registration_period_path(conference.short_title)) + + visit admin_conference_questions_path(conference.short_title) + expect(current_path).to eq(admin_conference_questions_path(conference.short_title)) + + visit admin_conference_sponsorship_levels_path(conference.short_title) + expect(current_path).to eq(admin_conference_sponsorship_levels_path(conference.short_title)) + + visit new_admin_conference_sponsorship_level_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_sponsorship_level_path(conference.short_title)) + + create(:sponsorship_level, conference: conference) + visit edit_admin_conference_sponsorship_level_path(conference.short_title, conference.sponsorship_levels.first) + expect(current_path).to eq(edit_admin_conference_sponsorship_level_path(conference.short_title, conference.sponsorship_levels.first)) + + visit admin_conference_sponsors_path(conference.short_title) + expect(current_path).to eq(admin_conference_sponsors_path(conference.short_title)) + + visit new_admin_conference_sponsor_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_sponsor_path(conference.short_title)) + + create(:sponsor, conference: conference, sponsorship_level: conference.sponsorship_levels.first) + visit edit_admin_conference_sponsor_path(conference.short_title, conference.sponsors.first) + expect(current_path).to eq(edit_admin_conference_sponsor_path(conference.short_title, conference.sponsors.first)) + + visit admin_conference_tickets_path(conference.short_title) + expect(current_path).to eq(admin_conference_tickets_path(conference.short_title)) + + visit new_admin_conference_ticket_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_ticket_path(conference.short_title)) + + create(:ticket, conference: conference) + visit edit_admin_conference_ticket_path(conference.short_title, conference.tickets.first) + expect(current_path).to eq(edit_admin_conference_ticket_path(conference.short_title, conference.tickets.first)) + + visit admin_conference_campaigns_path(conference.short_title) + expect(current_path).to eq(admin_conference_campaigns_path(conference.short_title)) + + visit new_admin_conference_campaign_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_campaign_path(conference.short_title)) + + create(:campaign, conference: conference) + visit edit_admin_conference_campaign_path(conference.short_title, conference.campaigns.first) + expect(current_path).to eq(edit_admin_conference_campaign_path(conference.short_title, conference.campaigns.first)) + + visit admin_conference_targets_path(conference.short_title) + expect(current_path).to eq(admin_conference_targets_path(conference.short_title)) + + visit new_admin_conference_target_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_target_path(conference.short_title)) + + create(:target, conference: conference) + visit edit_admin_conference_target_path(conference.short_title, conference.targets.first) + expect(current_path).to eq(edit_admin_conference_target_path(conference.short_title, conference.targets.first)) + + visit admin_conference_program_tracks_path(conference.short_title) + expect(current_path).to eq(admin_conference_program_tracks_path(conference.short_title)) + + visit admin_conference_roles_path(conference.short_title) + expect(current_path).to eq(admin_conference_roles_path(conference.short_title)) + + visit admin_conference_emails_path(conference.short_title) + expect(current_path).to eq(admin_conference_emails_path(conference.short_title)) + + visit admin_conference_resources_path(conference.short_title) + expect(current_path).to eq(admin_conference_resources_path(conference.short_title)) + + visit new_admin_conference_resource_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_resource_path(conference.short_title)) + + create(:resource, conference: conference) + visit edit_admin_conference_resource_path(conference.short_title, conference.resources.first) + expect(current_path).to eq(edit_admin_conference_resource_path(conference.short_title, conference.resources.first)) + + visit admin_revision_history_path + expect(current_path).to eq(admin_revision_history_path) + end + end +end diff --git a/spec/features/user_ability_spec.rb b/spec/features/user_ability_spec.rb new file mode 100644 index 00000000..d56e7441 --- /dev/null +++ b/spec/features/user_ability_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +feature 'Has correct abilities' do + + let(:organization) { create(:organization) } + let(:conference) { create(:full_conference, organization: organization) } # user is cfp + let(:user) { create(:user) } + + context 'when user has no role' do + before do + sign_in user + end + + scenario 'for administration views' do + visit admin_conference_path(conference.short_title) + + expect(current_path).to eq root_path + expect(flash).to eq 'You are not authorized to access this page.' + end + end +end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index fcf9b384..6803ffc5 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -139,22 +139,20 @@ describe 'User' do end shared_examples 'user with any role' do - before do - @other_organization = create(:organization) - @other_conference = create(:conference, organization: @other_organization) - end + let!(:other_organization) { create(:organization) } + let!(:other_conference) { create(:conference, organization: other_organization) } - it{ should_not be_able_to(:update, Role.find_by(name: 'organization_admin', resource: @other_organization)) } - it{ should_not be_able_to(:edit, Role.find_by(name: 'organization_admin', resource: @other_organization)) } - it{ should_not be_able_to(:show, Role.find_by(name: 'organization_admin', resource: @other_organization)) } + it{ should_not be_able_to(:update, Role.find_by(name: 'organization_admin', resource: other_organization)) } + it{ should_not be_able_to(:edit, Role.find_by(name: 'organization_admin', resource: other_organization)) } + it{ should_not be_able_to(:show, Role.find_by(name: 'organization_admin', resource: other_organization)) } - %w(organizer cfp info_desk volunteers_coordinator).each do |role| - it{ should_not be_able_to(:toggle_user, Role.find_by(name: role, resource: @other_conference)) } - it{ should_not be_able_to(:update, Role.find_by(name: role, resource: @other_conference)) } - it{ should_not be_able_to(:edit, Role.find_by(name: role, resource: @other_conference)) } - it{ should be_able_to(:show, Role.find_by(name: role, resource: @other_conference)) } - it{ should be_able_to(:index, Role.find_by(name: role, resource: @other_conference)) } - end + %w(organizer cfp info_desk volunteers_coordinator).each do |role| + it{ should_not be_able_to(:toggle_user, Role.find_by(name: role, resource: other_conference)) } + it{ should_not be_able_to(:update, Role.find_by(name: role, resource: other_conference)) } + it{ should_not be_able_to(:edit, Role.find_by(name: role, resource: other_conference)) } + it{ should be_able_to(:show, Role.find_by(name: role, resource: other_conference)) } + it{ should be_able_to(:index, Role.find_by(name: role, resource: other_conference)) } + end end shared_examples 'user with non-organizer role' do |role_name| @@ -199,8 +197,8 @@ describe 'User' do it{ should_not be_able_to(:new, Organization)} it{ should_not be_able_to(:create, Organization)} - it{ should_not be_able_to(:new, Conference.new) } - it{ should_not be_able_to(:create, Conference.new) } + it{ should_not be_able_to(:new, Conference)} + it{ should_not be_able_to(:create, Conference) } it{ should be_able_to(:manage, my_conference) } it{ should_not be_able_to(:manage, conference_public) } it{ should be_able_to(:manage, my_conference.splashpage) } @@ -269,8 +267,8 @@ describe 'User' do let(:role) { Role.find_by(name: 'cfp', resource: my_conference) } let(:user) { create(:user, role_ids: [role.id]) } - it{ should_not be_able_to(:new, Conference.new) } - it{ should_not be_able_to(:create, Conference.new) } + it{ should_not be_able_to(:new, Conference) } + it{ should_not be_able_to(:create, Conference) } it{ should_not be_able_to(:manage, my_conference) } it{ should_not be_able_to(:manage, conference_public) } it{ should_not be_able_to(:manage, my_conference.splashpage) } @@ -336,8 +334,8 @@ describe 'User' do let(:role) { Role.find_by(name: 'info_desk', resource: my_conference) } let(:user) { create(:user, role_ids: [role.id]) } - it{ should_not be_able_to(:new, Conference.new) } - it{ should_not be_able_to(:create, Conference.new) } + it{ should_not be_able_to(:new, Conference) } + it{ should_not be_able_to(:create, Conference) } it{ should_not be_able_to(:manage, my_conference) } it{ should_not be_able_to(:manage, conference_public) } it{ should_not be_able_to(:manage, my_conference.splashpage) } @@ -403,8 +401,8 @@ describe 'User' do let(:role) { Role.find_by(name: 'volunteers_coordinator', resource: my_conference) } let(:user) { create(:user, role_ids: [role.id]) } - it{ should_not be_able_to(:new, Conference.new) } - it{ should_not be_able_to(:create, Conference.new) } + it{ should_not be_able_to(:new, Conference) } + it{ should_not be_able_to(:create, Conference) } it{ should_not be_able_to(:manage, my_conference) } it{ should_not be_able_to(:manage, conference_public) } it{ should_not be_able_to(:manage, my_conference.splashpage) } From d59a036cf17b405df38bbdf13aafce6dcef838df Mon Sep 17 00:00:00 2001 From: shlok007 Date: Fri, 30 Jun 2017 09:27:19 +0530 Subject: [PATCH 056/237] removed unnecessary comments and fixed grammatical errors --- spec/features/cfp_ability_spec.rb | 3 +-- spec/features/info_desk_ability_spec.rb | 5 +---- spec/features/organization_admin_ability_spec.rb | 2 +- spec/features/organization_spec.rb | 6 +++--- spec/features/organizer_ability_spec.rb | 3 +-- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/spec/features/cfp_ability_spec.rb b/spec/features/cfp_ability_spec.rb index 52725527..235dedea 100644 --- a/spec/features/cfp_ability_spec.rb +++ b/spec/features/cfp_ability_spec.rb @@ -3,8 +3,7 @@ require 'spec_helper' feature 'Has correct abilities' do let(:organization) { create(:organization) } - # It is necessary to use bang version of let to build roles before user - let(:conference) { create(:full_conference, organization: organization) } # user is cfp + let(:conference) { create(:full_conference, organization: organization) } let(:role_cfp) { Role.find_by(name: 'cfp', resource: conference) } let(:user_cfp) { create(:user, role_ids: [role_cfp.id]) } diff --git a/spec/features/info_desk_ability_spec.rb b/spec/features/info_desk_ability_spec.rb index d7b0b909..7d0039fe 100644 --- a/spec/features/info_desk_ability_spec.rb +++ b/spec/features/info_desk_ability_spec.rb @@ -3,11 +3,8 @@ require 'spec_helper' feature 'Has correct abilities' do let(:organization) { create(:organization) } - # It is necessary to use bang version of let to build roles before user - let(:conference) { create(:full_conference, organization: organization) } # user is info_desk - + let(:conference) { create(:full_conference, organization: organization) } let(:role_info_desk) { Role.find_by(name: 'info_desk', resource: conference) } - let(:user_info_desk) { create(:user, role_ids: [role_info_desk.id]) } context 'when user is info desk' do diff --git a/spec/features/organization_admin_ability_spec.rb b/spec/features/organization_admin_ability_spec.rb index 5a247dd8..3a5ffcd3 100644 --- a/spec/features/organization_admin_ability_spec.rb +++ b/spec/features/organization_admin_ability_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Has correct abilities' do let(:organization) { create(:organization) } - let(:conference) { create(:full_conference, organization: organization) } # user is organization_admin + let(:conference) { create(:full_conference, organization: organization) } let(:role_organization_admin) { Role.find_by(name: 'organization_admin', resource: organization) } let(:user_organization_admin) { create(:user, role_ids: [role_organization_admin.id]) } diff --git a/spec/features/organization_spec.rb b/spec/features/organization_spec.rb index 72fee466..6fcf590b 100644 --- a/spec/features/organization_spec.rb +++ b/spec/features/organization_spec.rb @@ -6,7 +6,7 @@ feature Organization do let(:organization_admin) { create(:user, role_ids: [organization_admin_role.id]) } let(:admin_user) { create(:admin) } - shared_examples 'successfully updates a organization' do + shared_examples 'successfully updates an organization' do scenario 'updates a exsisting organization', feature: true, js: true do visit edit_admin_organization_path(organization) fill_in 'organization_name', with: 'changed name' @@ -33,7 +33,7 @@ feature Organization do expect(Organization.last.name).to eq('Organization name') end - it_behaves_like 'successfully updates a organization' + it_behaves_like 'successfully updates an organization' end context 'signed in as organization admin' do @@ -46,6 +46,6 @@ feature Organization do expect(flash).to eq('You are not authorized to access this page.') end - it_behaves_like 'successfully updates a organization' + it_behaves_like 'successfully updates an organization' end end diff --git a/spec/features/organizer_ability_spec.rb b/spec/features/organizer_ability_spec.rb index 9604fad6..7617bc0a 100644 --- a/spec/features/organizer_ability_spec.rb +++ b/spec/features/organizer_ability_spec.rb @@ -3,8 +3,7 @@ require 'spec_helper' feature 'Has correct abilities' do let(:organization) { create(:organization) } - # It is necessary to use bang version of let to build roles before user - let(:conference) { create(:full_conference, organization: organization) } # user is organizer + let(:conference) { create(:full_conference, organization: organization) } let(:other_conference) { create(:conference, organization: organization) } # user is organizer, venue is not set by default let(:role_organizer_conf) { Role.find_by(name: 'organizer', resource: conference) } let(:role_organizer_other_conf) { Role.find_by(name: 'organizer', resource: other_conference) } From f68fd39095915bcfda29a41b1ddc2abc19aa8695 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Mon, 3 Jul 2017 04:17:06 +0530 Subject: [PATCH 057/237] fixed abilities for conference#new and organization#new --- app/models/ability.rb | 6 +++--- spec/models/ability_spec.rb | 38 +++++++++++++++++++++++-------------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 8185fadd..5001278a 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -150,11 +150,11 @@ class Ability def signed_in_with_organization_admin_role(user) org_ids_for_organization_admin = Organization.with_role(:organization_admin, user).pluck(:id) + conf_ids_for_organization_admin = Conference.where(organization_id: org_ids_for_organization_admin).pluck(:id) - can :manage, Organization, id: org_ids_for_organization_admin + can [:read, :update, :destroy], Organization, id: org_ids_for_organization_admin can :new, Conference can :manage, Conference, organization_id: org_ids_for_organization_admin - conf_ids_for_organization_admin = Conference.where(organization_id: org_ids_for_organization_admin).pluck(:id) can [:index, :show], Role can [:edit, :update], Role do |role| role.resource_type == 'Organization' && (org_ids_for_organization_admin.include? role.resource_id) @@ -167,7 +167,7 @@ class Ability # conferences that belong to organizations for which user is 'organization_admin' conf_ids = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq can :manage, Resource, conference_id: conf_ids - can :manage, Conference, id: conf_ids + can [:read, :update, :destroy], Conference, id: conf_ids can :manage, Splashpage, conference_id: conf_ids can :manage, Contact, conference_id: conf_ids can :manage, EmailSettings, conference_id: conf_ids diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 6803ffc5..02aa4882 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -172,11 +172,19 @@ describe 'User' do context 'when user has the role organization_admin' do let(:role) { Role.find_by(name: 'organization_admin', resource: organization) } let(:user) { create(:user, role_ids: [role.id]) } - let(:other_conference) { create(:conference) } + let(:other_organization) { create(:organization) } + let(:other_conference) { create(:conference, organization: other_organization) } - it{ should_not be_able_to(:manage, other_conference) } it{ should be_able_to(:manage, my_conference) } - it{ should be_able_to(:manage, organization) } + it{ should be_able_to(:read, organization) } + it{ should be_able_to(:update, organization) } + it{ should be_able_to(:destroy, organization) } + it{ should be_able_to(:new, Conference.new) } + it{ should be_able_to(:create, Conference.new(organization_id: organization.id)) } + it{ should_not be_able_to(:manage, other_conference) } + it{ should_not be_able_to(:create, Conference.new(organization_id: other_organization.id)) } + it{ should_not be_able_to(:new, Organization.new) } + it{ should_not be_able_to(:create, Organization.new) } end context 'when user has the role organizer' do @@ -195,11 +203,13 @@ describe 'User' do should be_able_to(:destroy, my_venue) end - it{ should_not be_able_to(:new, Organization)} - it{ should_not be_able_to(:create, Organization)} - it{ should_not be_able_to(:new, Conference)} - it{ should_not be_able_to(:create, Conference) } - it{ should be_able_to(:manage, my_conference) } + it{ should_not be_able_to(:new, Organization.new)} + it{ should_not be_able_to(:create, Organization.new)} + it{ should_not be_able_to(:new, Conference.new)} + it{ should_not be_able_to(:create, Conference.new) } + it{ should be_able_to(:read, my_conference) } + it{ should be_able_to(:update, my_conference) } + it{ should be_able_to(:destroy, my_conference) } it{ should_not be_able_to(:manage, conference_public) } it{ should be_able_to(:manage, my_conference.splashpage) } it{ should_not be_able_to(:manage, conference_public.splashpage) } @@ -267,8 +277,8 @@ describe 'User' do let(:role) { Role.find_by(name: 'cfp', resource: my_conference) } let(:user) { create(:user, role_ids: [role.id]) } - it{ should_not be_able_to(:new, Conference) } - it{ should_not be_able_to(:create, Conference) } + it{ should_not be_able_to(:new, Conference.new) } + it{ should_not be_able_to(:create, Conference.new) } it{ should_not be_able_to(:manage, my_conference) } it{ should_not be_able_to(:manage, conference_public) } it{ should_not be_able_to(:manage, my_conference.splashpage) } @@ -334,8 +344,8 @@ describe 'User' do let(:role) { Role.find_by(name: 'info_desk', resource: my_conference) } let(:user) { create(:user, role_ids: [role.id]) } - it{ should_not be_able_to(:new, Conference) } - it{ should_not be_able_to(:create, Conference) } + it{ should_not be_able_to(:new, Conference.new) } + it{ should_not be_able_to(:create, Conference.new) } it{ should_not be_able_to(:manage, my_conference) } it{ should_not be_able_to(:manage, conference_public) } it{ should_not be_able_to(:manage, my_conference.splashpage) } @@ -401,8 +411,8 @@ describe 'User' do let(:role) { Role.find_by(name: 'volunteers_coordinator', resource: my_conference) } let(:user) { create(:user, role_ids: [role.id]) } - it{ should_not be_able_to(:new, Conference) } - it{ should_not be_able_to(:create, Conference) } + it{ should_not be_able_to(:new, Conference.new) } + it{ should_not be_able_to(:create, Conference.new) } it{ should_not be_able_to(:manage, my_conference) } it{ should_not be_able_to(:manage, conference_public) } it{ should_not be_able_to(:manage, my_conference.splashpage) } From 3d4adb568379d3de50dc6069aad273142c8aa3ee Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Mon, 26 Jun 2017 04:04:36 +0530 Subject: [PATCH 058/237] Allow admin to show/generate ticket Created physical ticket controller and views for admin. --- .../admin/physical_ticket_controller.rb | 14 ++++++ .../admin/physical_ticket/index.html.haml | 43 +++++++++++++++++++ app/views/admin/tickets/index.html.haml | 6 +-- config/routes.rb | 1 + 4 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 app/controllers/admin/physical_ticket_controller.rb create mode 100644 app/views/admin/physical_ticket/index.html.haml diff --git a/app/controllers/admin/physical_ticket_controller.rb b/app/controllers/admin/physical_ticket_controller.rb new file mode 100644 index 00000000..d43c5c33 --- /dev/null +++ b/app/controllers/admin/physical_ticket_controller.rb @@ -0,0 +1,14 @@ +module Admin + class PhysicalTicketController < Admin::BaseController + before_action :authenticate_user! + load_resource :conference, find_by: :short_title + load_and_authorize_resource + authorize_resource :conference_registrations, class: Registration + + def index + @physical_tickets = @conference.physical_tickets + @tickets_sold_distribution = @conference.tickets_sold_distribution + @tickets_turnover_distribution = @conference.tickets_turnover_distribution + end + end +end diff --git a/app/views/admin/physical_ticket/index.html.haml b/app/views/admin/physical_ticket/index.html.haml new file mode 100644 index 00000000..fe128932 --- /dev/null +++ b/app/views/admin/physical_ticket/index.html.haml @@ -0,0 +1,43 @@ +.container + .row + .col-md-12.page-header + %h2 + Tickets Sold + .text-muted + Tickets sold for the conference + .row + .col-md-4 + = render partial: 'admin/conferences/doughnut_chart', + locals: { title: 'Tickets sold', data: @tickets_sold_distribution } + .col-md-4 + = render partial: 'admin/conferences/doughnut_chart', + locals: {title: 'Tickets turnover', data: @tickets_turnover_distribution} + %br + - if @physical_tickets.any? + .row + .col-md-12 + %table.table.table-hover.datatable#tickets + %thead + %th ID + %th Type + %th User + %th Actions + %tbody + - @physical_tickets.each do |physical_ticket| + %tr + %td= physical_ticket.id + %td= physical_ticket.ticket.title + %td= physical_ticket.user.email + %td + .btn-group + = link_to 'Show', + conference_physical_ticket_path(@conference.short_title, + physical_ticket.id), + class: 'btn btn-primary' + = link_to 'Generate PDF', + conference_physical_ticket_path(@conference.short_title, + physical_ticket.id, + format: :pdf), + class: 'button btn btn-default btn-info' + - else + %h5 No Tickets sold! diff --git a/app/views/admin/tickets/index.html.haml b/app/views/admin/tickets/index.html.haml index 6a0c7dca..bb2804bf 100644 --- a/app/views/admin/tickets/index.html.haml +++ b/app/views/admin/tickets/index.html.haml @@ -4,11 +4,6 @@ %h1 Tickets %p.text-muted Tickets to get during registration -.row - .col-md-4 - = render partial: 'admin/conferences/doughnut_chart', locals: { title: 'Tickets sold', data: @tickets_sold_distribution,} - .col-md-4 - = render partial: 'admin/conferences/doughnut_chart', locals: { title: 'Tickets turnover', data: @tickets_turnover_distribution } %br - if @conference.tickets.any? .row @@ -42,3 +37,4 @@ .row .col-md-12 = link_to 'Add Ticket', new_admin_conference_ticket_path, class: 'btn btn-success pull-right' + = link_to 'Tickets Sold', admin_conference_physical_ticket_index_path, class: 'button btn btn-default btn-info pull-right' diff --git a/config/routes.rb b/config/routes.rb index 8fa4b857..ae67a820 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -81,6 +81,7 @@ Osem::Application.routes.draw do resources :targets, except: [:show] resources :campaigns, except: [:show] resources :emails, only: [:show, :update, :index] + resources :physical_ticket, only: [:index] resources :roles, except: [ :new, :create ] do member do post :toggle_user From 6b3a6fa967ade39bf01b42798013fb14e5dab155 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Thu, 29 Jun 2017 20:58:22 +0530 Subject: [PATCH 059/237] Fixed ticket_sold method of ticket model --- app/models/ticket.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/ticket.rb b/app/models/ticket.rb index 7bac9462..ce527472 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -56,7 +56,7 @@ class Ticket < ActiveRecord::Base end def tickets_sold - ticket_purchases.sum(:quantity) + ticket_purchases.paid.sum(:quantity) end def tickets_turnover From 7d472f2ad5670fd754eb44d56358a8cd50c75e94 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 4 Jul 2017 05:55:41 +0530 Subject: [PATCH 060/237] fix failing tests --- app/views/admin/registration_periods/show.html.haml | 2 +- app/views/admin/splashpages/show.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/registration_periods/show.html.haml b/app/views/admin/registration_periods/show.html.haml index 9ef02e37..057a7a37 100644 --- a/app/views/admin/registration_periods/show.html.haml +++ b/app/views/admin/registration_periods/show.html.haml @@ -25,5 +25,5 @@ = link_to 'Delete', admin_conference_registration_period_path, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' - else - - if can? :create, @conference + - if can? :create, @conference.build_registration_period = link_to 'New Registration Period', new_admin_conference_registration_period_path, class: 'btn btn-primary' diff --git a/app/views/admin/splashpages/show.html.haml b/app/views/admin/splashpages/show.html.haml index 0c6be8a8..b4e5f24c 100644 --- a/app/views/admin/splashpages/show.html.haml +++ b/app/views/admin/splashpages/show.html.haml @@ -90,5 +90,5 @@ - else .row .col-md-12.text-right - - if can? :create, @conference + - if can? :create, @conference.build_splashpage = link_to 'Create Splashpage', new_admin_conference_splashpage_path, class: 'btn btn-primary' From 95fbd10153035043318fcc08b92988c817fc3301 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Thu, 29 Jun 2017 23:39:56 +0300 Subject: [PATCH 061/237] Friendly urls for tracks Don't use tracks ids in urls Add short_name to tracks and use that in urls as the identifier --- app/controllers/admin/tracks_controller.rb | 4 +- app/models/track.rb | 6 +++ app/views/admin/tracks/_form.html.haml | 3 +- app/views/admin/tracks/index.html.haml | 9 +++-- .../versions/_object_desc_and_link.html.haml | 2 +- ...20170629162450_add_short_name_to_tracks.rb | 39 +++++++++++++++++++ db/schema.rb | 3 +- spec/factories/tracks.rb | 1 + spec/features/tracks_spec.rb | 2 + 9 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20170629162450_add_short_name_to_tracks.rb diff --git a/app/controllers/admin/tracks_controller.rb b/app/controllers/admin/tracks_controller.rb index 2df7db67..4fc9d9c7 100644 --- a/app/controllers/admin/tracks_controller.rb +++ b/app/controllers/admin/tracks_controller.rb @@ -2,7 +2,7 @@ module Admin class TracksController < Admin::BaseController load_and_authorize_resource :conference, find_by: :short_title load_and_authorize_resource :program, through: :conference, singleton: true - load_and_authorize_resource through: :program + load_and_authorize_resource through: :program, find_by: :short_name def index; end @@ -53,7 +53,7 @@ module Admin private def track_params - params.require(:track).permit(:name, :description, :color) + params.require(:track).permit(:name, :description, :color, :short_name) end end end diff --git a/app/models/track.rb b/app/models/track.rb index 1d94f7d5..d3502bb0 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -7,6 +7,12 @@ class Track < ActiveRecord::Base before_create :generate_guid validates :name, presence: true validates :color, format: /\A#[0-9A-F]{6}\z/ + validates :short_name, + presence: true, + format: /\A[a-zA-Z0-9_-]*\z/, + uniqueness: { + scope: :program + } before_validation :capitalize_color diff --git a/app/views/admin/tracks/_form.html.haml b/app/views/admin/tracks/_form.html.haml index 579d263d..c3c7cf26 100644 --- a/app/views/admin/tracks/_form.html.haml +++ b/app/views/admin/tracks/_form.html.haml @@ -8,8 +8,9 @@ Track .row .col-md-12 - = semantic_form_for(@track, url: (@track.new_record? ? admin_conference_program_tracks_path : admin_conference_program_track_path(@conference.short_title, @track))) do |f| + = semantic_form_for(@track, url: (@track.new_record? ? admin_conference_program_tracks_path : admin_conference_program_track_path(@conference.short_title, @track.short_name))) do |f| = f.input :name + = f.input :short_name, hint: "A short and unique handle for the track, using only letters, numbers, underscores, and dashes. This will be used to identify the track in URLs etc. Example: 'my_awesome_track'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' } = f.input :color, input_html: {size: 6, type: 'color'}, required: true = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, hint: markdown_hint = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index f2de8a38..f9ed9036 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -9,6 +9,7 @@ %table.table.table-hover#tracks %thead %th Name + %th Short name %th Description %th Color %th Actions @@ -16,8 +17,10 @@ - @tracks.each do |track| %tr %td - = link_to(admin_conference_program_track_path(@conference.short_title, track)) do + = link_to(admin_conference_program_track_path(@conference.short_title, track.short_name)) do = track.name + %td + = track.short_name %td %p = truncate(track.description) @@ -26,9 +29,9 @@ = track.color %td .btn-group{role: "group"} - = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track.id), + = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track.short_name), method: :get, class: 'btn btn-primary' - = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track.id), + = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track.short_name), method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } .row diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index 14b1f2fc..83542ef1 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -94,7 +94,7 @@ = 'track' - track = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, track.name, - admin_conference_program_track_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) + admin_conference_program_track_path(conference_id: Conference.find(version.conference_id).short_title, id: track.try(:short_name)) - when 'EventType' = 'event type' diff --git a/db/migrate/20170629162450_add_short_name_to_tracks.rb b/db/migrate/20170629162450_add_short_name_to_tracks.rb new file mode 100644 index 00000000..cbc6b431 --- /dev/null +++ b/db/migrate/20170629162450_add_short_name_to_tracks.rb @@ -0,0 +1,39 @@ +class AddShortNameToTracks < ActiveRecord::Migration + class TmpProgram < ActiveRecord::Base + self.table_name = 'programs' + end + + class TmpTrack < ActiveRecord::Base + self.table_name = 'tracks' + end + + def change + add_column :tracks, :short_name, :string + + TmpTrack.reset_column_information + + TmpProgram.find_each do |program| + # Keeps count of how many times we've encountered a short_name + track_name_counter = {} + + TmpTrack.where(program_id: program.id).find_each do |track| + # Replace spaces with undercores and remove the non alphanumeric characters that aren't underscores or dashes + short_name = track.name.tr(' ', '_').tr('^a-zA-Z0-9_-', '') + + # If we've seen that short_name before then add the counter in the end to avoid collisions + if track_name_counter[short_name] + track_name_counter[short_name] += 1 + short_name += "_#{track_name_counter[short_name]}" + else + # Initialize the counter + track_name_counter[short_name] = 0 unless track_name_counter[short_name] + end + + track.short_name = short_name + track.save! + end + end + + change_column_null :tracks, :short_name, false + end +end diff --git a/db/schema.rb b/db/schema.rb index 348f6170..2e2fb088 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170603095900) do +ActiveRecord::Schema.define(version: 20170629162450) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -485,6 +485,7 @@ ActiveRecord::Schema.define(version: 20170603095900) do t.datetime "created_at" t.datetime "updated_at" t.integer "program_id" + t.string "short_name", null: false end create_table "users", force: :cascade do |t| diff --git a/spec/factories/tracks.rb b/spec/factories/tracks.rb index 1b7f8083..4334cb4c 100644 --- a/spec/factories/tracks.rb +++ b/spec/factories/tracks.rb @@ -3,6 +3,7 @@ FactoryGirl.define do name { Faker::Commerce.department(2, true) } description { Faker::Lorem.sentence } color { Faker::Color.hex_color } + short_name { SecureRandom.urlsafe_base64(5) } program end end diff --git a/spec/features/tracks_spec.rb b/spec/features/tracks_spec.rb index d1972075..3538a6d7 100644 --- a/spec/features/tracks_spec.rb +++ b/spec/features/tracks_spec.rb @@ -14,6 +14,7 @@ feature Track do click_link 'New Track' fill_in 'track_name', with: 'Distribution' + fill_in 'track_short_name', with: 'Distribution' page.find('#track_color').set('#B94D4D') fill_in 'track_description', with: 'Events about our Linux distribution' click_button 'Create Track' @@ -50,6 +51,7 @@ feature Track do click_link 'Edit' fill_in 'track_name', with: 'Distribution' + fill_in 'track_short_name', with: 'Distribution' page.find('#track_color').set('#B94D4D') fill_in 'track_description', with: 'Events about our Linux distribution' click_button 'Update Track' From b9a540f4e2bba612f44f848589a3f1c0c1dd7ac7 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Tue, 13 Jun 2017 07:20:43 +0530 Subject: [PATCH 062/237] Sample prototype for ticket pdf Added verticl layout of ticket pdf without QR code. --- Gemfile | 2 + Gemfile.lock | 8 +++ app/controllers/physical_ticket_controller.rb | 5 +- app/uploaders/picture_uploader.rb | 4 ++ app/views/physical_ticket/show.pdf.prawn | 62 +++++++++++++++++++ 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 app/views/physical_ticket/show.pdf.prawn diff --git a/Gemfile b/Gemfile index 245080c3..e6245e78 100644 --- a/Gemfile +++ b/Gemfile @@ -128,6 +128,8 @@ gem 'country_select' # as PDF generator gem 'prawn_rails' +gem 'rqrcode' +gem 'prawn-qrcode', '~> 0.2.2.1' # to render XLS spreadsheets gem 'axlsx', git: 'https://github.com/randym/axlsx.git' diff --git a/Gemfile.lock b/Gemfile.lock index 74e8ce84..a493c113 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -117,6 +117,7 @@ GEM chart-js-rails (0.0.6) railties (> 3.1) chronic (0.10.2) + chunky_png (1.3.8) cliver (0.3.2) cloudinary (1.1.6) aws_cf_signer @@ -343,6 +344,9 @@ GEM prawn (1.0.0) pdf-core (~> 0.2.2) ttfunk (~> 1.1.1) + prawn-qrcode (0.2.2.1) + prawn (>= 0.11.1) + rqrcode (>= 0.4.1) prawn_rails (0.0.11) prawn (>= 0.11.1) railties (>= 3.0.0) @@ -429,6 +433,8 @@ GEM mime-types (>= 1.16, < 3.0) netrc (~> 0.7) rolify (5.1.0) + rqrcode (0.10.1) + chunky_png (~> 1.0) rspec (3.0.0) rspec-core (~> 3.0.0) rspec-expectations (~> 3.0.0) @@ -611,6 +617,7 @@ DEPENDENCIES phantomjs piwik_analytics (~> 1.0.1) poltergeist + prawn-qrcode (~> 0.2.2.1) prawn_rails rails (~> 4.2) rails-assets-bootstrap-markdown! @@ -631,6 +638,7 @@ DEPENDENCIES redcarpet responders (~> 2.0) rolify + rqrcode rspec-activemodel-mocks rspec-rails rubocop (~> 0.48.1) diff --git a/app/controllers/physical_ticket_controller.rb b/app/controllers/physical_ticket_controller.rb index 2354f279..20d335d7 100644 --- a/app/controllers/physical_ticket_controller.rb +++ b/app/controllers/physical_ticket_controller.rb @@ -8,5 +8,8 @@ class PhysicalTicketController < ApplicationController @physical_tickets = current_user.physical_tickets.by_conference(@conference) end - def show; end + def show + @file_name = "ticket_for_#{@conference.short_title}" + @user = @physical_ticket.user + end end diff --git a/app/uploaders/picture_uploader.rb b/app/uploaders/picture_uploader.rb index af3c2227..b17f0d76 100644 --- a/app/uploaders/picture_uploader.rb +++ b/app/uploaders/picture_uploader.rb @@ -52,6 +52,10 @@ class PictureUploader < CarrierWave::Uploader::Base "system/#{object_class_name}/#{mounted_as}/#{model.id}" end + def image + @image ||= MiniMagick::Image.open(file.file) + end + # Create different versions of your uploaded files: version :large do process resize_to_fit: [300, 300] diff --git a/app/views/physical_ticket/show.pdf.prawn b/app/views/physical_ticket/show.pdf.prawn new file mode 100644 index 00000000..90f11fd5 --- /dev/null +++ b/app/views/physical_ticket/show.pdf.prawn @@ -0,0 +1,62 @@ +prawn_document(filename: @file_name, page_layout: :portrait, :page_size =>'A4' ) do |pdf| + # Vertical Layout + top = pdf.bounds.top + bottom = pdf.bounds.bottom + left = pdf.bounds.left + right = pdf.bounds.right + mid_vertical = (pdf.bounds.top-pdf.bounds.bottom)/2 + mid_horizontal = (pdf.bounds.right-pdf.bounds.left)/2 + x = 0 + + pdf.move_down mid_vertical + pdf.dash(2, :space => 1) + pdf.stroke_horizontal_rule + pdf.stroke_vertical_line pdf.bounds.top, pdf.bounds.bottom, :at => mid_horizontal + pdf.move_up mid_vertical + pdf.draw_text "TICKET HOLDER", :at => [x,pdf.cursor-30], :size => 17 + pdf.dash(2, :space => 0) + pdf.stroke_rectangle [x, pdf.cursor-50], 230, 150 + pdf.move_down 80 + pdf.draw_text "NAME", :at => [x+10,pdf.cursor], :size => 13 + pdf.fill_color "808080" + pdf.draw_text "#{@user.name}", :at => [x+10,pdf.cursor-25], size: 20 + pdf.fill_color "000000" + pdf.draw_text "EMAIL", :at => [x+10,pdf.cursor-50], :size => 13 + pdf.fill_color "808080" + pdf.draw_text "#{@user.email}", :at => [x+10,pdf.cursor-75], size: 20 + pdf.fill_color "000000" + pdf.move_up 20 + if @conference.picture? + if 7 * @conference.picture.image[:width] > 12 * @conference.picture.image[:height] + pdf.image "#{Rails.root}/public#{@conference.picture_url}", :at => [mid_horizontal+30, pdf.cursor], :width => 120 + else + pdf.image "#{Rails.root}/public#{@conference.picture_url}", :at => [mid_horizontal+30, pdf.cursor], :height => 70 + end + else + pdf.image "#{Rails.root}/public/img/osem-logo.png", :at => [mid_horizontal+30, pdf.cursor], :height => 70 + end + pdf.move_down 70 + pdf.draw_text "#{@conference.title}", :at => [mid_horizontal+30,pdf.cursor-30], :size => 12 + pdf.draw_text "#{@conference.organization.name}", :at => [mid_horizontal+30,pdf.cursor-50], :size => 12 + pdf.draw_text "#{@conference.venue.name}", :at => [mid_horizontal+30,pdf.cursor-70] + pdf.move_up 130 + pdf.move_down mid_vertical + pdf.draw_text "EVENT", :at => [x,pdf.cursor-40], :size => 15 + pdf.fill_color "808080" + pdf.draw_text "#{@conference.title}", :at => [x,pdf.cursor-60], size: 12 + pdf.draw_text "#{@conference.start_date.strftime('%B %d, %Y')}", :at => [x,pdf.cursor-80], size: 12 + pdf.move_down 80 + pdf.fill_color "000000" + pdf.draw_text "TICKET", :at => [x,pdf.cursor-30], :size => 15 + pdf.fill_color "808080" + pdf.draw_text "#{@physical_ticket.ticket.title}", :at => [x,pdf.cursor-50], size: 12 + pdf.move_down 50 + pdf.fill_color "000000" + pdf.draw_text "TICKET REF.", :at => [x,pdf.cursor-30], :size => 15 + pdf.fill_color "808080" + pdf.draw_text "#{@physical_ticket.ticket_purchase.id}", :at => [x,pdf.cursor-50], size: 12 + pdf.move_down 50 + pdf.fill_color "000000" + pdf.draw_text "Powered By OSEM", :at => [(mid_horizontal-left-100)/2,pdf.cursor-100], :size => 11 + pdf.move_up 180 +end From 72537ba2a8e590877e12edae767efcc0f2b147f0 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Thu, 29 Jun 2017 19:25:10 +0530 Subject: [PATCH 063/237] Fixed user abilities in Physical Ticket --- app/models/ability.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 5001278a..40965719 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -88,7 +88,7 @@ class Ability can :index, Ticket can :manage, TicketPurchase, user_id: user.id can [:new, :create], Payment, user_id: user.id - can [:index, :show], PhysicalTicket, user_id: user.id + can [:index, :show], PhysicalTicket, user: user can [:create, :destroy], Subscription, user_id: user.id From 2cc97a92f5b42877946c4a29f3df87cd4da84a5b Mon Sep 17 00:00:00 2001 From: L11 Date: Sat, 1 Jul 2017 13:39:22 +0530 Subject: [PATCH 064/237] Remove duplicated label - target/form --- app/views/admin/targets/_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/targets/_form.html.haml b/app/views/admin/targets/_form.html.haml index b0462249..1e81989b 100644 --- a/app/views/admin/targets/_form.html.haml +++ b/app/views/admin/targets/_form.html.haml @@ -10,6 +10,6 @@ = semantic_form_for(@target, url: (@target.new_record? ? admin_conference_targets_path : admin_conference_target_path(@conference.short_title, @target))) do |f| = f.input :due_date, as: :string, input_html: { class: 'target-due-date-datepicker'}, label: 'Until when do you want to have ' = f.input :target_count, label: 'this amount of ' - = f.input :unit, as: :select, label: 'Unit', class: 'form-control', collection: Target.units.values, include_blank: false, label: 'units ' + = f.input :unit, as: :select, label: 'Unit', class: 'form-control', collection: Target.units.values, include_blank: false %p.text-right = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } From a327d2cbd2e41c728f001f5204eabde1e8a26276 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Mon, 26 Jun 2017 06:07:52 +0530 Subject: [PATCH 065/237] Ticket Purchase Index Page List all the unpaid ticket purchases of the user for that conference and allow user to pay for them. --- app/controllers/physical_ticket_controller.rb | 1 + .../ticket_purchases_controller.rb | 4 +++ app/views/physical_ticket/index.html.haml | 7 +++++ app/views/ticket_purchases/index.html.haml | 30 +++++++++++++++++++ config/routes.rb | 2 +- 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 app/views/ticket_purchases/index.html.haml diff --git a/app/controllers/physical_ticket_controller.rb b/app/controllers/physical_ticket_controller.rb index 2354f279..59c248d1 100644 --- a/app/controllers/physical_ticket_controller.rb +++ b/app/controllers/physical_ticket_controller.rb @@ -6,6 +6,7 @@ class PhysicalTicketController < ApplicationController def index @physical_tickets = current_user.physical_tickets.by_conference(@conference) + @unpaid_ticket_purchases = current_user.ticket_purchases.by_conference(@conference).unpaid end def show; end diff --git a/app/controllers/ticket_purchases_controller.rb b/app/controllers/ticket_purchases_controller.rb index 3945e154..792122e2 100644 --- a/app/controllers/ticket_purchases_controller.rb +++ b/app/controllers/ticket_purchases_controller.rb @@ -23,6 +23,10 @@ class TicketPurchasesController < ApplicationController end end + def index + @unpaid_ticket_purchases = current_user.ticket_purchases.by_conference(@conference).unpaid + end + private def ticket_purchase_params diff --git a/app/views/physical_ticket/index.html.haml b/app/views/physical_ticket/index.html.haml index ce741c39..b077400b 100644 --- a/app/views/physical_ticket/index.html.haml +++ b/app/views/physical_ticket/index.html.haml @@ -33,3 +33,10 @@ class: 'button btn btn-default btn-info' - else %h5 No Tickets found! + .row + .col-md-12 + - if @unpaid_ticket_purchases.any? + .h3 + You have unpaid tickets! + %small + = link_to "Pay them here", conference_ticket_purchases_path diff --git a/app/views/ticket_purchases/index.html.haml b/app/views/ticket_purchases/index.html.haml new file mode 100644 index 00000000..c9255c37 --- /dev/null +++ b/app/views/ticket_purchases/index.html.haml @@ -0,0 +1,30 @@ +.container + .row + .col-md-12.page-header + %h2 + Ticket Purchases + .text-muted + Your unpaid ticket purchases for the conference + + .col-md-12 + - if @unpaid_ticket_purchases.present? + %table.table.table-bordered.table-striped.table-hover#roles + %thead + %th ID + %th Type + %th Quantity + %th Date + %th Actions + %tbody + - @unpaid_ticket_purchases.each do |ticket_purchase| + %tr + %td= ticket_purchase.id + %td= ticket_purchase.ticket.title + %td= ticket_purchase.quantity + %td= ticket_purchase.created_at.strftime('%B %d, %Y') + %td + .btn-group + = link_to 'Pay', new_conference_payment_path, + class: 'btn btn-primary' + - else + %h5 You don't have any unpaid ticket purchase! diff --git a/config/routes.rb b/config/routes.rb index ae67a820..db88613f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -125,7 +125,7 @@ Osem::Application.routes.draw do # TODO: change conference_registrations to singular resource resource :conference_registration, path: 'register' resources :tickets, only: [:index] - resources :ticket_purchases, only: [:create, :destroy] + resources :ticket_purchases, only: [:create, :destroy, :index] resources :payments, only: [:index, :new, :create] resources :physical_ticket, only: [:index, :show] resource :subscriptions, only: [:create, :destroy] From dd52a9b2ab0b78708a7b23fba061a0fc0f730b38 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Fri, 30 Jun 2017 05:26:21 +0530 Subject: [PATCH 066/237] Make ticket layout configurable Added option for conference organizer to switch between ticket layouts (horizontal or vertical). Added test for the same. --- .../admin/conferences_controller.rb | 2 +- app/controllers/physical_ticket_controller.rb | 1 + app/models/conference.rb | 3 +++ app/views/admin/conferences/edit.html.haml | 1 + app/views/physical_ticket/show.pdf.prawn | 2 +- ...232817_add_ticket_layout_to_conferences.rb | 5 +++++ db/schema.rb | 1 + .../physical_ticket_controller_spec.rb | 20 +++++++++++++++++++ spec/factories/conferences.rb | 1 + spec/models/conference_spec.rb | 4 ++++ 10 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20170629232817_add_ticket_layout_to_conferences.rb create mode 100644 spec/controllers/physical_ticket_controller_spec.rb diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index f8c9ea19..6716a253 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -211,7 +211,7 @@ module Admin :vpositions_attributes, :use_volunteers, :color, :sponsorship_levels_attributes, :sponsors_attributes, :targets, :targets_attributes, - :campaigns, :campaigns_attributes, :registration_limit, :organization_id) + :campaigns, :campaigns_attributes, :registration_limit, :organization_id, :ticket_layout) end end end diff --git a/app/controllers/physical_ticket_controller.rb b/app/controllers/physical_ticket_controller.rb index 09b38ff2..8617e0d9 100644 --- a/app/controllers/physical_ticket_controller.rb +++ b/app/controllers/physical_ticket_controller.rb @@ -12,5 +12,6 @@ class PhysicalTicketController < ApplicationController def show @file_name = "ticket_for_#{@conference.short_title}" @user = @physical_ticket.user + @ticket_layout = @conference.ticket_layout.to_sym end end diff --git a/app/models/conference.rb b/app/models/conference.rb index 11fab753..cf94b334 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -57,6 +57,7 @@ class Conference < ActiveRecord::Base :end_date, :start_hour, :end_hour, + :ticket_layout, :organization, presence: true validates :short_title, uniqueness: true @@ -73,6 +74,8 @@ class Conference < ActiveRecord::Base after_create :create_free_ticket after_update :delete_event_schedules + enum ticket_layout: [:portrait, :landscape] + ## # Checks if the user is registered to the conference # diff --git a/app/views/admin/conferences/edit.html.haml b/app/views/admin/conferences/edit.html.haml index 5aa717ea..2d5df126 100644 --- a/app/views/admin/conferences/edit.html.haml +++ b/app/views/admin/conferences/edit.html.haml @@ -17,6 +17,7 @@ = image_tag @conference.picture.thumb.url = f.input :picture, label: false, hint: 'This will be displayed on the front page.' = f.hidden_field :picture_cache + = f.input :ticket_layout, as: :select, collection: Conference.ticket_layouts.keys, hint: "Layout type for tickets of the conference." = f.inputs name: 'Scheduling' do = f.input :timezone, as: :time_zone, hint: 'The conference time zone' = f.input :start_date, as: :string, input_html: { id: 'conference-start-datepicker', readonly: 'readonly' } diff --git a/app/views/physical_ticket/show.pdf.prawn b/app/views/physical_ticket/show.pdf.prawn index 90f11fd5..92206baf 100644 --- a/app/views/physical_ticket/show.pdf.prawn +++ b/app/views/physical_ticket/show.pdf.prawn @@ -1,4 +1,4 @@ -prawn_document(filename: @file_name, page_layout: :portrait, :page_size =>'A4' ) do |pdf| +prawn_document(filename: @file_name, page_layout: @ticket_layout, :page_size =>'A4' ) do |pdf| # Vertical Layout top = pdf.bounds.top bottom = pdf.bounds.bottom diff --git a/db/migrate/20170629232817_add_ticket_layout_to_conferences.rb b/db/migrate/20170629232817_add_ticket_layout_to_conferences.rb new file mode 100644 index 00000000..c07f85c3 --- /dev/null +++ b/db/migrate/20170629232817_add_ticket_layout_to_conferences.rb @@ -0,0 +1,5 @@ +class AddTicketLayoutToConferences < ActiveRecord::Migration + def change + add_column :conferences, :ticket_layout, :integer, default: 0 + end +end diff --git a/db/schema.rb b/db/schema.rb index 2e2fb088..4a9cc724 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -105,6 +105,7 @@ ActiveRecord::Schema.define(version: 20170629162450) do t.integer "start_hour", default: 9 t.integer "end_hour", default: 20 t.integer "organization_id" + t.integer "ticket_layout", default: 0 end add_index "conferences", ["organization_id"], name: "index_conferences_on_organization_id" diff --git a/spec/controllers/physical_ticket_controller_spec.rb b/spec/controllers/physical_ticket_controller_spec.rb new file mode 100644 index 00000000..7a430479 --- /dev/null +++ b/spec/controllers/physical_ticket_controller_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe PhysicalTicketController do + let(:conference) { create(:conference) } + let(:user) { create(:user) } + let(:paid_ticket_purchase) { create(:ticket_purchase, conference: conference, user: user) } + let(:physical_ticket) { create(:physical_ticket, ticket_purchase: paid_ticket_purchase) } + + describe 'GET #show' do + before :each do + sign_in user + get :show, id: physical_ticket.id, conference_id: conference.short_title + end + + it 'assigns ticket_layout' do + ticket_layout = conference.ticket_layout.to_sym + expect(assigns(:ticket_layout)).to eq ticket_layout + end + end +end diff --git a/spec/factories/conferences.rb b/spec/factories/conferences.rb index e1ef7d84..1e4d8551 100644 --- a/spec/factories/conferences.rb +++ b/spec/factories/conferences.rb @@ -10,6 +10,7 @@ FactoryGirl.define do start_hour 9 end_hour 20 registration_limit 0 + ticket_layout 'portrait' description { Faker::Hipster.paragraph } organization after(:create) do |conference| diff --git a/spec/models/conference_spec.rb b/spec/models/conference_spec.rb index d6e4f485..eaef9293 100755 --- a/spec/models/conference_spec.rb +++ b/spec/models/conference_spec.rb @@ -1573,6 +1573,10 @@ describe Conference do should validate_presence_of(:end_hour) end + it 'is not valid without a ticket_layout' do + should validate_presence_of(:ticket_layout) + end + it 'is not valid with a duplicate short title' do should validate_uniqueness_of(:short_title) end From 4c957a8b17d9822291f5fe854dd9a2f15e147988 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Fri, 7 Jul 2017 02:35:40 +0530 Subject: [PATCH 067/237] Updated Paper Trail --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index a493c113..89d52471 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -323,7 +323,7 @@ GEM rack-openid (~> 1.3.1) open4 (1.3.4) orm_adapter (0.5.0) - paper_trail (5.0.1) + paper_trail (5.2.1) activerecord (>= 3.0, < 6.0) activesupport (>= 3.0, < 6.0) request_store (~> 1.1) From 1ba797bead3bd3c9daaad7fd1f69d9601428d38a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A1n=20Schmidt?= Date: Sat, 8 Jul 2017 18:45:38 +0200 Subject: [PATCH 068/237] Fix schema.rb In #1570, db/schema.rb got broken, as the version was not updated. --- db/schema.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/schema.rb b/db/schema.rb index 4a9cc724..6608495b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170629162450) do +ActiveRecord::Schema.define(version: 20170629232817) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" From 9c6286182ef8c9b33f6a170e2b2cf989eb71f4ef Mon Sep 17 00:00:00 2001 From: shlok007 Date: Thu, 29 Dec 2016 03:17:33 -0500 Subject: [PATCH 069/237] caching comment counts --- app/models/comment.rb | 2 +- app/views/admin/events/index.html.haml | 2 +- ...1229080315_add_comments_count_to_events.rb | 10 ++++++++ db/schema.rb | 1 + spec/models/event_spec.rb | 23 +++++++++++++++++++ 5 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20161229080315_add_comments_count_to_events.rb diff --git a/app/models/comment.rb b/app/models/comment.rb index 947b2f54..4bb90719 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -8,7 +8,7 @@ class Comment < ActiveRecord::Base # want user to vote on the quality of comments. #acts_as_votable - belongs_to :commentable, polymorphic: true + belongs_to :commentable, counter_cache: true, polymorphic: true # NOTE: Comments belong to a user belongs_to :user diff --git a/app/views/admin/events/index.html.haml b/app/views/admin/events/index.html.haml index 0e204c87..50d7acd5 100644 --- a/app/views/admin/events/index.html.haml +++ b/app/views/admin/events/index.html.haml @@ -184,4 +184,4 @@ %ul.dropdown-menu{ role: 'menu' } = render 'change_state_dropdown', event: event %td.text-center - = link_to "#{event.comment_threads.count}", admin_conference_program_event_path(@conference.short_title, event), anchor: 'comments-div' + = link_to "#{event.comments_count}", admin_conference_program_event_path(@conference.short_title, event), anchor: 'comments-div' diff --git a/db/migrate/20161229080315_add_comments_count_to_events.rb b/db/migrate/20161229080315_add_comments_count_to_events.rb new file mode 100644 index 00000000..e1d6ebec --- /dev/null +++ b/db/migrate/20161229080315_add_comments_count_to_events.rb @@ -0,0 +1,10 @@ +class AddCommentsCountToEvents < ActiveRecord::Migration + def change + add_column :events, :comments_count, :integer, default: 0, null: false + + Event.find_each do |event| + comments_count = event.comment_threads.count + event.update_attribute(:comments_count, comments_count) unless comments_count.zero? + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 6608495b..9f0f9ff5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -242,6 +242,7 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.boolean "is_highlight", default: false t.integer "program_id" t.integer "max_attendees" + t.integer "comments_count", default: 0, null: false end create_table "events_registrations", force: :cascade do |t| diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index e1c2297c..b723d151 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -98,6 +98,29 @@ describe Event do end end + describe '#comments_count' do + context 'has a valid counter cache' do + before do + create(:comment, commentable: event) + end + + it 'successfully increments comments_count' do + expected = expect do + create(:comment, commentable: event) + end + expected.to change { event.comments_count }.by(1) + end + + it 'successfully decrements comments_count' do + expected = expect do + event.comment_threads.last.destroy + event.reload + end + expected.to change { event.comments_count }.by(-1) + end + end + end + describe 'scope ' do context 'confirmed' do it 'returns only confirmed events' do From 518ecc3d4ef53a95a8ac52e66f0e5f9879f0579f Mon Sep 17 00:00:00 2001 From: shlok007 Date: Sun, 9 Jul 2017 01:29:15 +0530 Subject: [PATCH 070/237] rebuild schema.rb for sqlite3 --- db/schema.rb | 51 ++++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 9f0f9ff5..7a640259 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -13,20 +13,17 @@ ActiveRecord::Schema.define(version: 20170629232817) do - # These are extensions that must be enabled in order to support this database - enable_extension "plpgsql" - create_table "ahoy_events", force: :cascade do |t| - t.integer "visit_id" + t.uuid "visit_id", limit: 16 t.integer "user_id" t.string "name" t.text "properties" t.datetime "time" end - add_index "ahoy_events", ["time"], name: "index_ahoy_events_on_time", using: :btree - add_index "ahoy_events", ["user_id"], name: "index_ahoy_events_on_user_id", using: :btree - add_index "ahoy_events", ["visit_id"], name: "index_ahoy_events_on_visit_id", using: :btree + add_index "ahoy_events", ["time"], name: "index_ahoy_events_on_time" + add_index "ahoy_events", ["user_id"], name: "index_ahoy_events_on_user_id" + add_index "ahoy_events", ["visit_id"], name: "index_ahoy_events_on_visit_id" create_table "answers", force: :cascade do |t| t.string "title" @@ -69,9 +66,9 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.integer "rgt" end - add_index "comments", ["commentable_id"], name: "index_comments_on_commentable_id", using: :btree - add_index "comments", ["commentable_type"], name: "index_comments_on_commentable_type", using: :btree - add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree + add_index "comments", ["commentable_id"], name: "index_comments_on_commentable_id" + add_index "comments", ["commentable_type"], name: "index_comments_on_commentable_type" + add_index "comments", ["user_id"], name: "index_comments_on_user_id" create_table "commercials", force: :cascade do |t| t.string "commercial_id" @@ -142,7 +139,7 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.datetime "updated_at" end - add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree + add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority" create_table "difficulty_levels", force: :cascade do |t| t.string "title" @@ -195,10 +192,10 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.datetime "updated_at", null: false end - add_index "event_schedules", ["event_id", "schedule_id"], name: "index_event_schedules_on_event_id_and_schedule_id", unique: true, using: :btree - add_index "event_schedules", ["event_id"], name: "index_event_schedules_on_event_id", using: :btree - add_index "event_schedules", ["room_id"], name: "index_event_schedules_on_room_id", using: :btree - add_index "event_schedules", ["schedule_id"], name: "index_event_schedules_on_schedule_id", using: :btree + add_index "event_schedules", ["event_id", "schedule_id"], name: "index_event_schedules_on_event_id_and_schedule_id", unique: true + add_index "event_schedules", ["event_id"], name: "index_event_schedules_on_event_id" + add_index "event_schedules", ["room_id"], name: "index_event_schedules_on_room_id" + add_index "event_schedules", ["schedule_id"], name: "index_event_schedules_on_schedule_id" create_table "event_types", force: :cascade do |t| t.string "title", null: false @@ -313,7 +310,7 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.integer "schedule_interval", default: 15, null: false end - add_index "programs", ["selected_schedule_id"], name: "index_programs_on_selected_schedule_id", using: :btree + add_index "programs", ["selected_schedule_id"], name: "index_programs_on_selected_schedule_id" create_table "qanswers", force: :cascade do |t| t.integer "question_id" @@ -385,8 +382,8 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.string "resource_type" end - add_index "roles", ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree - add_index "roles", ["name"], name: "index_roles_on_name", using: :btree + add_index "roles", ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id" + add_index "roles", ["name"], name: "index_roles_on_name" create_table "rooms", force: :cascade do |t| t.string "guid", null: false @@ -401,7 +398,7 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.datetime "updated_at", null: false end - add_index "schedules", ["program_id"], name: "index_schedules_on_program_id", using: :btree + add_index "schedules", ["program_id"], name: "index_schedules_on_program_id" create_table "splashpages", force: :cascade do |t| t.integer "conference_id" @@ -525,17 +522,17 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.boolean "is_disabled", default: false end - add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree - add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree - add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree - add_index "users", ["username"], name: "index_users_on_username", unique: true, using: :btree + add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true + add_index "users", ["email"], name: "index_users_on_email", unique: true + add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true + add_index "users", ["username"], name: "index_users_on_username", unique: true create_table "users_roles", force: :cascade do |t| t.integer "role_id" t.integer "user_id" end - add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree + add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id" create_table "vchoices", force: :cascade do |t| t.integer "vday_id" @@ -579,10 +576,10 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.integer "conference_id" end - add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id", using: :btree + add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id" create_table "visits", force: :cascade do |t| - t.uuid "visitor_id" + t.uuid "visitor_id", limit: 16 t.string "ip" t.text "user_agent" t.text "referrer" @@ -604,7 +601,7 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.datetime "started_at" end - add_index "visits", ["user_id"], name: "index_visits_on_user_id", using: :btree + add_index "visits", ["user_id"], name: "index_visits_on_user_id" create_table "votes", force: :cascade do |t| t.integer "event_id" From b33e9ed28ee444f45e5bac2f9e1761fe896784ea Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 4 Jan 2017 22:27:46 -0500 Subject: [PATCH 071/237] fix revision count and drop observers --- Gemfile | 3 --- Gemfile.lock | 3 --- app/models/concerns/revision_count.rb | 11 ++++++++ app/models/conference.rb | 10 +++++++ app/models/event.rb | 5 ++++ app/models/revision_observer.rb | 26 ------------------ app/models/room.rb | 5 ++++ app/models/track.rb | 5 ++++ config/application.rb | 1 - ...1_add_default_to_revision_in_conference.rb | 5 ++++ db/schema.rb | 2 +- spec/models/conference_spec.rb | 27 +++++++++++++++++++ 12 files changed, 69 insertions(+), 34 deletions(-) create mode 100644 app/models/concerns/revision_count.rb delete mode 100644 app/models/revision_observer.rb create mode 100644 db/migrate/20170108053041_add_default_to_revision_in_conference.rb diff --git a/Gemfile b/Gemfile index e6245e78..1af89f34 100644 --- a/Gemfile +++ b/Gemfile @@ -22,9 +22,6 @@ gem 'responders', '~> 2.0' gem 'mysql2' # gem 'pg' -# for observing records -gem 'rails-observers' - # for tracking data changes gem 'paper_trail' diff --git a/Gemfile.lock b/Gemfile.lock index 89d52471..9ea214c2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -399,8 +399,6 @@ GEM rails-i18n (4.0.8) i18n (~> 0.7) railties (~> 4.0) - rails-observers (0.1.2) - activemodel (~> 4.0) rails_12factor (0.0.3) rails_serve_static_assets rails_stdout_logging @@ -632,7 +630,6 @@ DEPENDENCIES rails-assets-trianglify! rails-assets-waypoints! rails-i18n (~> 4.0.0) - rails-observers rails_12factor rdoc-generator-fivefish redcarpet diff --git a/app/models/concerns/revision_count.rb b/app/models/concerns/revision_count.rb new file mode 100644 index 00000000..71789f34 --- /dev/null +++ b/app/models/concerns/revision_count.rb @@ -0,0 +1,11 @@ +module RevisionCount + extend ActiveSupport::Concern + + included do + after_update :increment_revision + end + + def increment_revision + conference.update_column(:revision, conference.revision + 1) + end +end diff --git a/app/models/conference.rb b/app/models/conference.rb index cf94b334..69571dc9 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -1,4 +1,5 @@ class Conference < ActiveRecord::Base + include RevisionCount require 'uri' serialize :events_per_week, Hash # Needed to call 'Conference.with_role' in /models/ability.rb @@ -734,6 +735,15 @@ class Conference < ActiveRecord::Base (start_hour..(end_hour - 1)).cover?(current_hour) ? current_hour - start_hour : 0 end + ## + # Return the current conference object to be used in RevisionCount + # + # ====Returns + # * +ActiveRecord+ + def conference + self + end + private # Returns a different html colour for every i and consecutive colors are diff --git a/app/models/event.rb b/app/models/event.rb index f8f9c2d8..8436aac9 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,5 +1,6 @@ class Event < ActiveRecord::Base include ActiveRecord::Transitions + include RevisionCount has_paper_trail on: [:create, :update], ignore: [:updated_at, :guid, :week], meta: { conference_id: :conference_id } acts_as_commentable @@ -251,6 +252,10 @@ class Event < ActiveRecord::Base event_schedules.find_by(schedule_id: program.selected_schedule_id).try(:start_time) end + def conference + program.conference + end + private ## diff --git a/app/models/revision_observer.rb b/app/models/revision_observer.rb deleted file mode 100644 index 4d2784f4..00000000 --- a/app/models/revision_observer.rb +++ /dev/null @@ -1,26 +0,0 @@ -# -# suseconferenceclient relies on a 'revision' attribute for caching and -# doing some calculations. -# -# It should be incremented after any change in the conference or in any -# associated models -# -# This observer updates the revision column in a non-intrusive way, -# preventing validations, callbacks or exceptions to be triggered -# -# Relying on paper_trail could also be an option, but a 'revision' column -# in table 'conferences' looks like a more simple and straightforward solution -# -class RevisionObserver < ActiveRecord::Observer - observe :conference, :event, :room, :track - - def after_save(model) - begin - conference = model.kind_of?(Conference) ? model : model.conference - conference.reload.increment(:revision) - conference.update_column(:revision, conference.revision) - rescue - nil - end - end -end diff --git a/app/models/room.rb b/app/models/room.rb index 1477a2c6..f8150f78 100644 --- a/app/models/room.rb +++ b/app/models/room.rb @@ -1,4 +1,5 @@ class Room < ActiveRecord::Base + include RevisionCount belongs_to :venue has_many :event_schedules, dependent: :destroy @@ -10,6 +11,10 @@ class Room < ActiveRecord::Base validates :size, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true + def conference + venue.conference + end + private def generate_guid diff --git a/app/models/track.rb b/app/models/track.rb index d3502bb0..f65506d8 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -1,4 +1,5 @@ class Track < ActiveRecord::Base + include RevisionCount belongs_to :program has_many :events, dependent: :nullify @@ -16,6 +17,10 @@ class Track < ActiveRecord::Base before_validation :capitalize_color + def conference + program.conference + end + private def generate_guid diff --git a/config/application.rb b/config/application.rb index 9123e5bb..07ba40f3 100644 --- a/config/application.rb +++ b/config/application.rb @@ -25,7 +25,6 @@ module Osem # Activate observers that should always be running. # config.active_record.observers = :cacher, :garbage_collector, :forum_observer - config.active_record.observers = :revision_observer # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. diff --git a/db/migrate/20170108053041_add_default_to_revision_in_conference.rb b/db/migrate/20170108053041_add_default_to_revision_in_conference.rb new file mode 100644 index 00000000..1c3571de --- /dev/null +++ b/db/migrate/20170108053041_add_default_to_revision_in_conference.rb @@ -0,0 +1,5 @@ +class AddDefaultToRevisionInConference < ActiveRecord::Migration + def change + change_column :conferences, :revision, :integer, default: 0, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 7a640259..af227946 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -90,7 +90,7 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.datetime "created_at" t.datetime "updated_at" t.string "logo_file_name" - t.integer "revision" + t.integer "revision", default: 0, null: false t.boolean "use_vpositions", default: false t.boolean "use_vdays", default: false t.boolean "use_volunteers" diff --git a/spec/models/conference_spec.rb b/spec/models/conference_spec.rb index eaef9293..89863412 100755 --- a/spec/models/conference_spec.rb +++ b/spec/models/conference_spec.rb @@ -1660,4 +1660,31 @@ describe Conference do expect{ conference.save }.to change{ EventSchedule.count }.from(2).to(1) end end + + describe '#revision' do + let(:track) { create(:track, program: subject.program) } + let(:event) { create(:event, program: subject.program, track: track) } + let(:venue) { create(:venue, conference: subject) } + let(:room) { create(:room, venue: venue) } + + it 'for change in conference' do + subject.title = 'changed' + expect{ subject.save }.to change { subject.revision }.by(1) + end + + it 'for change in event' do + event.title = 'changed' + expect{ event.save }.to change { subject.revision }.by(1) + end + + it 'for change in track' do + track.name = 'changed' + expect{ track.save }.to change { subject.revision }.by(1) + end + + it 'for change in room' do + room.name = 'changed' + expect{ room.save }.to change { subject.revision }.by(1) + end + end end From f15fe9ddb0cc5422b777d4ef299b043af7e6a75f Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Sat, 25 Mar 2017 22:51:21 +0100 Subject: [PATCH 072/237] Docker support for production use This commit adds a Docker infrastructure that is ready for production use. It is meant to simplify the deployment of OSEM for everyone who wants to host their own instances. It includes many features like data persistence, automatic secret key generation and persistence and automatic database initialization and upgrading. This should make updating the Docker container as easy as possible. --- .dockerignore | 2 ++ Dockerfile | 46 ++++++++++++++++++++++++++++++++++++++ config/database.yml.docker | 7 ++++++ docker-compose.env.example | 38 +++++++++++++++++++++++++++++++ docker-compose.yml.example | 29 ++++++++++++++++++++++++ docker/init.sh | 45 +++++++++++++++++++++++++++++++++++++ 6 files changed, 167 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 config/database.yml.docker create mode 100644 docker-compose.env.example create mode 100644 docker-compose.yml.example create mode 100644 docker/init.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..e235b236 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +Dockerfile +docker-compose.* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..86a6d4d1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,46 @@ +FROM ruby:2.3 + +MAINTAINER TheAssassin + +# required for compiling assets +RUN apt-get update && \ + apt-get install -y nodejs nodejs-legacy mariadb-client + +# used to run the container without root permissions +RUN adduser --home /osem/ --system --group --disabled-login --disabled-password osem + +# required to detect when the database is up and running in init.sh +RUN cd /usr/bin && \ + wget https://github.com/jwilder/dockerize/releases/download/v0.3.0/dockerize-linux-amd64-v0.3.0.tar.gz -O dockerize.tar.gz && \ + echo "36e8319cdf9d2b07340f456ec61cfa0f495ec6c130b02ad9c116fd55a5c43fa1 dockerize.tar.gz" | sha256sum -c && \ + tar -xf dockerize.tar.gz && \ + rm dockerize.tar.gz + +# explicitly add Gemfile and install dependencies using bundler to make use of +# Docker's caching +WORKDIR /osem/ +RUN gem install puma +COPY Gemfile /osem/ +COPY Gemfile.lock /osem/ +RUN bundle install --without test development + +# add OSEM files and prepare them for use inside a Docker container +COPY . /osem/ +RUN chown osem.osem /osem/ -R && \ + mv /osem/config/database.yml.docker /osem/config/database.yml + +# data directory is used to cache the secret key in a file +ENV DATA_DIR /data +RUN install -d -m 0700 -o osem $DATA_DIR +VOLUME ["$DATA_DIR"] + +USER osem +EXPOSE 9292 + +COPY docker/init.sh /init.sh + +# a user could override this if they wanted to serve the static files directly +# from a webserver +ENV RAILS_SERVE_STATIC_FILES 1 + +CMD ["bash", "/init.sh"] diff --git a/config/database.yml.docker b/config/database.yml.docker new file mode 100644 index 00000000..60ef8947 --- /dev/null +++ b/config/database.yml.docker @@ -0,0 +1,7 @@ +production: + adapter: mysql2 + host: <%= ENV['DATABASE_HOST'] %> + port: <%= ENV['DATABASE_PORT'] %> + username: <%= ENV['MYSQL_USER'] %> + password: <%= ENV['MYSQL_PASSWORD'] %> + database: <%= ENV['MYSQL_DATABASE'] %> diff --git a/docker-compose.env.example b/docker-compose.env.example new file mode 100644 index 00000000..911b8062 --- /dev/null +++ b/docker-compose.env.example @@ -0,0 +1,38 @@ +## database related variables ## + +# variables prefixed with MYSQL_ are used by both database and web containers +# variables prefixed with DATABASE_ are used exlusively by the web container + +MYSQL_DATABASE=osem +MYSQL_USER=osem +MYSQL_PASSWORD=changemeimmediately +MYSQL_ROOT_PASSWORD=changemeevenmoreimmediately + +# the following settings should not be modified unless the database service +# is renamed in docker-compose.yml or you plan to use an external database +DATABASE_HOST=database +DATABASE_PORT=3306 + + +## OSEM options ## +# you can configure any option described in this document here instead of +# having to create a .env file: +# https://github.com/openSUSE/osem/blob/master/dotenv.example + +OSEM_NAME=Dockerized OSEM +OSEM_HOSTNAME=http://localhost:9292 +OSEM_ERRBIT_HOST=localhost +SECRET_KEY_BASE=changemechangemechangeme + +# these settings work for the MailHog server that is enabled by default in +# docker-compose.yml +# if you do not plan to use MailHog (you most likely don't want to), you need +# to change these settings to use an external working mailserver, otherwise +# your users are going to see the HTTP status 500 page +# you should comment out or remove the mailhog service from docker-compose.yml, +# too +OSEM_EMAIL_ADDRESS=osem@mailhog +OSEM_SMTP_ADDRESS=mailhog +OSEM_SMTP_PORT=1025 +OSEM_SMTP_USERNAME=mailhog +OSEM_SMTP_PASSWORD=mailhog diff --git a/docker-compose.yml.example b/docker-compose.yml.example new file mode 100644 index 00000000..0959523c --- /dev/null +++ b/docker-compose.yml.example @@ -0,0 +1,29 @@ +version: "2" + +services: + database: + image: mariadb:10.1 + env_file: docker-compose.env + volumes: + - database:/var/lib/mysql + + mailhog: + image: mailhog/mailhog:latest + ports: + - "127.0.0.1:8025:8025" + + web: + build: . + env_file: docker-compose.env + depends_on: + - database + - mailhog + ports: + - "127.0.0.1:9292:9292" + volumes: + - "web:/data" + +# these named volumes are used to persist data +volumes: + database: + web: diff --git a/docker/init.sh b/docker/init.sh new file mode 100644 index 00000000..36601e6c --- /dev/null +++ b/docker/init.sh @@ -0,0 +1,45 @@ +#! /bin/bash + +set -e + +# data directory is required for caching the secret key in a file +if [ "$DATA_DIR" == "" ]; then + echo -n "Error: DATA_DIR environment variable not set!" + echo "Are you sure you are running this script in a Docker container?" + exit 1 +fi + +SECRET_KEY_FILE="$DATA_DIR/secret_key" + +if [ ! -f "$SECRET_KEY_FILE" ]; then + install -m 0600 /dev/null "$SECRET_KEY_FILE" + SECRET_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 100 | head -n 1) + echo "$key" > "$SECRET_KEY_FILE" + chmod -w "$SECRET_KEY_FILE" +else + SECRET_KEY=$(cat "$SECRET_KEY_FILE") +fi + +export SECRET_KEY +export RAILS_ENV=production + +install -m 0600 /dev/null .my.cnf +cat > .my.cnf <>> Initializing database..." + dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s bundle exec rake db:schema:load +fi + +echo ">>> Upgrading database..." +dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s bundle exec rake db:migrate + +echo ">>> Precompiling assets..." +bundle exec rake assets:precompile + +echo ">>> Starting application server..." +exec puma -e production From 8229cca1e83ec5222ab3c44beccd169adbaeb0e3 Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Fri, 31 Mar 2017 13:33:03 +0200 Subject: [PATCH 073/237] Add missing dependency to Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 86a6d4d1..0e7a70aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER TheAssassin # required for compiling assets RUN apt-get update && \ - apt-get install -y nodejs nodejs-legacy mariadb-client + apt-get install -y nodejs nodejs-legacy mariadb-client imagemagick # used to run the container without root permissions RUN adduser --home /osem/ --system --group --disabled-login --disabled-password osem From 9402eb36d85530b3c1f4da3d7a53b8283fb48e04 Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Fri, 31 Mar 2017 13:33:24 +0200 Subject: [PATCH 074/237] Add beginner guide for deploying OSEM with Docker --- INSTALL.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/INSTALL.md b/INSTALL.md index 9cbfafcc..6307b7ae 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -11,7 +11,9 @@ OSEM is an [semantic versioned](http://semver.org/) app. That means given a vers ## Download You can find the latest OSEM releases on our [release page](https://github.com/openSUSE/osem/releases/latest) ([older release here](https://github.com/openSUSE/osem/releases)) + ## Deploy + OSEM is a *Ruby on Rails* application. We recommend to run OSEM in production with [mod_passenger](https://www.phusionpassenger.com/download/#open_source) and the [apache web-server](https://www.apache.org/). There are tons of guides on how to deploy rails apps on various base operating systems. [Check Google](https://encrypted.google.com/search?hl=en&q=ruby%20on%20rails%20apache%20passenger) ;-) @@ -24,6 +26,53 @@ If you have an heroku account you can also Deploy +### Deploy with Docker + +You can deploy OSEM using [Docker](https://docker.com/) and [Docker-Compose](https://docs.docker.com/compose/overview/). + +*This is just a short guide and does not explain how to use Docker and/or Docker-Compose. You need some experience with these tools to be able to deploy OSEM with Docker properly.* + +First of all, copy `docker-compose.yml.example` to `docker-compose.yml` and `docker-compose.env.example` to `docker-compose.env`. + +There are two configurations to deploy OSEM with Docker: *evaluation mode* and *production mode*. + +#### Evaluation mode + +If you want to evaluate OSEM to see if it fits your needs, the default configuration in `docker-compose.env` will work perfectly fine for you. +For convenience reasons, `docker-compose.yml` already contains a [MailHog](https://github.com/mailhog/MailHog) service configuration. MailHog +is going to catch every email sent by OSEM and displays them on a special web service. Thus, it eliminitates the need to set up an SMTP server just to try out OSEM. +Just point your browser to http://localhost:8025 to get access to registration confirmation links etc. + +Run `docker-compose up --build` to start the services. On first run, it will take a few minutes to initialize the database. Thus, wait a few minutes before you open up +http://localhost:9292 in your browser. + +#### Production mode + +To deploy OSEM for production, you have to make a few changes to `docker-compose.yml`. First, remove (or comment) the `mailhog` service, as it is only useful for evaluation and +cannot be used for production. +You can change the forwarded port from port `9292` to any other value if this port is already in use or you just want to use another one. + +Next, you have to modify `docker-compose.env`. This file works as a Docker-like replacement for the regular Rails `.env` files described below. +You can configure any of the configuration values shown in the **Configure** section below in it. The most essential variables are already configured to standard +values in `docker-compose.env` which you most likely want to change. + +First, you need to modify the email related settings. You need a working SMTP server for OSEM to send out registration confirmation mails etc. + +For security reasons, the following variables have to be changed, too: + + - `MYSQL_PASSWORD` + - `MYSQL_ROOT_PASSWORD` + - `SECRET_KEY_BASE` + +These variables need to be set to the correct values at first, as they are used to initialize everything. Modification of these variables after installation and initialization is more +complicated and out of this document's scope. + +As with any other Docker-Compose configuration, run `docker-compose up --build` (or `docker-compose up --build -d` to run in background) to start the services. During the first +start, the database has to be initialized which can take several minutes. The web service is by default exposed on localhost only as it is intended to be served by a reverse proxy (for SSL +termination, caching etc.). +You should not directly expose the web server port unless you have a good reason to do so. + + ## Configure There are a couple of environment variables you can set to configure OSEM. Check out the *dotenv.example* file. From 2c3c070f7e20bea9d932a99c783ccc5beba56e1f Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Sat, 1 Apr 2017 00:48:22 +0200 Subject: [PATCH 075/237] Update Docker docs --- INSTALL.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 6307b7ae..29dc5cec 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -32,7 +32,9 @@ You can deploy OSEM using [Docker](https://docker.com/) and [Docker-Compose](htt *This is just a short guide and does not explain how to use Docker and/or Docker-Compose. You need some experience with these tools to be able to deploy OSEM with Docker properly.* -First of all, copy `docker-compose.yml.example` to `docker-compose.yml` and `docker-compose.env.example` to `docker-compose.env`. +First of all, copy `docker-compose.yml.example` to `docker-compose.yml` and `docker-compose.env.example` to `docker-compose.env`. You should immediately change +`docker-compose.env`'s permissions to `0600` to make sure all the passphrases in it are kept secret. +(Tip: the easiest and most secure way to do it is to do it with a single command, for example `install -m 0600 docker-compose.env.example docker-compose.env`). There are two configurations to deploy OSEM with Docker: *evaluation mode* and *production mode*. From 28d9ac9b1fb37400133cad675ab3b822e66a02a8 Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Sat, 1 Apr 2017 01:13:39 +0200 Subject: [PATCH 076/237] Switch to built in rails server --- Dockerfile | 1 - docker/init.sh | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0e7a70aa..dab432ca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,6 @@ RUN cd /usr/bin && \ # explicitly add Gemfile and install dependencies using bundler to make use of # Docker's caching WORKDIR /osem/ -RUN gem install puma COPY Gemfile /osem/ COPY Gemfile.lock /osem/ RUN bundle install --without test development diff --git a/docker/init.sh b/docker/init.sh index 36601e6c..4d71ec77 100644 --- a/docker/init.sh +++ b/docker/init.sh @@ -42,4 +42,4 @@ echo ">>> Precompiling assets..." bundle exec rake assets:precompile echo ">>> Starting application server..." -exec puma -e production +exec bundle exec rails server -e production -p 9292 From 769643a642c6161c72459cbdbdf5f687a54181af Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Sat, 1 Apr 2017 01:16:30 +0200 Subject: [PATCH 077/237] Remove MySQL config file again as soon as possible --- docker/init.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/init.sh b/docker/init.sh index 4d71ec77..be418b9e 100644 --- a/docker/init.sh +++ b/docker/init.sh @@ -38,6 +38,8 @@ fi echo ">>> Upgrading database..." dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s bundle exec rake db:migrate +rm .my.cnf + echo ">>> Precompiling assets..." bundle exec rake assets:precompile From d7765bf4fdaa33f9db3ece41d65e761ccef26ace Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Sat, 1 Apr 2017 01:16:51 +0200 Subject: [PATCH 078/237] Update ignores --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4d5fd427..37bd6b81 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ pickle-email-*.html .env.development .env.test .env.local +docker-compose.{env,yml} From c592a19f2deb8b7ec25f6bf2ba13370595c728a8 Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Tue, 4 Apr 2017 07:32:33 +0200 Subject: [PATCH 079/237] Use rails secret to generate the secret key --- docker/init.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/init.sh b/docker/init.sh index be418b9e..81ab11b5 100644 --- a/docker/init.sh +++ b/docker/init.sh @@ -12,8 +12,9 @@ fi SECRET_KEY_FILE="$DATA_DIR/secret_key" if [ ! -f "$SECRET_KEY_FILE" ]; then + echo ">>> Creating a new secret key file..." install -m 0600 /dev/null "$SECRET_KEY_FILE" - SECRET_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 100 | head -n 1) + SECRET_KEY=$(bundle exec rails secret) echo "$key" > "$SECRET_KEY_FILE" chmod -w "$SECRET_KEY_FILE" else From dd993b74481e158bee3a7105ca85bdb01e5f61fe Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Tue, 16 May 2017 22:16:46 +0200 Subject: [PATCH 080/237] Fix issue mentioned in osem/pull/1407 After the rebase (to update the PR with the latest changes), I had the same issue @lguerard has had. I noticed that the rails server didn't lisen on all interfaces any more, but bound the port to the loopback device only. By adding the parameter `-b 0.0.0.0`, I restored the previous behavior, and OSEM could be reached with the browser after it started up (takes a few seconds). --- docker/init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/init.sh b/docker/init.sh index 81ab11b5..8f1ba766 100644 --- a/docker/init.sh +++ b/docker/init.sh @@ -45,4 +45,4 @@ echo ">>> Precompiling assets..." bundle exec rake assets:precompile echo ">>> Starting application server..." -exec bundle exec rails server -e production -p 9292 +exec bundle exec rails server -e production -b 0.0.0.0 -p 9292 From b5ca626873cd6d4c95c481238b9f117203fe4de2 Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Sun, 9 Jul 2017 15:47:24 +0200 Subject: [PATCH 081/237] Fix Git ignores --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 37bd6b81..75a1bdc6 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,5 @@ pickle-email-*.html .env.development .env.test .env.local -docker-compose.{env,yml} +docker-compose.env +docker-compose.yml From ad9ef4aba36710f9c032a5473e96fd782b983d8b Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Sun, 9 Jul 2017 15:48:09 +0200 Subject: [PATCH 082/237] Fix secret key generation --- docker/init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/init.sh b/docker/init.sh index 8f1ba766..aedb0874 100644 --- a/docker/init.sh +++ b/docker/init.sh @@ -14,7 +14,7 @@ SECRET_KEY_FILE="$DATA_DIR/secret_key" if [ ! -f "$SECRET_KEY_FILE" ]; then echo ">>> Creating a new secret key file..." install -m 0600 /dev/null "$SECRET_KEY_FILE" - SECRET_KEY=$(bundle exec rails secret) + SECRET_KEY=$(bundle exec rake secret) echo "$key" > "$SECRET_KEY_FILE" chmod -w "$SECRET_KEY_FILE" else From 13d6bf471da363a2901009aa60781c0a5339e13e Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Sun, 9 Jul 2017 15:54:51 +0200 Subject: [PATCH 083/237] Wait for database to be started before running MySQL client command --- docker/init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/init.sh b/docker/init.sh index aedb0874..16a55231 100644 --- a/docker/init.sh +++ b/docker/init.sh @@ -31,7 +31,7 @@ user=$MYSQL_USER password=$MYSQL_PASSWORD ABC -if [ $(echo "show tables;" | mysql --host $DATABASE_HOST --port $DATABASE_PORT $MYSQL_DATABASE | wc -l) -le 1 ]; then +if [ $(echo "show tables;" | dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s mysql --host $DATABASE_HOST --port $DATABASE_PORT $MYSQL_DATABASE | wc -l) -le 1 ]; then echo ">>> Initializing database..." dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s bundle exec rake db:schema:load fi From 6dea37ec413630ad45dace2891294942eccd9061 Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Sun, 9 Jul 2017 19:57:29 +0200 Subject: [PATCH 084/237] Add missing environment variable --- docker-compose.env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.env.example b/docker-compose.env.example index 911b8062..2aedbe73 100644 --- a/docker-compose.env.example +++ b/docker-compose.env.example @@ -32,6 +32,7 @@ SECRET_KEY_BASE=changemechangemechangeme # you should comment out or remove the mailhog service from docker-compose.yml, # too OSEM_EMAIL_ADDRESS=osem@mailhog +OSEM_SMTP_AUTHENTICATION=login OSEM_SMTP_ADDRESS=mailhog OSEM_SMTP_PORT=1025 OSEM_SMTP_USERNAME=mailhog From 93d5e360ca0fbf42dba804e1bf3c71ad936f2cc9 Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Sun, 9 Jul 2017 20:55:09 +0200 Subject: [PATCH 085/237] Merge dockerize commands --- docker/init.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docker/init.sh b/docker/init.sh index 16a55231..3a2031f3 100644 --- a/docker/init.sh +++ b/docker/init.sh @@ -31,13 +31,16 @@ user=$MYSQL_USER password=$MYSQL_PASSWORD ABC -if [ $(echo "show tables;" | dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s mysql --host $DATABASE_HOST --port $DATABASE_PORT $MYSQL_DATABASE | wc -l) -le 1 ]; then +echo ">>> Waiting for database to get ready to connect..." +dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s true + +if [ $(echo "show tables;" | mysql --host $DATABASE_HOST --port $DATABASE_PORT $MYSQL_DATABASE | wc -l) -le 1 ]; then echo ">>> Initializing database..." - dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s bundle exec rake db:schema:load + bundle exec rake db:schema:load fi echo ">>> Upgrading database..." -dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s bundle exec rake db:migrate +bundle exec rake db:migrate rm .my.cnf From fbd4be3503131022fb3d037576239a8f3c64d954 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Mon, 10 Jul 2017 17:45:05 +0530 Subject: [PATCH 086/237] Ticket show page --- app/views/physical_ticket/show.html.haml | 51 ++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/app/views/physical_ticket/show.html.haml b/app/views/physical_ticket/show.html.haml index e69de29b..19b89473 100644 --- a/app/views/physical_ticket/show.html.haml +++ b/app/views/physical_ticket/show.html.haml @@ -0,0 +1,51 @@ +.container + .row + .col-md-12 + .page-header + %h1 + Ticket for + = @conference.title + %p.text-muted + - if @conference.venue + at + %strong + #{@conference.venue.name}, + #{@conference.venue.street}, + #{@conference.venue.city} / #{@conference.venue.country_name}. + %small + = date_string(@conference.start_date, @conference.end_date) + .row + .col-md-6 + - if @conference.picture? + = image_tag(@conference.picture_url, class: 'img-responsive') + - else + = image_tag('/img/osem-logo.png', class: 'img-responsive') + .col-md-6 + %address + %strong + Ticket Type + %br + = @physical_ticket.ticket.title + %br + %strong + Ticket REF. + %br + = @physical_ticket.ticket_purchase.id + %br + %strong + Organization + %br + = @conference.organization.name + %br + %strong + Transaction Date + %br + = @physical_ticket.created_at.strftime('%B %d, %Y') + .row + .col-md-12 + %p.text-right + = link_to 'Generate PDF', + conference_physical_ticket_path(@conference.short_title, + @physical_ticket.id, + format: :pdf), + class: 'button btn btn-default btn-info' From c066aadae2138961952a1495d2afa7953ef2e539 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Tue, 11 Jul 2017 17:05:07 +0530 Subject: [PATCH 087/237] Added TicketScanning Model --- app/models/physical_ticket.rb | 1 + app/models/ticket_scanning.rb | 3 +++ db/migrate/20170711102511_create_ticket_scannings.rb | 9 +++++++++ db/schema.rb | 8 +++++++- 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 app/models/ticket_scanning.rb create mode 100644 db/migrate/20170711102511_create_ticket_scannings.rb diff --git a/app/models/physical_ticket.rb b/app/models/physical_ticket.rb index a0874a6e..6142c875 100644 --- a/app/models/physical_ticket.rb +++ b/app/models/physical_ticket.rb @@ -3,4 +3,5 @@ class PhysicalTicket < ActiveRecord::Base has_one :ticket, through: :ticket_purchase has_one :conference, through: :ticket_purchase has_one :user, through: :ticket_purchase + has_many :ticket_scannings end diff --git a/app/models/ticket_scanning.rb b/app/models/ticket_scanning.rb new file mode 100644 index 00000000..6ce9d00c --- /dev/null +++ b/app/models/ticket_scanning.rb @@ -0,0 +1,3 @@ +class TicketScanning < ActiveRecord::Base + belongs_to :physical_ticket +end diff --git a/db/migrate/20170711102511_create_ticket_scannings.rb b/db/migrate/20170711102511_create_ticket_scannings.rb new file mode 100644 index 00000000..d1879f68 --- /dev/null +++ b/db/migrate/20170711102511_create_ticket_scannings.rb @@ -0,0 +1,9 @@ +class CreateTicketScannings < ActiveRecord::Migration + def change + create_table :ticket_scannings do |t| + t.integer :physical_ticket_id, null: false + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index af227946..b9f8e3f4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170629232817) do +ActiveRecord::Schema.define(version: 20170711102511) do create_table "ahoy_events", force: :cascade do |t| t.uuid "visit_id", limit: 16 @@ -468,6 +468,12 @@ ActiveRecord::Schema.define(version: 20170629232817) do t.integer "week" end + create_table "ticket_scannings", force: :cascade do |t| + t.integer "physical_ticket_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "tickets", force: :cascade do |t| t.integer "conference_id" t.string "title", null: false From 43b4204e308ffa7ffafd808d4d8a391214ae3cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mois=C3=A9s=20D=C3=A9niz=20Alem=C3=A1n?= Date: Wed, 12 Jul 2017 10:33:16 +0200 Subject: [PATCH 088/237] Revert "Ticket show page" --- app/views/physical_ticket/show.html.haml | 51 ------------------------ 1 file changed, 51 deletions(-) diff --git a/app/views/physical_ticket/show.html.haml b/app/views/physical_ticket/show.html.haml index 19b89473..e69de29b 100644 --- a/app/views/physical_ticket/show.html.haml +++ b/app/views/physical_ticket/show.html.haml @@ -1,51 +0,0 @@ -.container - .row - .col-md-12 - .page-header - %h1 - Ticket for - = @conference.title - %p.text-muted - - if @conference.venue - at - %strong - #{@conference.venue.name}, - #{@conference.venue.street}, - #{@conference.venue.city} / #{@conference.venue.country_name}. - %small - = date_string(@conference.start_date, @conference.end_date) - .row - .col-md-6 - - if @conference.picture? - = image_tag(@conference.picture_url, class: 'img-responsive') - - else - = image_tag('/img/osem-logo.png', class: 'img-responsive') - .col-md-6 - %address - %strong - Ticket Type - %br - = @physical_ticket.ticket.title - %br - %strong - Ticket REF. - %br - = @physical_ticket.ticket_purchase.id - %br - %strong - Organization - %br - = @conference.organization.name - %br - %strong - Transaction Date - %br - = @physical_ticket.created_at.strftime('%B %d, %Y') - .row - .col-md-12 - %p.text-right - = link_to 'Generate PDF', - conference_physical_ticket_path(@conference.short_title, - @physical_ticket.id, - format: :pdf), - class: 'button btn btn-default btn-info' From c5db5dba1e96e996ec902d2e51daea5df1fca917 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Mon, 10 Jul 2017 17:45:05 +0530 Subject: [PATCH 089/237] Ticket show page --- app/assets/stylesheets/osem.css.scss | 6 +- app/views/physical_ticket/show.html.haml | 77 ++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/osem.css.scss b/app/assets/stylesheets/osem.css.scss index bc8b6388..5a331436 100644 --- a/app/assets/stylesheets/osem.css.scss +++ b/app/assets/stylesheets/osem.css.scss @@ -89,4 +89,8 @@ p.comment-body { .changeset{ display: none; -} \ No newline at end of file +} + +.box{ + height: 230px; +} diff --git a/app/views/physical_ticket/show.html.haml b/app/views/physical_ticket/show.html.haml index e69de29b..26fa7853 100644 --- a/app/views/physical_ticket/show.html.haml +++ b/app/views/physical_ticket/show.html.haml @@ -0,0 +1,77 @@ +.container + .row + .col-md-12 + .page-header + %h1 + Ticket for + = @conference.title + %p.text-muted + - if @conference.venue + at + %strong + #{@conference.venue.name}, + #{@conference.venue.street}, + #{@conference.venue.city} / #{@conference.venue.country_name}. + %small + = date_string(@conference.start_date, @conference.end_date) + .row + .col-md-5.box.well + %h3.text-center + Ticket Holder + %p.text-left + %strong + Name + %br + = @user.name + %br + %br + %strong + Email + %br + = @user.email + .col-md-5.col-md-offset-2.box.well + - if @conference.picture? + - width = @conference.picture.image[:width] + - height = @conference.picture.image[:height] + - if 10 * width > 15 * height + = image_tag(@conference.picture_url, width: '150') + - else + = image_tag(@conference.picture_url, height: '100') + - else + = image_tag('/img/osem-logo.png', class: 'img-responsive') + %p.text-left + %br + %strong + Organization + %br + = @conference.organization.name + .col-md-5.box.well + %p.text-left + %strong + Event + %br + = @conference.title + %br + = @conference.start_date.strftime('%B %d, %Y') + %br + %br + %strong + Ticket + %br + = @physical_ticket.ticket.title + %br + %br + %strong + Ticket Ref. + %br + = @physical_ticket.ticket_purchase.id + %br + .col-md-5.col-md-offset-2.box.well + .row + .col-md-12 + %p.text-left + = link_to 'Generate PDF', + conference_physical_ticket_path(@conference.short_title, + @physical_ticket.id, + format: :pdf), + class: 'button btn btn-default btn-info' From eb23d838b53ce0dc61e333206a2fa24b1eb80440 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 11 Jul 2017 04:59:03 +0530 Subject: [PATCH 090/237] correct past and upcoming conferences in admin/organizations#index --- app/models/conference.rb | 2 ++ app/views/admin/organizations/index.html.haml | 4 ++-- spec/models/conference_spec.rb | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/models/conference.rb b/app/models/conference.rb index 69571dc9..68cdc186 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -7,6 +7,8 @@ class Conference < ActiveRecord::Base resourcify :roles, dependent: :delete_all default_scope { order('start_date DESC') } + scope :upcoming, (-> { where('end_date >= ?', Date.current) }) + scope :past, (-> { where('end_date < ?', Date.current) }) belongs_to :organization diff --git a/app/views/admin/organizations/index.html.haml b/app/views/admin/organizations/index.html.haml index 52e2877a..aa682c57 100644 --- a/app/views/admin/organizations/index.html.haml +++ b/app/views/admin/organizations/index.html.haml @@ -20,9 +20,9 @@ %td = organization.name %td - = organization.conferences.count + = organization.conferences.upcoming.count %td - = organization.conferences.count + = organization.conferences.past.count %td .btn-group = link_to 'Edit', edit_admin_organization_path(organization), diff --git a/spec/models/conference_spec.rb b/spec/models/conference_spec.rb index 89863412..91c06140 100755 --- a/spec/models/conference_spec.rb +++ b/spec/models/conference_spec.rb @@ -1687,4 +1687,21 @@ describe Conference do expect{ room.save }.to change { subject.revision }.by(1) end end + + describe '.upcoming' do + let!(:upcoming_conference) { create(:conference) } + let!(:past_conference) { create(:conference, start_date: Date.current - 1.days, end_date: Date.current - 1.days) } + subject { Conference.upcoming } + + it { is_expected.to eq [upcoming_conference] } + end + + describe '.past' do + let!(:upcoming_conference) { create(:conference) } + let!(:past_conference1) { create(:conference, start_date: Date.current - 1.days, end_date: Date.current - 1.days) } + let!(:past_conference2) { create(:conference, start_date: Date.current - 2.days, end_date: Date.current - 1.days) } + subject { Conference.past } + + it { is_expected.to eq [past_conference1, past_conference2] } + end end From ddf6f4b4c90954b1483fc3d6f446967795eac817 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 11 Jul 2017 03:59:52 +0530 Subject: [PATCH 091/237] fix new conference links --- app/views/layouts/_admin_sidebar.html.haml | 2 +- app/views/layouts/_admin_sidebar_index.html.haml | 2 +- app/views/layouts/_user_menu.html.haml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/layouts/_admin_sidebar.html.haml b/app/views/layouts/_admin_sidebar.html.haml index 2c3eaf52..1c7bac9a 100644 --- a/app/views/layouts/_admin_sidebar.html.haml +++ b/app/views/layouts/_admin_sidebar.html.haml @@ -16,7 +16,7 @@ %span.fa.fa-cog Manage = conference.short_title - - if (current_user.is_admin) || (current_user.has_role? :organizer, :any) + - if can? :new, Conference.new %li = link_to(new_admin_conference_path) do %span.fa.fa-plus diff --git a/app/views/layouts/_admin_sidebar_index.html.haml b/app/views/layouts/_admin_sidebar_index.html.haml index 3844339b..01356f42 100644 --- a/app/views/layouts/_admin_sidebar_index.html.haml +++ b/app/views/layouts/_admin_sidebar_index.html.haml @@ -16,7 +16,7 @@ %span.fa.fa-cog Manage = conference.short_title - - if can? :create, Conference + - if can? :new, Conference.new %li = link_to(new_admin_conference_path) do %span.fa.fa-plus diff --git a/app/views/layouts/_user_menu.html.haml b/app/views/layouts/_user_menu.html.haml index 01432b3c..38a96b08 100644 --- a/app/views/layouts/_user_menu.html.haml +++ b/app/views/layouts/_user_menu.html.haml @@ -28,10 +28,10 @@ = link_to(admin_conferences_path()) do %span.fa.fa-home Administration - - if can? :create, Conference + - if can? :new, Conference.new =link_to(new_admin_conference_path) do %span.fa.fa-plus - Create Conference + New Conference -if @conference and @conference.id and can? :show, @conference %li = link_to(admin_conference_path(@conference.short_title)) do From ea43b19ef489e5fb61ab3672483a5e589c482e1d Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 12 Jul 2017 17:34:33 +0530 Subject: [PATCH 092/237] add tests for new conference links --- spec/features/cfp_ability_spec.rb | 1 + spec/features/info_desk_ability_spec.rb | 1 + spec/features/organization_admin_ability_spec.rb | 1 + spec/features/organizer_ability_spec.rb | 1 + 4 files changed, 4 insertions(+) diff --git a/spec/features/cfp_ability_spec.rb b/spec/features/cfp_ability_spec.rb index 235dedea..7af4e119 100644 --- a/spec/features/cfp_ability_spec.rb +++ b/spec/features/cfp_ability_spec.rb @@ -46,6 +46,7 @@ feature 'Has correct abilities' do expect(page).to_not have_link('Goals', href: "/admin/conferences/#{conference.short_title}/targets") expect(page).to have_link('Roles', href: "/admin/conferences/#{conference.short_title}/roles") expect(page).to have_link('Resources', href: "/admin/conferences/#{conference.short_title}/resources") + expect(page).to_not have_link('New Conference', href: '/admin/conferences/new') visit admin_conference_venue_rooms_path(conference.short_title) expect(current_path).to eq(admin_conference_venue_rooms_path(conference.short_title)) diff --git a/spec/features/info_desk_ability_spec.rb b/spec/features/info_desk_ability_spec.rb index 7d0039fe..20aa586b 100644 --- a/spec/features/info_desk_ability_spec.rb +++ b/spec/features/info_desk_ability_spec.rb @@ -46,6 +46,7 @@ feature 'Has correct abilities' do expect(page).to have_link('Registrations', href: "/admin/conferences/#{conference.short_title}/registrations") expect(page).to have_link('Questions', href: "/admin/conferences/#{conference.short_title}/questions") expect(page).to_not have_link('E-Mails', href: "/admin/conferences/#{conference.short_title}/emails") + expect(page).to_not have_link('New Conference', href: '/admin/conferences/new') visit admin_organizations_path expect(current_path).to eq(admin_organizations_path) diff --git a/spec/features/organization_admin_ability_spec.rb b/spec/features/organization_admin_ability_spec.rb index 3a5ffcd3..aefb89f4 100644 --- a/spec/features/organization_admin_ability_spec.rb +++ b/spec/features/organization_admin_ability_spec.rb @@ -55,6 +55,7 @@ feature 'Has correct abilities' do expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference.short_title}/emails") expect(page).to have_link('Roles', href: "/admin/conferences/#{conference.short_title}/roles") expect(page).to have_link('Resources', href: "/admin/conferences/#{conference.short_title}/resources") + expect(page).to have_link('New Conference', href: '/admin/conferences/new') visit edit_admin_conference_path(conference.short_title) expect(current_path).to eq(edit_admin_conference_path(conference.short_title)) diff --git a/spec/features/organizer_ability_spec.rb b/spec/features/organizer_ability_spec.rb index 7617bc0a..34d87b0a 100644 --- a/spec/features/organizer_ability_spec.rb +++ b/spec/features/organizer_ability_spec.rb @@ -58,6 +58,7 @@ feature 'Has correct abilities' do expect(page).to have_link('E-Mails', href: "/admin/conferences/#{conference.short_title}/emails") expect(page).to have_link('Roles', href: "/admin/conferences/#{conference.short_title}/roles") expect(page).to have_link('Resources', href: "/admin/conferences/#{conference.short_title}/resources") + expect(page).to_not have_link('New Conference', href: '/admin/conferences/new') visit admin_conference_path(other_conference.short_title) expect(page).to have_link('Add venue', href: "/admin/conferences/#{other_conference.short_title}/venue/new") From 8652a5cb784562d79671f602bd50f8adbf915ca0 Mon Sep 17 00:00:00 2001 From: Hernan Schmidt Date: Wed, 12 Jul 2017 16:40:13 +0200 Subject: [PATCH 093/237] Update Byebug to latest version --- Gemfile.lock | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9ea214c2..5ef3f60c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -89,9 +89,7 @@ GEM momentjs-rails (>= 2.8.1) browser (0.6.0) builder (3.2.2) - byebug (3.1.2) - columnize (~> 0.8) - debugger-linecache (~> 1.2) + byebug (9.0.6) cancancan (1.13.1) capybara (2.6.2) addressable @@ -131,7 +129,6 @@ GEM coffee-script-source execjs coffee-script-source (1.10.0) - columnize (0.8.9) countable-rails (0.0.1) railties (>= 3.1) countries (1.2.5) @@ -153,7 +150,6 @@ GEM dante (0.2.0) database_cleaner (1.3.0) debug_inspector (0.0.2) - debugger-linecache (1.2.0) delayed_job (4.1.1) activesupport (>= 3.0, < 5.0) delayed_job_active_record (4.1.0) From 366fced200e007d4ad3bc0dd53b1adb1365d526b Mon Sep 17 00:00:00 2001 From: shlok007 Date: Sat, 24 Jun 2017 05:03:24 +0530 Subject: [PATCH 094/237] Move abilities for admin views in separate model --- app/controllers/admin/base_controller.rb | 6 + .../admin/registration_periods_controller.rb | 2 +- app/models/ability.rb | 246 ++--------- app/models/admin_ability.rb | 237 +++++++++++ spec/models/ability_spec.rb | 361 ---------------- spec/models/admin_ability_spec.rb | 396 ++++++++++++++++++ 6 files changed, 676 insertions(+), 572 deletions(-) create mode 100644 app/models/admin_ability.rb create mode 100644 spec/models/admin_ability_spec.rb diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 85dba43d..3b28a230 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -2,6 +2,12 @@ module Admin class BaseController < ApplicationController before_filter :verify_user_admin + private + + def current_ability + @current_ability ||= AdminAbility.new(current_user) + end + def verify_user_admin if (current_user.nil?) redirect_to sign_in_path diff --git a/app/controllers/admin/registration_periods_controller.rb b/app/controllers/admin/registration_periods_controller.rb index d955ddd0..4e48c013 100644 --- a/app/controllers/admin/registration_periods_controller.rb +++ b/app/controllers/admin/registration_periods_controller.rb @@ -1,5 +1,5 @@ module Admin - class RegistrationPeriodsController < ApplicationController + class RegistrationPeriodsController < Admin::BaseController load_and_authorize_resource :conference, find_by: :short_title load_and_authorize_resource through: :conference, singleton: true diff --git a/app/models/ability.rb b/app/models/ability.rb index 40965719..6581069c 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -3,30 +3,52 @@ class Ability # Initializes the ability class def initialize(user) - # Order Abilities - # (Check https://github.com/CanCanCommunity/cancancan/wiki/Ability-Precedence) - # Check roles of user, using rolify. Role name is *case sensitive* - # user.is_organizer? or user.has_role? :organizer - # user.is_cfp_of? Conference or user.has_role? :cfp, Conference - # user.is_info_desk_of? Conference - # user.is_volunteers_coordinator_of? Conference - # user.is_attendee_of? Conference - # The following is wrong because a user will only have 'cfp' role for a specific conference - # user.is_cfp? # This is always false - user ||= User.new - # This is what sets up the different abilities if user.new_record? not_signed_in - # Checks if the user does not have any role and is not an admin elsif user.roles.any? || user.is_admin - signed_in_with_roles(user) + common_abilities_for_admins(user) else signed_in(user) end end + # Abilities for users with roles wandering around in non-admin views. + def common_abilities_for_admins(user) + signed_in(user) + conf_ids_for_organizer = Conference.with_role(:organizer, user).pluck(:id) + conf_ids_for_cfp = Conference.with_role(:cfp, user).pluck(:id) + conf_ids_for_info_desk = Conference.with_role(:info_desk, user).pluck(:id) + + if conf_ids_for_organizer + + # To access splashpage of their conference if it is not public + can :show, Conference, id: conf_ids_for_organizer + + # To access conference/proposals/registrations + can :manage, Registration, conference_id: conf_ids_for_organizer + + # To access conference/proposals + can :manage, Event, program: { conference_id: conf_ids_for_organizer } + + # To access comment link in menu bar + can :index, Comment, commentable_type: 'Event', + commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id) + elsif conf_ids_for_cfp + + can :index, Comment, commentable_type: 'Event', + commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id) + can :manage, Event, program: { conference_id: conf_ids_for_cfp } + + elsif conf_ids_for_info_desk + can :manage, Registration, conference_id: conf_ids_for_info_desk + end + + can :access, Admin + can :manage, :all if user.is_admin + end + # Abilities for not signed in users (guests) def not_signed_in can [:index], Organization @@ -74,7 +96,6 @@ class Ability def signed_in(user) # Abilities from not_signed_in user are also inherited not_signed_in - can :manage, User, id: user.id can :manage, Registration, user_id: user.id @@ -105,199 +126,4 @@ class Ability can [:destroy], Openid end - - # Abilities for signed in users with roles - def signed_in_with_roles(user) - # Abilities from not_signed_in and signed_in are also inherited - signed_in(user) - - signed_in_with_organization_admin_role(user) if user.has_role? :organization_admin, :any - signed_in_with_organizer_role(user) if user.has_role? :organizer, :any - signed_in_with_cfp_role(user) if user.has_role? :cfp, :any - signed_in_with_info_desk_role(user) if user.has_role? :info_desk, :any - signed_in_with_volunteers_coordinator_role(user) if user.has_role? :volunteers_coordinator, :any - - # for users with any role - can :access, Admin - can [:show], Conference - can :index, Commercial, commercialable_type: 'Conference' - cannot [:edit, :update, :destroy], Question, global: true - # for admins - can :manage, :all if user.is_admin - - # even admin cannot create new users with ICHAIN enabled - cannot [:new, :create], User if ENV['OSEM_ICHAIN_ENABLED'] == 'true' - - cannot :revert_object, PaperTrail::Version do |version| - (version.event == 'create' && %w(Conference User Event).include?(version.item_type)) - end - - cannot :revert_attribute, PaperTrail::Version do |version| - version.event != 'update' || version.item.nil? - end - - cannot :destroy, Program - # Do not delete venue, when there are rooms being used - cannot :destroy, Venue do |venue| - venue.conference.program.events.where.not(room_id: nil).any? - end - - # Can't create cfp if there are no available cfp types - cannot [:new, :create], Cfp do |cfp| - cfp.program.remaining_cfp_types.empty? - end - end - - def signed_in_with_organization_admin_role(user) - org_ids_for_organization_admin = Organization.with_role(:organization_admin, user).pluck(:id) - conf_ids_for_organization_admin = Conference.where(organization_id: org_ids_for_organization_admin).pluck(:id) - - can [:read, :update, :destroy], Organization, id: org_ids_for_organization_admin - can :new, Conference - can :manage, Conference, organization_id: org_ids_for_organization_admin - can [:index, :show], Role - can [:edit, :update], Role do |role| - role.resource_type == 'Organization' && (org_ids_for_organization_admin.include? role.resource_id) - end - signed_in_with_organizer_role(user, conf_ids_for_organization_admin) - end - - 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' - conf_ids = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq - can :manage, Resource, conference_id: conf_ids - can [:read, :update, :destroy], Conference, id: conf_ids - can :manage, Splashpage, conference_id: conf_ids - can :manage, Contact, conference_id: conf_ids - can :manage, EmailSettings, conference_id: conf_ids - can :manage, Campaign, conference_id: conf_ids - can :manage, Target, conference_id: conf_ids - can :manage, Commercial, commercialable_type: 'Conference', - commercialable_id: conf_ids - can :manage, Registration, conference_id: conf_ids - can :manage, RegistrationPeriod, conference_id: conf_ids - can :manage, Question, conference_id: conf_ids - can :manage, Question do |question| - !(question.conferences.pluck(:id) & conf_ids).empty? - end - can :manage, Vposition, conference_id: conf_ids - can :manage, Vday, conference_id: conf_ids - can :manage, Program, conference_id: conf_ids - can :manage, Schedule, program: { conference_id: conf_ids } - can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids } } - 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, Track, program: { conference_id: conf_ids} - can :manage, DifficultyLevel, program: { conference_id: conf_ids} - can :manage, Commercial, commercialable_type: 'Event', - commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id) - can :manage, Venue, conference_id: conf_ids - can :manage, Commercial, commercialable_type: 'Venue', - commercialable_id: Venue.where(conference_id: conf_ids).pluck(:id) - can :manage, Lodging, conference_id: conf_ids - can :manage, Room, venue: { conference_id: conf_ids} - can :manage, Sponsor, conference_id: conf_ids - can :manage, SponsorshipLevel, conference_id: conf_ids - can :manage, Ticket, conference_id: conf_ids - can :index, Comment, commentable_type: 'Event', - commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id) - - # Abilities for Role (Conference resource) - can [:index, :show], Role do |role| - role.resource_type == 'Conference' - end - - can [:edit, :update, :toggle_user], Role do |role| - role.resource_type == 'Conference' && (conf_ids.include? role.resource_id) - end - - can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| - version.item_type == 'User' || (conf_ids.include? version.conference_id) - end - end - - def signed_in_with_cfp_role(user) - # ids of all the conferences for which the user has the 'cfp' role - conf_ids_for_cfp = Conference.with_role(:cfp, user).pluck(:id) - - can [:index, :show, :update], Resource, 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, 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 - can :manage, Schedule, program: { conference_id: conf_ids_for_cfp } - can :manage, Room, venue: { conference_id: conf_ids_for_cfp } - can :show, Venue, conference_id: conf_ids_for_cfp - can :show, Commercial, commercialable_type: 'Venue', commercialable_id: Venue.where(conference_id: conf_ids_for_cfp).pluck(:id) - can :manage, Cfp, program: { conference_id: conf_ids_for_cfp } - can :manage, Program, conference_id: conf_ids_for_cfp - can :manage, Commercial, commercialable_type: 'Event', - commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id) - can :index, Comment, commentable_type: 'Event', - commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id) - - # Abilities for Role (Conference resource) - can [:index, :show], Role do |role| - role.resource_type == 'Conference' - end - # Can add or remove users from role, when user has that same role for the conference - # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') - can :toggle_user, Role do |role| - role.resource_type == 'Conference' && role.name == 'cfp' && - (Conference.with_role(:cfp, user).pluck(:id).include? role.resource_id) - end - - can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Event', conference_id: conf_ids_for_cfp - can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Vote', conference_id: conf_ids_for_cfp - can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| - version.item_type == 'Commercial' && conf_ids_for_cfp.include?(version.conference_id) && - (version.object.to_s.include?('Event') || version.object_changes.to_s.include?('Event')) - end - end - - def signed_in_with_info_desk_role(user) - # ids of all the conferences for which the user has the 'info_desk' role - conf_ids_for_info_desk = Conference.with_role(:info_desk, user).pluck(:id) - - can [:index, :show, :update], Resource, conference_id: conf_ids_for_info_desk - can :manage, Registration, conference_id: conf_ids_for_info_desk - can :manage, Question, conference_id: conf_ids_for_info_desk - can :manage, Question do |question| - !(question.conferences.pluck(:id) & conf_ids_for_info_desk).empty? - end - - # Abilities for Role (Conference resource) - can [:index, :show], Role do |role| - role.resource_type == 'Conference' - end - # Can add or remove users from role, when user has that same role for the conference - # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') - can :toggle_user, Role do |role| - role.resource_type == 'Conference' && role.name == 'info_desk' && - (Conference.with_role(:info_desk, user).pluck(:id).include? role.resource_id) - end - end - - def signed_in_with_volunteers_coordinator_role(user) - # ids of all the conferences for which the user has the 'volunteers_coordinator' role - conf_ids_for_volunteers_coordinator = Conference.with_role(:volunteers_coordinator, user).pluck(:id) - - can [:index, :show, :update], Resource, conference_id: conf_ids_for_volunteers_coordinator - can :manage, Vposition, conference_id: conf_ids_for_volunteers_coordinator - can :manage, Vday, conference_id: conf_ids_for_volunteers_coordinator - - # Abilities for Role (Conference resource) - can [:index, :show], Role do |role| - role.resource_type == 'Conference' - end - # Can add or remove users from role, when user has that same role for the conference - # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') - can :toggle_user, Role do |role| - role.resource_type == 'Conference' && role.name == 'volunteers_coordinator' && - (Conference.with_role(:volunteers_coordinator, user).pluck(:id).include? role.resource_id) - end - end end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb new file mode 100644 index 00000000..99c80401 --- /dev/null +++ b/app/models/admin_ability.rb @@ -0,0 +1,237 @@ +class AdminAbility + include CanCan::Ability + + def initialize(user) + # Order Abilities + # (Check https://github.com/CanCanCommunity/cancancan/wiki/Ability-Precedence) + # Check roles of user, using rolify. Role name is *case sensitive* + # user.is_organizer? or user.has_role? :organizer + # user.is_cfp_of? Conference or user.has_role? :cfp, Conference + # user.is_info_desk_of? Conference + # user.is_volunteers_coordinator_of? Conference + # user.is_attendee_of? Conference + # The following is wrong because a user will only have 'cfp' role for a specific conference + # user.is_cfp? # This is always false + + user ||= User.new + signed_in_with_roles(user) + end + + def common_abilities_for_roles(user) + can :manage, User, id: user.id + can :manage, Registration, user_id: user.id + + can :show, Registration, &:new_record? + + can [:new, :create], Registration do |registration| + conference = registration.conference + conference.registration_open? && !conference.registration_limit_exceeded? || conference.program.speakers.confirmed.include?(user) + end + + can :index, Organization + can :index, Ticket + can :manage, TicketPurchase, user_id: user.id + can [:new, :create], Payment, user_id: user.id + + can [:create, :destroy], Subscription, user_id: user.id + + can [:new, :create], Event do |event| + event.program.cfp_open? && event.new_record? + end + + can [:update, :show, :delete, :index], Event do |event| + event.users.include?(user) + end + + # can manage the commercials of their own events + can :manage, Commercial, commercialable_type: 'Event', commercialable_id: user.events.pluck(:id) + + can [:destroy], Openid + can :access, Admin + can [:show], Conference + can :index, Commercial, commercialable_type: 'Conference' + cannot [:edit, :update, :destroy], Question, global: true + # for admins + can :manage, :all if user.is_admin + # even admin cannot create new users with ICHAIN enabled + cannot [:new, :create], User if ENV['OSEM_ICHAIN_ENABLED'] == 'true' + cannot :revert_object, PaperTrail::Version do |version| + (version.event == 'create' && %w[Conference User Event].include?(version.item_type)) + end + cannot :revert_attribute, PaperTrail::Version do |version| + version.event != 'update' || version.item.nil? + end + # Can't create cfp if there are no available cfp types + cannot [:new, :create], Cfp do |cfp| + cfp.program.remaining_cfp_types.empty? + end + cannot :destroy, Program + # Do not delete venue, when there are rooms being used + cannot :destroy, Venue do |venue| + venue.conference.program.events.where.not(room_id: nil).any? + end + end + + # Abilities for signed in users with roles + def signed_in_with_roles(user) + signed_in_with_organization_admin_role(user) if user.has_role? :organization_admin, :any + signed_in_with_organizer_role(user) if user.has_role? :organizer, :any + signed_in_with_cfp_role(user) if user.has_role? :cfp, :any + signed_in_with_info_desk_role(user) if user.has_role? :info_desk, :any + signed_in_with_volunteers_coordinator_role(user) if user.has_role? :volunteers_coordinator, :any + common_abilities_for_roles(user) + end + + def signed_in_with_organization_admin_role(user) + org_ids_for_organization_admin = Organization.with_role(:organization_admin, user).pluck(:id) + conf_ids_for_organization_admin = Conference.where(organization_id: org_ids_for_organization_admin).pluck(:id) + + can [:read, :update, :destroy], Organization, id: org_ids_for_organization_admin + can :new, Conference + can :manage, Conference, organization_id: org_ids_for_organization_admin + can [:index, :show], Role + can [:edit, :update], Role do |role| + role.resource_type == 'Organization' && (org_ids_for_organization_admin.include? role.resource_id) + end + signed_in_with_organizer_role(user, conf_ids_for_organization_admin) + end + + 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' + conf_ids = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq + can :manage, Resource, conference_id: conf_ids + can [:read, :update, :destroy], Conference, id: conf_ids + can :manage, Splashpage, conference_id: conf_ids + can :manage, Contact, conference_id: conf_ids + can :manage, EmailSettings, conference_id: conf_ids + can :manage, Campaign, conference_id: conf_ids + can :manage, Target, conference_id: conf_ids + can :manage, Commercial, commercialable_type: 'Conference', + commercialable_id: conf_ids + can :manage, Registration, conference_id: conf_ids + can :manage, RegistrationPeriod, conference_id: conf_ids + can :manage, Question, conference_id: conf_ids + can :manage, Question do |question| + !(question.conferences.pluck(:id) & conf_ids).empty? + end + can :manage, Vposition, conference_id: conf_ids + can :manage, Vday, conference_id: conf_ids + can :manage, Program, conference_id: conf_ids + can :manage, Schedule, program: { conference_id: conf_ids } + can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids } } + 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, Track, program: { conference_id: conf_ids } + can :manage, DifficultyLevel, program: { conference_id: conf_ids } + can :manage, Commercial, commercialable_type: 'Event', + commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id) + can :manage, Venue, conference_id: conf_ids + can :manage, Commercial, commercialable_type: 'Venue', + commercialable_id: Venue.where(conference_id: conf_ids).pluck(:id) + can :manage, Lodging, conference_id: conf_ids + can :manage, Room, venue: { conference_id: conf_ids } + can :manage, Sponsor, conference_id: conf_ids + can :manage, SponsorshipLevel, conference_id: conf_ids + can :manage, Ticket, conference_id: conf_ids + can :index, Comment, commentable_type: 'Event', + commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id) + + # Abilities for Role (Conference resource) + can [:index, :show], Role do |role| + role.resource_type == 'Conference' + end + + can [:edit, :update, :toggle_user], Role do |role| + role.resource_type == 'Conference' && (conf_ids.include? role.resource_id) + end + + can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| + version.item_type == 'User' || (conf_ids.include? version.conference_id) + end + end + + def signed_in_with_cfp_role(user) + # ids of all the conferences for which the user has the 'cfp' role + conf_ids_for_cfp = Conference.with_role(:cfp, user).pluck(:id) + + can [:index, :show, :update], Resource, 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, 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 + can :manage, Schedule, program: { conference_id: conf_ids_for_cfp } + can :manage, Room, venue: { conference_id: conf_ids_for_cfp } + can :show, Venue, conference_id: conf_ids_for_cfp + can :show, Commercial, commercialable_type: 'Venue', commercialable_id: Venue.where(conference_id: conf_ids_for_cfp).pluck(:id) + can :manage, Cfp, program: { conference_id: conf_ids_for_cfp } + can :manage, Program, conference_id: conf_ids_for_cfp + can :manage, Commercial, commercialable_type: 'Event', + commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id) + can :index, Comment, commentable_type: 'Event', + commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id) + + # Abilities for Role (Conference resource) + can [:index, :show], Role do |role| + role.resource_type == 'Conference' + end + # Can add or remove users from role, when user has that same role for the conference + # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') + can :toggle_user, Role do |role| + role.resource_type == 'Conference' && role.name == 'cfp' && + (Conference.with_role(:cfp, user).pluck(:id).include? role.resource_id) + end + + can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Event', conference_id: conf_ids_for_cfp + can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Vote', conference_id: conf_ids_for_cfp + can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| + version.item_type == 'Commercial' && conf_ids_for_cfp.include?(version.conference_id) && + (version.object.to_s.include?('Event') || version.object_changes.to_s.include?('Event')) + end + end + + def signed_in_with_info_desk_role(user) + # ids of all the conferences for which the user has the 'info_desk' role + conf_ids_for_info_desk = Conference.with_role(:info_desk, user).pluck(:id) + + can [:index, :show, :update], Resource, conference_id: conf_ids_for_info_desk + can :manage, Registration, conference_id: conf_ids_for_info_desk + can :manage, Question, conference_id: conf_ids_for_info_desk + can :manage, Question do |question| + !(question.conferences.pluck(:id) & conf_ids_for_info_desk).empty? + end + + # Abilities for Role (Conference resource) + can [:index, :show], Role do |role| + role.resource_type == 'Conference' + end + # Can add or remove users from role, when user has that same role for the conference + # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') + can :toggle_user, Role do |role| + role.resource_type == 'Conference' && role.name == 'info_desk' && + (Conference.with_role(:info_desk, user).pluck(:id).include? role.resource_id) + end + end + + def signed_in_with_volunteers_coordinator_role(user) + # ids of all the conferences for which the user has the 'volunteers_coordinator' role + conf_ids_for_volunteers_coordinator = Conference.with_role(:volunteers_coordinator, user).pluck(:id) + + can [:index, :show, :update], Resource, conference_id: conf_ids_for_volunteers_coordinator + can :manage, Vposition, conference_id: conf_ids_for_volunteers_coordinator + can :manage, Vday, conference_id: conf_ids_for_volunteers_coordinator + + # Abilities for Role (Conference resource) + can [:index, :show], Role do |role| + role.resource_type == 'Conference' + end + # Can add or remove users from role, when user has that same role for the conference + # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') + can :toggle_user, Role do |role| + role.resource_type == 'Conference' && role.name == 'volunteers_coordinator' && + (Conference.with_role(:volunteers_coordinator, user).pluck(:id).include? role.resource_id) + end + end +end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 02aa4882..55f430f2 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -11,14 +11,8 @@ describe 'User' do let!(:organization) { create(:organization) } let!(:my_conference) { create(:full_conference, organization: organization) } - let(:my_venue) { my_conference.venue || create(:venue, conference: my_conference) } - let(:my_registration) { create(:registration, conference: my_conference, user: admin) } - let(:other_registration) { create(:registration, conference: conference_public) } - let(:my_event) { create(:event_full, program: my_conference.program) } let(:my_room) { create(:room, venue: my_conference.venue) } - let!(:my_event_scheduled) { create(:event_full, program: my_conference.program, room_id: my_room.id) } - let(:other_event) { create(:event_full, program: conference_public.program) } let(:conference_not_public) { create(:conference, splashpage: create(:splashpage, public: false)) } let(:conference_public) { create(:full_conference, splashpage: create(:splashpage, public: true)) } @@ -28,7 +22,6 @@ describe 'User' do let(:commercial_event_confirmed) { create(:commercial, commercialable: event_confirmed) } let(:commercial_event_unconfirmed) { create(:commercial, commercialable: event_unconfirmed) } - let(:resource) { create(:resource, conference: my_conference)} let(:registration) { create(:registration) } let(:program_with_cfp) { create(:program, :with_cfp) } @@ -38,11 +31,6 @@ describe 'User' do let(:conference_with_closed_registration) { create(:conference) } let!(:closed_registration_period) { create(:registration_period, conference: conference_with_closed_registration, start_date: Date.current - 6.days, end_date: Date.current - 6.days) } - let!(:my_schedule) { create(:schedule, program: my_conference.program) } - let!(:other_schedule) { create(:schedule, program: conference_public.program) } - - let!(:my_event_schedule) { create(:event_schedule, schedule: my_schedule) } - let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) } # Test abilities for not signed in users context 'when user is not signed in' do it{ should be_able_to(:index, Organization)} @@ -127,354 +115,5 @@ describe 'User' do it{ should be_able_to(:manage, user_commercial) } it{ should_not be_able_to(:manage, commercial_event_unconfirmed) } end - - context 'user #is_admin?' do - let(:venue) { my_conference.venue } - let(:room) { create(:room, venue: venue) } - let!(:event) { create(:event_full, program: my_conference.program, room_id: room.id) } - let(:user) { create(:admin) } - it{ should be_able_to(:manage, :all) } - it{ should_not be_able_to(:destroy, my_conference.program) } - it{ should_not be_able_to(:destroy, my_venue) } - end - - shared_examples 'user with any role' do - let!(:other_organization) { create(:organization) } - let!(:other_conference) { create(:conference, organization: other_organization) } - - it{ should_not be_able_to(:update, Role.find_by(name: 'organization_admin', resource: other_organization)) } - it{ should_not be_able_to(:edit, Role.find_by(name: 'organization_admin', resource: other_organization)) } - it{ should_not be_able_to(:show, Role.find_by(name: 'organization_admin', resource: other_organization)) } - - %w(organizer cfp info_desk volunteers_coordinator).each do |role| - it{ should_not be_able_to(:toggle_user, Role.find_by(name: role, resource: other_conference)) } - it{ should_not be_able_to(:update, Role.find_by(name: role, resource: other_conference)) } - it{ should_not be_able_to(:edit, Role.find_by(name: role, resource: other_conference)) } - it{ should be_able_to(:show, Role.find_by(name: role, resource: other_conference)) } - it{ should be_able_to(:index, Role.find_by(name: role, resource: other_conference)) } - end - end - - shared_examples 'user with non-organizer role' do |role_name| - %w(organizer cfp info_desk volunteers_coordinator).each do |role| - if role == role_name - it{ should be_able_to(:toggle_user, Role.find_by(name: role, resource: my_conference)) } - else - it{ should_not be_able_to(:toggle_user, Role.find_by(name: role, resource: my_conference)) } - end - it{ should_not be_able_to(:update, Role.find_by(name: role, resource: my_conference)) } - it{ should_not be_able_to(:edit, Role.find_by(name: role, resource: my_conference)) } - it{ should be_able_to(:show, Role.find_by(name: role, resource: my_conference)) } - it{ should be_able_to(:index, Role.find_by(name: role, resource: my_conference)) } - end - end - - context 'when user has the role organization_admin' do - let(:role) { Role.find_by(name: 'organization_admin', resource: organization) } - let(:user) { create(:user, role_ids: [role.id]) } - let(:other_organization) { create(:organization) } - let(:other_conference) { create(:conference, organization: other_organization) } - - it{ should be_able_to(:manage, my_conference) } - it{ should be_able_to(:read, organization) } - it{ should be_able_to(:update, organization) } - it{ should be_able_to(:destroy, organization) } - it{ should be_able_to(:new, Conference.new) } - it{ should be_able_to(:create, Conference.new(organization_id: organization.id)) } - it{ should_not be_able_to(:manage, other_conference) } - it{ should_not be_able_to(:create, Conference.new(organization_id: other_organization.id)) } - it{ should_not be_able_to(:new, Organization.new) } - it{ should_not be_able_to(:create, Organization.new) } - end - - context 'when user has the role organizer' do - let(:role) { Role.find_by(name: 'organizer', resource: my_conference) } - let(:user) { create(:user, role_ids: [role.id]) } - - it{ should_not be_able_to(:destroy, my_conference.program) } - it 'when there is a room assigned to an event' do - should_not be_able_to(:destroy, my_venue) - end - - it 'when there are no rooms used' do - my_event_scheduled.room_id = nil - my_event_scheduled.save! - my_event_scheduled.reload - should be_able_to(:destroy, my_venue) - end - - it{ should_not be_able_to(:new, Organization.new)} - it{ should_not be_able_to(:create, Organization.new)} - it{ should_not be_able_to(:new, Conference.new)} - it{ should_not be_able_to(:create, Conference.new) } - it{ should be_able_to(:read, my_conference) } - it{ should be_able_to(:update, my_conference) } - it{ should be_able_to(:destroy, my_conference) } - it{ should_not be_able_to(:manage, conference_public) } - it{ should be_able_to(:manage, my_conference.splashpage) } - it{ should_not be_able_to(:manage, conference_public.splashpage) } - it{ should be_able_to(:manage, my_conference.contact) } - it{ should_not be_able_to(:manage, conference_public.contact) } - it{ should be_able_to(:manage, my_conference.email_settings) } - it{ should_not be_able_to(:manage, conference_public.email_settings) } - it{ should be_able_to(:manage, my_conference.campaigns.first) } - it{ should_not be_able_to(:manage, conference_public.campaigns.first) } - it{ should be_able_to(:manage, my_conference.targets.first) } - it{ should_not be_able_to(:manage, conference_public.targets.first) } - it{ should be_able_to(:manage, my_conference.commercials.first) } - it{ should_not be_able_to(:manage, conference_public.commercials.first) } - it{ should be_able_to(:manage, my_conference.registration_period) } - it{ should_not be_able_to(:manage, conference_public.registration_period) } - it{ should be_able_to(:manage, my_conference.questions.first) } - it{ should_not be_able_to(:manage, conference_public.questions.first) } - it{ should be_able_to(:manage, my_conference.program.cfp) } - it{ should_not be_able_to(:manage, conference_public.program.cfp) } - it{ should be_able_to(:manage, my_schedule) } - it{ should_not be_able_to(:manage, other_schedule) } - it{ should be_able_to(:manage, my_event_schedule) } - it{ should_not be_able_to(:manage, other_event_schedule) } - it{ should be_able_to(:manage, my_conference.venue) } - it{ should_not be_able_to(:manage, conference_public.venue) } - it{ should be_able_to(:manage, my_conference.lodgings.first) } - it{ should_not be_able_to(:manage, conference_public.lodgings.first) } - it{ should be_able_to(:manage, my_conference.sponsors.first) } - it{ should_not be_able_to(:manage, conference_public.sponsors.first) } - it{ should be_able_to(:manage, my_conference.sponsorship_levels.first) } - it{ should_not be_able_to(:manage, conference_public.sponsorship_levels.first) } - it{ should be_able_to(:manage, my_conference.tickets.first) } - it{ should_not be_able_to(:manage, conference_public.tickets.first) } - - it{ should be_able_to(:manage, my_registration) } - it{ should_not be_able_to(:manage, other_registration) } - - it{ should be_able_to(:manage, my_event) } - it{ should_not be_able_to(:manage, other_event) } - it{ should be_able_to(:manage, my_event.event_type) } - it{ should_not be_able_to(:manage, other_event.event_type) } - it{ should be_able_to(:manage, my_event.track) } - it{ should_not be_able_to(:manage, other_event.track) } - it{ should be_able_to(:manage, my_event.difficulty_level) } - it{ should_not be_able_to(:manage, other_event.difficulty_level) } - it{ should be_able_to(:manage, my_event.commercials.first) } - it{ should_not be_able_to(:manage, other_event.commercials.first) } - it{ should be_able_to(:index, my_event.comment_threads.first) } - it{ should_not be_able_to(:index, other_event.comment_threads.first) } - - it{ should be_able_to(:manage, resource)} - - %w(organizer cfp info_desk volunteers_coordinator).each do |role| - it{ should be_able_to(:toggle_user, Role.find_by(name: role, resource: my_conference)) } - it{ should be_able_to(:edit, Role.find_by(name: role, resource: my_conference)) } - it{ should be_able_to(:update, Role.find_by(name: role, resource: my_conference)) } - it{ should be_able_to(:show, Role.find_by(name: role, resource: my_conference)) } - it{ should be_able_to(:index, Role.find_by(name: role, resource: my_conference)) } - end - - it_behaves_like 'user with any role' - end - - context 'when user has the role cfp' do - let(:role) { Role.find_by(name: 'cfp', resource: my_conference) } - let(:user) { create(:user, role_ids: [role.id]) } - - it{ should_not be_able_to(:new, Conference.new) } - it{ should_not be_able_to(:create, Conference.new) } - it{ should_not be_able_to(:manage, my_conference) } - it{ should_not be_able_to(:manage, conference_public) } - it{ should_not be_able_to(:manage, my_conference.splashpage) } - it{ should_not be_able_to(:manage, conference_public.splashpage) } - it{ should_not be_able_to(:manage, my_conference.contact) } - it{ should_not be_able_to(:manage, conference_public.contact) } - it{ should be_able_to(:manage, my_conference.email_settings) } - it{ should_not be_able_to(:manage, conference_public.email_settings) } - it{ should_not be_able_to(:manage, my_conference.campaigns.first) } - it{ should_not be_able_to(:manage, conference_public.campaigns.first) } - it{ should_not be_able_to(:manage, my_conference.targets.first) } - it{ should_not be_able_to(:manage, conference_public.targets.first) } - it{ should_not be_able_to(:manage, my_conference.commercials.first) } - it{ should_not be_able_to(:manage, conference_public.commercials.first) } - it{ should_not be_able_to(:manage, my_conference.registration_period) } - it{ should_not be_able_to(:manage, conference_public.registration_period) } - it{ should_not be_able_to(:manage, my_conference.questions.first) } - it{ should_not be_able_to(:manage, conference_public.questions.first) } - it{ should be_able_to(:manage, my_conference.program.cfp) } - it{ should_not be_able_to(:manage, conference_public.program.cfp) } - it{ should be_able_to(:manage, my_schedule) } - it{ should_not be_able_to(:manage, other_schedule) } - it{ should_not be_able_to(:manage, my_event_schedule) } - it{ should_not be_able_to(:manage, other_event_schedule) } - it{ should_not be_able_to(:manage, my_conference.venue) } - it{ should be_able_to(:show, my_conference.venue) } - it{ should_not be_able_to(:manage, conference_public.venue) } - it{ should_not be_able_to(:manage, my_conference.lodgings.first) } - it{ should_not be_able_to(:manage, conference_public.lodgings.first) } - it{ should_not be_able_to(:manage, my_conference.sponsors.first) } - it{ should_not be_able_to(:manage, conference_public.sponsors.first) } - it{ should_not be_able_to(:manage, my_conference.sponsorship_levels.first) } - it{ should_not be_able_to(:manage, conference_public.sponsorship_levels.first) } - it{ should_not be_able_to(:manage, my_conference.tickets.first) } - it{ should_not be_able_to(:manage, conference_public.tickets.first) } - - it{ should_not be_able_to(:manage, my_registration) } - it{ should_not be_able_to(:manage, other_registration) } - - it{ should be_able_to(:manage, my_event) } - it{ should_not be_able_to(:manage, other_event) } - it{ should be_able_to(:manage, my_event.event_type) } - it{ should_not be_able_to(:manage, other_event.event_type) } - it{ should be_able_to(:manage, my_event.track) } - it{ should_not be_able_to(:manage, other_event.track) } - it{ should be_able_to(:manage, my_event.difficulty_level) } - it{ should_not be_able_to(:manage, other_event.difficulty_level) } - it{ should be_able_to(:manage, my_event.commercials.first) } - it{ should_not be_able_to(:manage, other_event.commercials.first) } - it{ should be_able_to(:index, my_event.comment_threads.first) } - it{ should_not be_able_to(:index, other_event.comment_threads.first) } - - it{ should_not be_able_to(:manage, resource)} - it{ should be_able_to(:index, resource)} - it{ should be_able_to(:show, resource)} - it{ should be_able_to(:update, resource)} - - it_behaves_like 'user with any role' - it_behaves_like 'user with non-organizer role', 'cfp' - end - - context 'when user has the role info_desk' do - let(:role) { Role.find_by(name: 'info_desk', resource: my_conference) } - let(:user) { create(:user, role_ids: [role.id]) } - - it{ should_not be_able_to(:new, Conference.new) } - it{ should_not be_able_to(:create, Conference.new) } - it{ should_not be_able_to(:manage, my_conference) } - it{ should_not be_able_to(:manage, conference_public) } - it{ should_not be_able_to(:manage, my_conference.splashpage) } - it{ should_not be_able_to(:manage, conference_public.splashpage) } - it{ should_not be_able_to(:manage, my_conference.contact) } - it{ should_not be_able_to(:manage, conference_public.contact) } - it{ should_not be_able_to(:manage, my_conference.email_settings) } - it{ should_not be_able_to(:manage, conference_public.email_settings) } - it{ should_not be_able_to(:manage, my_conference.campaigns.first) } - it{ should_not be_able_to(:manage, conference_public.campaigns.first) } - it{ should_not be_able_to(:manage, my_conference.targets.first) } - it{ should_not be_able_to(:manage, conference_public.targets.first) } - it{ should_not be_able_to(:manage, my_conference.commercials.first) } - it{ should_not be_able_to(:manage, conference_public.commercials.first) } - it{ should_not be_able_to(:manage, my_conference.registration_period) } - it{ should_not be_able_to(:manage, conference_public.registration_period) } - it{ should be_able_to(:manage, my_conference.questions.first) } - it{ should_not be_able_to(:manage, conference_public.questions.first) } - it{ should_not be_able_to(:manage, my_conference.program.cfp) } - it{ should_not be_able_to(:manage, conference_public.program.cfp) } - it{ should_not be_able_to(:manage, my_schedule) } - it{ should_not be_able_to(:manage, other_schedule) } - it{ should_not be_able_to(:manage, my_event_schedule) } - it{ should_not be_able_to(:manage, other_event_schedule) } - it{ should_not be_able_to(:manage, my_conference.venue) } - it{ should_not be_able_to(:show, my_conference.venue) } - it{ should_not be_able_to(:manage, conference_public.venue) } - it{ should_not be_able_to(:manage, my_conference.lodgings.first) } - it{ should_not be_able_to(:manage, conference_public.lodgings.first) } - it{ should_not be_able_to(:manage, my_conference.sponsors.first) } - it{ should_not be_able_to(:manage, conference_public.sponsors.first) } - it{ should_not be_able_to(:manage, my_conference.sponsorship_levels.first) } - it{ should_not be_able_to(:manage, conference_public.sponsorship_levels.first) } - it{ should_not be_able_to(:manage, my_conference.tickets.first) } - it{ should_not be_able_to(:manage, conference_public.tickets.first) } - - it{ should be_able_to(:manage, my_registration) } - it{ should_not be_able_to(:manage, other_registration) } - - it{ should_not be_able_to(:manage, my_event) } - it{ should_not be_able_to(:manage, other_event) } - it{ should_not be_able_to(:manage, my_event.event_type) } - it{ should_not be_able_to(:manage, other_event.event_type) } - it{ should_not be_able_to(:manage, my_event.track) } - it{ should_not be_able_to(:manage, other_event.track) } - it{ should_not be_able_to(:manage, my_event.difficulty_level) } - it{ should_not be_able_to(:manage, other_event.difficulty_level) } - it{ should_not be_able_to(:manage, my_event.commercials.first) } - it{ should_not be_able_to(:manage, other_event.commercials.first) } - it{ should_not be_able_to(:index, my_event.comment_threads.first) } - it{ should_not be_able_to(:index, other_event.comment_threads.first) } - - it{ should_not be_able_to(:manage, resource)} - it{ should be_able_to(:index, resource)} - it{ should be_able_to(:show, resource)} - it{ should be_able_to(:update, resource)} - - it_behaves_like 'user with any role' - it_behaves_like 'user with non-organizer role', 'info_desk' - end - - context 'when user has the role volunteers_coordinator' do - let(:role) { Role.find_by(name: 'volunteers_coordinator', resource: my_conference) } - let(:user) { create(:user, role_ids: [role.id]) } - - it{ should_not be_able_to(:new, Conference.new) } - it{ should_not be_able_to(:create, Conference.new) } - it{ should_not be_able_to(:manage, my_conference) } - it{ should_not be_able_to(:manage, conference_public) } - it{ should_not be_able_to(:manage, my_conference.splashpage) } - it{ should_not be_able_to(:manage, conference_public.splashpage) } - it{ should_not be_able_to(:manage, my_conference.contact) } - it{ should_not be_able_to(:manage, conference_public.contact) } - it{ should_not be_able_to(:manage, my_conference.email_settings) } - it{ should_not be_able_to(:manage, conference_public.email_settings) } - it{ should_not be_able_to(:manage, my_conference.campaigns.first) } - it{ should_not be_able_to(:manage, conference_public.campaigns.first) } - it{ should_not be_able_to(:manage, my_conference.targets.first) } - it{ should_not be_able_to(:manage, conference_public.targets.first) } - it{ should_not be_able_to(:manage, my_conference.commercials.first) } - it{ should_not be_able_to(:manage, conference_public.commercials.first) } - it{ should_not be_able_to(:manage, my_conference.registration_period) } - it{ should_not be_able_to(:manage, conference_public.registration_period) } - it{ should_not be_able_to(:manage, my_conference.questions.first) } - it{ should_not be_able_to(:manage, conference_public.questions.first) } - it{ should_not be_able_to(:manage, my_conference.program.cfp) } - it{ should_not be_able_to(:manage, conference_public.program.cfp) } - it{ should_not be_able_to(:manage, my_schedule) } - it{ should_not be_able_to(:manage, other_schedule) } - it{ should_not be_able_to(:manage, my_event_schedule) } - it{ should_not be_able_to(:manage, other_event_schedule) } - it{ should_not be_able_to(:manage, my_conference.venue) } - it{ should_not be_able_to(:show, my_conference.venue) } - it{ should_not be_able_to(:manage, conference_public.venue) } - it{ should_not be_able_to(:manage, my_conference.lodgings.first) } - it{ should_not be_able_to(:manage, conference_public.lodgings.first) } - it{ should_not be_able_to(:manage, my_conference.sponsors.first) } - it{ should_not be_able_to(:manage, conference_public.sponsors.first) } - it{ should_not be_able_to(:manage, my_conference.sponsorship_levels.first) } - it{ should_not be_able_to(:manage, conference_public.sponsorship_levels.first) } - it{ should_not be_able_to(:manage, my_conference.tickets.first) } - it{ should_not be_able_to(:manage, conference_public.tickets.first) } - - it{ should_not be_able_to(:manage, registration) } - it{ should_not be_able_to(:manage, other_registration) } - - it{ should_not be_able_to(:manage, my_event) } - it{ should_not be_able_to(:manage, other_event) } - it{ should_not be_able_to(:manage, my_event.event_type) } - it{ should_not be_able_to(:manage, other_event.event_type) } - it{ should_not be_able_to(:manage, my_event.track) } - it{ should_not be_able_to(:manage, other_event.track) } - it{ should_not be_able_to(:manage, my_event.difficulty_level) } - it{ should_not be_able_to(:manage, other_event.difficulty_level) } - it{ should_not be_able_to(:manage, my_event.commercials.first) } - it{ should_not be_able_to(:manage, other_event.commercials.first) } - it{ should_not be_able_to(:index, my_event.comment_threads.first) } - it{ should_not be_able_to(:index, other_event.comment_threads.first) } - - it{ should_not be_able_to(:manage, resource)} - it{ should be_able_to(:index, resource)} - it{ should be_able_to(:show, resource)} - it{ should be_able_to(:update, resource)} - - it 'should be_able to :manage Vposition' - it 'should be_able to :manage Vday' - - it_behaves_like 'user with any role' - it_behaves_like 'user with non-organizer role', 'volunteers_coordinator' - end end end diff --git a/spec/models/admin_ability_spec.rb b/spec/models/admin_ability_spec.rb new file mode 100644 index 00000000..486ff295 --- /dev/null +++ b/spec/models/admin_ability_spec.rb @@ -0,0 +1,396 @@ +require 'spec_helper' +require 'cancan/matchers' + +describe 'User with admin role' do + describe 'Abilities' do + let!(:admin) { create(:admin) } + + # see https://github.com/CanCanCommunity/cancancan/wiki/Testing-Abilities + subject(:ability){ AdminAbility.new(user) } + let(:user){ nil } + + let!(:organization) { create(:organization) } + let!(:my_conference) { create(:full_conference, organization: organization) } + let(:my_venue) { my_conference.venue || create(:venue, conference: my_conference) } + let(:my_registration) { create(:registration, conference: my_conference, user: admin) } + + let(:other_registration) { create(:registration, conference: conference_public) } + let(:my_event) { create(:event_full, program: my_conference.program) } + let(:my_room) { create(:room, venue: my_conference.venue) } + let!(:my_event_scheduled) { create(:event_full, program: my_conference.program, room_id: my_room.id) } + let(:other_event) { create(:event_full, program: conference_public.program) } + + let(:conference_not_public) { create(:conference, splashpage: create(:splashpage, public: false)) } + let(:conference_public) { create(:full_conference, splashpage: create(:splashpage, public: true)) } + + let(:event_confirmed) { create(:event, state: 'confirmed') } + let(:event_unconfirmed) { create(:event) } + + let(:commercial_event_confirmed) { create(:commercial, commercialable: event_confirmed) } + let(:commercial_event_unconfirmed) { create(:commercial, commercialable: event_unconfirmed) } + let(:resource) { create(:resource, conference: my_conference) } + let(:registration) { create(:registration) } + + let(:program_with_cfp) { create(:program, :with_cfp) } + let(:program_without_cfp) { create(:program) } + let(:conference_with_open_registration) { create(:conference) } + let!(:open_registration_period) { create(:registration_period, conference: conference_with_open_registration, start_date: Date.current - 6.days) } + let(:conference_with_closed_registration) { create(:conference) } + let!(:closed_registration_period) { create(:registration_period, conference: conference_with_closed_registration, start_date: Date.current - 6.days, end_date: Date.current - 6.days) } + + let!(:my_schedule) { create(:schedule, program: my_conference.program) } + let!(:other_schedule) { create(:schedule, program: conference_public.program) } + + let!(:my_event_schedule) { create(:event_schedule, schedule: my_schedule) } + let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) } + + context 'user #is_admin?' do + let(:venue) { my_conference.venue } + let(:room) { create(:room, venue: venue) } + let!(:event) { create(:event_full, program: my_conference.program, room_id: room.id) } + let(:user) { create(:admin) } + it{ should be_able_to(:manage, :all) } + it{ should_not be_able_to(:destroy, my_conference.program) } + it{ should_not be_able_to(:destroy, my_venue) } + end + + shared_examples 'user with any role' do + let!(:other_organization) { create(:organization) } + let!(:other_conference) { create(:conference, organization: other_organization) } + + it{ should_not be_able_to(:update, Role.find_by(name: 'organization_admin', resource: other_organization)) } + it{ should_not be_able_to(:edit, Role.find_by(name: 'organization_admin', resource: other_organization)) } + it{ should_not be_able_to(:show, Role.find_by(name: 'organization_admin', resource: other_organization)) } + + %w[organizer cfp info_desk volunteers_coordinator].each do |role| + it{ should_not be_able_to(:toggle_user, Role.find_by(name: role, resource: other_conference)) } + it{ should_not be_able_to(:update, Role.find_by(name: role, resource: other_conference)) } + it{ should_not be_able_to(:edit, Role.find_by(name: role, resource: other_conference)) } + it{ should be_able_to(:show, Role.find_by(name: role, resource: other_conference)) } + it{ should be_able_to(:index, Role.find_by(name: role, resource: other_conference)) } + end + end + + shared_examples 'user with non-organizer role' do |role_name| + %w[organizer cfp info_desk volunteers_coordinator].each do |role| + if role == role_name + it{ should be_able_to(:toggle_user, Role.find_by(name: role, resource: my_conference)) } + else + it{ should_not be_able_to(:toggle_user, Role.find_by(name: role, resource: my_conference)) } + end + it{ should_not be_able_to(:update, Role.find_by(name: role, resource: my_conference)) } + it{ should_not be_able_to(:edit, Role.find_by(name: role, resource: my_conference)) } + it{ should be_able_to(:show, Role.find_by(name: role, resource: my_conference)) } + it{ should be_able_to(:index, Role.find_by(name: role, resource: my_conference)) } + end + end + + context 'when user has the role organization_admin' do + let(:role) { Role.find_by(name: 'organization_admin', resource: organization) } + let(:user) { create(:user, role_ids: [role.id]) } + let(:other_organization) { create(:organization) } + let(:other_conference) { create(:conference, organization: other_organization) } + + it{ should be_able_to(:manage, my_conference) } + it{ should be_able_to(:read, organization) } + it{ should be_able_to(:update, organization) } + it{ should be_able_to(:destroy, organization) } + it{ should be_able_to(:new, Conference.new) } + it{ should be_able_to(:create, Conference.new(organization_id: organization.id)) } + it{ should_not be_able_to(:manage, other_conference) } + it{ should_not be_able_to(:create, Conference.new(organization_id: other_organization.id)) } + it{ should_not be_able_to(:new, Organization.new) } + it{ should_not be_able_to(:create, Organization.new) } + end + + context 'when user has the role organizer' do + let(:role) { Role.find_by(name: 'organizer', resource: my_conference) } + let(:user) { create(:user, role_ids: [role.id]) } + + it{ should_not be_able_to(:destroy, my_conference.program) } + it 'when there is a room assigned to an event' do + should_not be_able_to(:destroy, my_venue) + end + + it 'when there are no rooms used' do + my_event_scheduled.room_id = nil + my_event_scheduled.save! + my_event_scheduled.reload + should be_able_to(:destroy, my_venue) + end + + it{ should_not be_able_to(:new, Organization.new) } + it{ should_not be_able_to(:create, Organization.new) } + it{ should_not be_able_to(:new, Conference.new) } + it{ should_not be_able_to(:create, Conference.new) } + it{ should be_able_to(:read, my_conference) } + it{ should be_able_to(:update, my_conference) } + it{ should be_able_to(:destroy, my_conference) } + it{ should_not be_able_to(:manage, conference_public) } + it{ should be_able_to(:manage, my_conference.splashpage) } + it{ should_not be_able_to(:manage, conference_public.splashpage) } + it{ should be_able_to(:manage, my_conference.contact) } + it{ should_not be_able_to(:manage, conference_public.contact) } + it{ should be_able_to(:manage, my_conference.email_settings) } + it{ should_not be_able_to(:manage, conference_public.email_settings) } + it{ should be_able_to(:manage, my_conference.campaigns.first) } + it{ should_not be_able_to(:manage, conference_public.campaigns.first) } + it{ should be_able_to(:manage, my_conference.targets.first) } + it{ should_not be_able_to(:manage, conference_public.targets.first) } + it{ should be_able_to(:manage, my_conference.commercials.first) } + it{ should_not be_able_to(:manage, conference_public.commercials.first) } + it{ should be_able_to(:manage, my_conference.registration_period) } + it{ should_not be_able_to(:manage, conference_public.registration_period) } + it{ should be_able_to(:manage, my_conference.questions.first) } + it{ should_not be_able_to(:manage, conference_public.questions.first) } + it{ should be_able_to(:manage, my_conference.program.cfp) } + it{ should_not be_able_to(:manage, conference_public.program.cfp) } + it{ should be_able_to(:manage, my_schedule) } + it{ should_not be_able_to(:manage, other_schedule) } + it{ should be_able_to(:manage, my_event_schedule) } + it{ should_not be_able_to(:manage, other_event_schedule) } + it{ should be_able_to(:manage, my_conference.venue) } + it{ should_not be_able_to(:manage, conference_public.venue) } + it{ should be_able_to(:manage, my_conference.lodgings.first) } + it{ should_not be_able_to(:manage, conference_public.lodgings.first) } + it{ should be_able_to(:manage, my_conference.sponsors.first) } + it{ should_not be_able_to(:manage, conference_public.sponsors.first) } + it{ should be_able_to(:manage, my_conference.sponsorship_levels.first) } + it{ should_not be_able_to(:manage, conference_public.sponsorship_levels.first) } + it{ should be_able_to(:manage, my_conference.tickets.first) } + it{ should_not be_able_to(:manage, conference_public.tickets.first) } + + it{ should be_able_to(:manage, my_registration) } + it{ should_not be_able_to(:manage, other_registration) } + + it{ should be_able_to(:manage, my_event) } + it{ should_not be_able_to(:manage, other_event) } + it{ should be_able_to(:manage, my_event.event_type) } + it{ should_not be_able_to(:manage, other_event.event_type) } + it{ should be_able_to(:manage, my_event.track) } + it{ should_not be_able_to(:manage, other_event.track) } + it{ should be_able_to(:manage, my_event.difficulty_level) } + it{ should_not be_able_to(:manage, other_event.difficulty_level) } + it{ should be_able_to(:manage, my_event.commercials.first) } + it{ should_not be_able_to(:manage, other_event.commercials.first) } + it{ should be_able_to(:index, my_event.comment_threads.first) } + it{ should_not be_able_to(:index, other_event.comment_threads.first) } + + it{ should be_able_to(:manage, resource) } + + %w[organizer cfp info_desk volunteers_coordinator].each do |role| + it{ should be_able_to(:toggle_user, Role.find_by(name: role, resource: my_conference)) } + it{ should be_able_to(:edit, Role.find_by(name: role, resource: my_conference)) } + it{ should be_able_to(:update, Role.find_by(name: role, resource: my_conference)) } + it{ should be_able_to(:show, Role.find_by(name: role, resource: my_conference)) } + it{ should be_able_to(:index, Role.find_by(name: role, resource: my_conference)) } + end + + it_behaves_like 'user with any role' + end + + context 'when user has the role cfp' do + let(:role) { Role.find_by(name: 'cfp', resource: my_conference) } + let(:user) { create(:user, role_ids: [role.id]) } + + it{ should_not be_able_to(:new, Conference.new) } + it{ should_not be_able_to(:create, Conference.new) } + it{ should_not be_able_to(:manage, my_conference) } + it{ should_not be_able_to(:manage, conference_public) } + it{ should_not be_able_to(:manage, my_conference.splashpage) } + it{ should_not be_able_to(:manage, conference_public.splashpage) } + it{ should_not be_able_to(:manage, my_conference.contact) } + it{ should_not be_able_to(:manage, conference_public.contact) } + it{ should be_able_to(:manage, my_conference.email_settings) } + it{ should_not be_able_to(:manage, conference_public.email_settings) } + it{ should_not be_able_to(:manage, my_conference.campaigns.first) } + it{ should_not be_able_to(:manage, conference_public.campaigns.first) } + it{ should_not be_able_to(:manage, my_conference.targets.first) } + it{ should_not be_able_to(:manage, conference_public.targets.first) } + it{ should_not be_able_to(:manage, my_conference.commercials.first) } + it{ should_not be_able_to(:manage, conference_public.commercials.first) } + it{ should_not be_able_to(:manage, my_conference.registration_period) } + it{ should_not be_able_to(:manage, conference_public.registration_period) } + it{ should_not be_able_to(:manage, my_conference.questions.first) } + it{ should_not be_able_to(:manage, conference_public.questions.first) } + it{ should be_able_to(:manage, my_conference.program.cfp) } + it{ should_not be_able_to(:manage, conference_public.program.cfp) } + it{ should be_able_to(:manage, my_schedule) } + it{ should_not be_able_to(:manage, other_schedule) } + it{ should_not be_able_to(:manage, my_event_schedule) } + it{ should_not be_able_to(:manage, other_event_schedule) } + it{ should_not be_able_to(:manage, my_conference.venue) } + it{ should be_able_to(:show, my_conference.venue) } + it{ should_not be_able_to(:manage, conference_public.venue) } + it{ should_not be_able_to(:manage, my_conference.lodgings.first) } + it{ should_not be_able_to(:manage, conference_public.lodgings.first) } + it{ should_not be_able_to(:manage, my_conference.sponsors.first) } + it{ should_not be_able_to(:manage, conference_public.sponsors.first) } + it{ should_not be_able_to(:manage, my_conference.sponsorship_levels.first) } + it{ should_not be_able_to(:manage, conference_public.sponsorship_levels.first) } + it{ should_not be_able_to(:manage, my_conference.tickets.first) } + it{ should_not be_able_to(:manage, conference_public.tickets.first) } + + it{ should_not be_able_to(:manage, my_registration) } + it{ should_not be_able_to(:manage, other_registration) } + + it{ should be_able_to(:manage, my_event) } + it{ should_not be_able_to(:manage, other_event) } + it{ should be_able_to(:manage, my_event.event_type) } + it{ should_not be_able_to(:manage, other_event.event_type) } + it{ should be_able_to(:manage, my_event.track) } + it{ should_not be_able_to(:manage, other_event.track) } + it{ should be_able_to(:manage, my_event.difficulty_level) } + it{ should_not be_able_to(:manage, other_event.difficulty_level) } + it{ should be_able_to(:manage, my_event.commercials.first) } + it{ should_not be_able_to(:manage, other_event.commercials.first) } + it{ should be_able_to(:index, my_event.comment_threads.first) } + it{ should_not be_able_to(:index, other_event.comment_threads.first) } + + it{ should_not be_able_to(:manage, resource) } + it{ should be_able_to(:index, resource) } + it{ should be_able_to(:show, resource) } + it{ should be_able_to(:update, resource) } + + it_behaves_like 'user with any role' + it_behaves_like 'user with non-organizer role', 'cfp' + end + + context 'when user has the role info_desk' do + let(:role) { Role.find_by(name: 'info_desk', resource: my_conference) } + let(:user) { create(:user, role_ids: [role.id]) } + + it{ should_not be_able_to(:new, Conference.new) } + it{ should_not be_able_to(:create, Conference.new) } + it{ should_not be_able_to(:manage, my_conference) } + it{ should_not be_able_to(:manage, conference_public) } + it{ should_not be_able_to(:manage, my_conference.splashpage) } + it{ should_not be_able_to(:manage, conference_public.splashpage) } + it{ should_not be_able_to(:manage, my_conference.contact) } + it{ should_not be_able_to(:manage, conference_public.contact) } + it{ should_not be_able_to(:manage, my_conference.email_settings) } + it{ should_not be_able_to(:manage, conference_public.email_settings) } + it{ should_not be_able_to(:manage, my_conference.campaigns.first) } + it{ should_not be_able_to(:manage, conference_public.campaigns.first) } + it{ should_not be_able_to(:manage, my_conference.targets.first) } + it{ should_not be_able_to(:manage, conference_public.targets.first) } + it{ should_not be_able_to(:manage, my_conference.commercials.first) } + it{ should_not be_able_to(:manage, conference_public.commercials.first) } + it{ should_not be_able_to(:manage, my_conference.registration_period) } + it{ should_not be_able_to(:manage, conference_public.registration_period) } + it{ should be_able_to(:manage, my_conference.questions.first) } + it{ should_not be_able_to(:manage, conference_public.questions.first) } + it{ should_not be_able_to(:manage, my_conference.program.cfp) } + it{ should_not be_able_to(:manage, conference_public.program.cfp) } + it{ should_not be_able_to(:manage, my_schedule) } + it{ should_not be_able_to(:manage, other_schedule) } + it{ should_not be_able_to(:manage, my_event_schedule) } + it{ should_not be_able_to(:manage, other_event_schedule) } + it{ should_not be_able_to(:manage, my_conference.venue) } + it{ should_not be_able_to(:show, my_conference.venue) } + it{ should_not be_able_to(:manage, conference_public.venue) } + it{ should_not be_able_to(:manage, my_conference.lodgings.first) } + it{ should_not be_able_to(:manage, conference_public.lodgings.first) } + it{ should_not be_able_to(:manage, my_conference.sponsors.first) } + it{ should_not be_able_to(:manage, conference_public.sponsors.first) } + it{ should_not be_able_to(:manage, my_conference.sponsorship_levels.first) } + it{ should_not be_able_to(:manage, conference_public.sponsorship_levels.first) } + it{ should_not be_able_to(:manage, my_conference.tickets.first) } + it{ should_not be_able_to(:manage, conference_public.tickets.first) } + + it{ should be_able_to(:manage, my_registration) } + it{ should_not be_able_to(:manage, other_registration) } + + it{ should_not be_able_to(:manage, my_event) } + it{ should_not be_able_to(:manage, other_event) } + it{ should_not be_able_to(:manage, my_event.event_type) } + it{ should_not be_able_to(:manage, other_event.event_type) } + it{ should_not be_able_to(:manage, my_event.track) } + it{ should_not be_able_to(:manage, other_event.track) } + it{ should_not be_able_to(:manage, my_event.difficulty_level) } + it{ should_not be_able_to(:manage, other_event.difficulty_level) } + it{ should_not be_able_to(:manage, my_event.commercials.first) } + it{ should_not be_able_to(:manage, other_event.commercials.first) } + it{ should_not be_able_to(:index, my_event.comment_threads.first) } + it{ should_not be_able_to(:index, other_event.comment_threads.first) } + + it{ should_not be_able_to(:manage, resource) } + it{ should be_able_to(:index, resource) } + it{ should be_able_to(:show, resource) } + it{ should be_able_to(:update, resource) } + + it_behaves_like 'user with any role' + it_behaves_like 'user with non-organizer role', 'info_desk' + end + + context 'when user has the role volunteers_coordinator' do + let(:role) { Role.find_by(name: 'volunteers_coordinator', resource: my_conference) } + let(:user) { create(:user, role_ids: [role.id]) } + + it{ should_not be_able_to(:new, Conference.new) } + it{ should_not be_able_to(:create, Conference.new) } + it{ should_not be_able_to(:manage, my_conference) } + it{ should_not be_able_to(:manage, conference_public) } + it{ should_not be_able_to(:manage, my_conference.splashpage) } + it{ should_not be_able_to(:manage, conference_public.splashpage) } + it{ should_not be_able_to(:manage, my_conference.contact) } + it{ should_not be_able_to(:manage, conference_public.contact) } + it{ should_not be_able_to(:manage, my_conference.email_settings) } + it{ should_not be_able_to(:manage, conference_public.email_settings) } + it{ should_not be_able_to(:manage, my_conference.campaigns.first) } + it{ should_not be_able_to(:manage, conference_public.campaigns.first) } + it{ should_not be_able_to(:manage, my_conference.targets.first) } + it{ should_not be_able_to(:manage, conference_public.targets.first) } + it{ should_not be_able_to(:manage, my_conference.commercials.first) } + it{ should_not be_able_to(:manage, conference_public.commercials.first) } + it{ should_not be_able_to(:manage, my_conference.registration_period) } + it{ should_not be_able_to(:manage, conference_public.registration_period) } + it{ should_not be_able_to(:manage, my_conference.questions.first) } + it{ should_not be_able_to(:manage, conference_public.questions.first) } + it{ should_not be_able_to(:manage, my_conference.program.cfp) } + it{ should_not be_able_to(:manage, conference_public.program.cfp) } + it{ should_not be_able_to(:manage, my_schedule) } + it{ should_not be_able_to(:manage, other_schedule) } + it{ should_not be_able_to(:manage, my_event_schedule) } + it{ should_not be_able_to(:manage, other_event_schedule) } + it{ should_not be_able_to(:manage, my_conference.venue) } + it{ should_not be_able_to(:show, my_conference.venue) } + it{ should_not be_able_to(:manage, conference_public.venue) } + it{ should_not be_able_to(:manage, my_conference.lodgings.first) } + it{ should_not be_able_to(:manage, conference_public.lodgings.first) } + it{ should_not be_able_to(:manage, my_conference.sponsors.first) } + it{ should_not be_able_to(:manage, conference_public.sponsors.first) } + it{ should_not be_able_to(:manage, my_conference.sponsorship_levels.first) } + it{ should_not be_able_to(:manage, conference_public.sponsorship_levels.first) } + it{ should_not be_able_to(:manage, my_conference.tickets.first) } + it{ should_not be_able_to(:manage, conference_public.tickets.first) } + + it{ should_not be_able_to(:manage, registration) } + it{ should_not be_able_to(:manage, other_registration) } + + it{ should_not be_able_to(:manage, my_event) } + it{ should_not be_able_to(:manage, other_event) } + it{ should_not be_able_to(:manage, my_event.event_type) } + it{ should_not be_able_to(:manage, other_event.event_type) } + it{ should_not be_able_to(:manage, my_event.track) } + it{ should_not be_able_to(:manage, other_event.track) } + it{ should_not be_able_to(:manage, my_event.difficulty_level) } + it{ should_not be_able_to(:manage, other_event.difficulty_level) } + it{ should_not be_able_to(:manage, my_event.commercials.first) } + it{ should_not be_able_to(:manage, other_event.commercials.first) } + it{ should_not be_able_to(:index, my_event.comment_threads.first) } + it{ should_not be_able_to(:index, other_event.comment_threads.first) } + + it{ should_not be_able_to(:manage, resource) } + it{ should be_able_to(:index, resource) } + it{ should be_able_to(:show, resource) } + it{ should be_able_to(:update, resource) } + + it 'should be_able to :manage Vposition' + it 'should be_able to :manage Vday' + + it_behaves_like 'user with any role' + it_behaves_like 'user with non-organizer role', 'volunteers_coordinator' + end + end +end From d26a5dcf9b5e052d6e1735df0a52feded1d06b77 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 11 Jul 2017 17:25:34 +0530 Subject: [PATCH 095/237] fix failing tests about accessing admin area --- app/models/admin_ability.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 99c80401..29253709 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -21,6 +21,7 @@ class AdminAbility can :manage, User, id: user.id can :manage, Registration, user_id: user.id + can :index, Conference can :show, Registration, &:new_record? can [:new, :create], Registration do |registration| @@ -48,7 +49,6 @@ class AdminAbility can [:destroy], Openid can :access, Admin - can [:show], Conference can :index, Commercial, commercialable_type: 'Conference' cannot [:edit, :update, :destroy], Question, global: true # for admins @@ -156,6 +156,9 @@ class AdminAbility # ids of all the conferences for which the user has the 'cfp' role conf_ids_for_cfp = Conference.with_role(:cfp, user).pluck(:id) + can :show, Conference do |conf| + conf_ids_for_cfp.include?(conf.id) + end can [:index, :show, :update], Resource, 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 } @@ -196,6 +199,9 @@ class AdminAbility # ids of all the conferences for which the user has the 'info_desk' role conf_ids_for_info_desk = Conference.with_role(:info_desk, user).pluck(:id) + can :show, Conference do |conf| + conf_ids_for_info_desk.include?(conf.id) + end can [:index, :show, :update], Resource, conference_id: conf_ids_for_info_desk can :manage, Registration, conference_id: conf_ids_for_info_desk can :manage, Question, conference_id: conf_ids_for_info_desk @@ -219,6 +225,10 @@ class AdminAbility # ids of all the conferences for which the user has the 'volunteers_coordinator' role conf_ids_for_volunteers_coordinator = Conference.with_role(:volunteers_coordinator, user).pluck(:id) + can :show, Conference do |conf| + conf_ids_for_volunteers_coordinator.include?(conf.id) + end + can :show, Conference, conference_id: conf_ids_for_volunteers_coordinator can [:index, :show, :update], Resource, conference_id: conf_ids_for_volunteers_coordinator can :manage, Vposition, conference_id: conf_ids_for_volunteers_coordinator can :manage, Vday, conference_id: conf_ids_for_volunteers_coordinator From 05fdd443a433fa5f63001eb7a19935c7fe87470c Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 11 Jul 2017 20:56:02 +0530 Subject: [PATCH 096/237] fix failing tests for volunteers_coordinator --- app/models/admin_ability.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 29253709..006e919a 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -228,7 +228,6 @@ class AdminAbility can :show, Conference do |conf| conf_ids_for_volunteers_coordinator.include?(conf.id) end - can :show, Conference, conference_id: conf_ids_for_volunteers_coordinator can [:index, :show, :update], Resource, conference_id: conf_ids_for_volunteers_coordinator can :manage, Vposition, conference_id: conf_ids_for_volunteers_coordinator can :manage, Vday, conference_id: conf_ids_for_volunteers_coordinator From 98fc1137e17cc229e52482e02ed4cfa71022553f Mon Sep 17 00:00:00 2001 From: shlok007 Date: Thu, 13 Jul 2017 01:23:48 +0530 Subject: [PATCH 097/237] suggested changes --- app/models/ability.rb | 73 +++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 6581069c..afc51a68 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -7,48 +7,12 @@ class Ability if user.new_record? not_signed_in - elsif user.roles.any? || user.is_admin - common_abilities_for_admins(user) else signed_in(user) + common_abilities_for_admins(user) if user.roles.any? || user.is_admin? end end - # Abilities for users with roles wandering around in non-admin views. - def common_abilities_for_admins(user) - signed_in(user) - conf_ids_for_organizer = Conference.with_role(:organizer, user).pluck(:id) - conf_ids_for_cfp = Conference.with_role(:cfp, user).pluck(:id) - conf_ids_for_info_desk = Conference.with_role(:info_desk, user).pluck(:id) - - if conf_ids_for_organizer - - # To access splashpage of their conference if it is not public - can :show, Conference, id: conf_ids_for_organizer - - # To access conference/proposals/registrations - can :manage, Registration, conference_id: conf_ids_for_organizer - - # To access conference/proposals - can :manage, Event, program: { conference_id: conf_ids_for_organizer } - - # To access comment link in menu bar - can :index, Comment, commentable_type: 'Event', - commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id) - elsif conf_ids_for_cfp - - can :index, Comment, commentable_type: 'Event', - commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id) - can :manage, Event, program: { conference_id: conf_ids_for_cfp } - - elsif conf_ids_for_info_desk - can :manage, Registration, conference_id: conf_ids_for_info_desk - end - - can :access, Admin - can :manage, :all if user.is_admin - end - # Abilities for not signed in users (guests) def not_signed_in can [:index], Organization @@ -126,4 +90,39 @@ class Ability can [:destroy], Openid end + + # Abilities for users with roles wandering around in non-admin views. + def common_abilities_for_admins(user) + can :access, Admin + can :manage, :all if user.is_admin? + + conf_ids_for_organizer = Conference.with_role(:organizer, user).pluck(:id) + conf_ids_for_cfp = Conference.with_role(:cfp, user).pluck(:id) + conf_ids_for_info_desk = Conference.with_role(:info_desk, user).pluck(:id) + + if conf_ids_for_organizer + # To access splashpage of their conference if it is not public + can :show, Conference, id: conf_ids_for_organizer + # To access conference/proposals/registrations + can :manage, Registration, conference_id: conf_ids_for_organizer + # To access conference/proposals + can :manage, Event, program: { conference_id: conf_ids_for_organizer } + # To access comment link in menu bar + can :index, Comment, commentable_type: 'Event', + commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id) + end + + if conf_ids_for_cfp + # To access comment link in menu bar + can :index, Comment, commentable_type: 'Event', + commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id) + # To access conference/proposals + can :manage, Event, program: { conference_id: conf_ids_for_cfp } + end + + if conf_ids_for_info_desk + # To access conference/proposals/registrations + can :manage, Registration, conference_id: conf_ids_for_info_desk + end + end end From 68fc750e9f41a53171dcdee4fc608554c17ef0d7 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Thu, 8 Jun 2017 12:25:33 +0300 Subject: [PATCH 098/237] Implement track requests and add the track organizer role About track requests: Create migration that adds the fields submitter_id, state, and cfp_active to Tracks Add validations and the self_organized? method to the Track model Create a new TracksController outide of the admin namespace Create the relevant views for index, show, new and edit Modify the admin views for tracks to include extra info for self-organized tracks About track organizers: Create the role when a self-organized track is created Define track organizer abilities Modify the roles views and controller to handle the new role The route for Roles#edit needs to have higher priority than the nested routes for track roles, otherwise, the word edit in the url is matched as a track with short_name edit --- .haml-lint_todo.yml | 6 + .rubocop.yml | 1 + .rubocop_todo.yml | 3 + app/controllers/admin/base_controller.rb | 3 +- app/controllers/admin/roles_controller.rb | 49 +++- app/controllers/admin/tracks_controller.rb | 11 +- app/controllers/tracks_controller.rb | 47 ++++ app/models/admin_ability.rb | 50 +++- app/models/track.rb | 24 ++ app/models/user.rb | 1 + app/views/admin/roles/_form.html.haml | 2 +- app/views/admin/roles/_users.html.haml | 2 +- app/views/admin/roles/index.html.haml | 18 +- app/views/admin/roles/show.html.haml | 10 +- app/views/admin/tracks/_form.html.haml | 2 + app/views/admin/tracks/index.html.haml | 25 ++ app/views/tracks/_form.html.haml | 17 ++ app/views/tracks/index.html.haml | 43 +++ app/views/tracks/show.html.haml | 26 ++ config/routes.rb | 15 +- ...ctive_and_submitter_reference_to_tracks.rb | 8 + db/schema.rb | 11 +- spec/factories/tracks.rb | 6 + spec/features/track_organizer_ability_spec.rb | 244 ++++++++++++++++++ spec/models/admin_ability_spec.rb | 112 ++++++++ spec/models/track_spec.rb | 57 ++++ 26 files changed, 766 insertions(+), 27 deletions(-) create mode 100644 app/controllers/tracks_controller.rb create mode 100644 app/views/tracks/_form.html.haml create mode 100644 app/views/tracks/index.html.haml create mode 100644 app/views/tracks/show.html.haml create mode 100644 db/migrate/20170705075039_add_state_cfp_active_and_submitter_reference_to_tracks.rb create mode 100644 spec/features/track_organizer_ability_spec.rb create mode 100644 spec/models/track_spec.rb diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 0f6f5408..df4d0708 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -172,6 +172,9 @@ linters: - "app/views/users/edit.html.haml" - "app/views/users/show.html.haml" - "app/views/admin/cfps/index.html.haml" + - "app/views/tracks/_form.html.haml" + - "app/views/tracks/index.html.haml" + - "app/views/tracks/show.html.haml" # Offense count: 223 InstanceVariables: @@ -231,6 +234,7 @@ linters: - "app/views/schedules/_schedule_item.html.haml" - "app/views/schedules/_schedule_tabs.html.haml" - "app/views/admin/cfps/_events_cfp.html.haml" + - "app/views/tracks/_form.html.haml" # Offense count: 32 IdNames: @@ -330,6 +334,8 @@ linters: - "app/views/shared/_object_changes.html.haml" - "app/views/tickets/_ticket.html.haml" - "app/views/tickets/index.html.haml" + - "app/views/tracks/index.html.haml" + - "app/views/tracks/show.html.haml" # Offense count: 23 ClassesBeforeIds: diff --git a/.rubocop.yml b/.rubocop.yml index 22e17db0..5d24032d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -30,3 +30,4 @@ Metrics/BlockLength: Exclude: - 'spec/models/conference_spec.rb' - 'spec/features/ability_spec.rb' + - 'spec/models/ability_spec.rb' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 68360907..1c188b60 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -94,6 +94,8 @@ Metrics/ModuleLength: # Offense count: 14 Metrics/PerceivedComplexity: Max: 15 + Exclude: + - 'app/controllers/admin/roles_controller.rb' # Offense count: 11 # Cop supports --auto-correct. @@ -850,6 +852,7 @@ Style/SymbolProc: - 'app/controllers/admin/questions_controller.rb' - 'app/helpers/application_helper.rb' - 'app/models/ability.rb' + - 'app/models/admin_ability.rb' - 'db/migrate/20140730104658_migrate_roles_for_cancancan.rb' - 'spec/controllers/admin/conferences_controller_spec.rb' - 'spec/support/flash.rb' diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 3b28a230..631dd4d8 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -15,7 +15,8 @@ module Admin end unless (current_user.has_role? :organizer, :any) || (current_user.has_role? :cfp, :any) || (current_user.has_role? :info_desk, :any) || (current_user.has_role? :organization_admin, :any) || - (current_user.has_role? :volunteers_coordinator, :any) || current_user.is_admin + (current_user.has_role? :volunteers_coordinator, :any) || + (current_user.has_role? :track_organizer, :any) || current_user.is_admin raise CanCan::AccessDenied.new('You are not authorized to access this page.') end end diff --git a/app/controllers/admin/roles_controller.rb b/app/controllers/admin/roles_controller.rb index 3bc37bc3..15bf5e2b 100644 --- a/app/controllers/admin/roles_controller.rb +++ b/app/controllers/admin/roles_controller.rb @@ -8,14 +8,26 @@ module Admin def index @roles = Role.where(resource: @conference) + tracks = @conference.program.tracks.where.not(submitter: nil) + @roles += Role.where(resource: tracks) authorize! :index, @role end def show + @url = if @track + toggle_user_track_admin_conference_role_path(@conference.short_title, @role.name, @track.name.tr(' ', '_')) + else + toggle_user_admin_conference_role_path(@conference.short_title, @role.name) + end @users = @role.users end def edit + @url = if @track + track_admin_conference_role_path(@conference.short_title, @role.name, @track.name.tr(' ', '_')) + else + admin_conference_role_path(@conference.short_title, @role.name) + end @users = @role.users end @@ -23,7 +35,13 @@ module Admin role_name = @role.name if @role.update_attributes(role_params) - redirect_to admin_conference_role_path(@conference.short_title, @role.name), + url = if @track + track_admin_conference_role_path(@conference.short_title, @role.name, @track.name.tr(' ', '_')) + else + admin_conference_role_path(@conference.short_title, @role.name) + end + + redirect_to url, notice: 'Successfully updated role ' + @role.name else @role.name = role_name @@ -36,8 +54,14 @@ module Admin user = User.find_by(email: user_params[:email]) state = user_params[:state] + url = if @track + track_admin_conference_role_path(@conference.short_title, @role.name, @track.name.tr(' ', '_')) + else + admin_conference_role_path(@conference.short_title, @role.name) + end + unless user - redirect_to admin_conference_role_path(@conference.short_title, @role.name), + redirect_to url, error: 'Could not find user. Please provide a valid email!' return end @@ -49,17 +73,23 @@ module Admin return end + if @role.resource_type == 'Conference' + role_resource = @conference + elsif @role.resource_type == 'Track' + role_resource = @track + end + # Remove user if state == 'false' - if user.remove_role @role.name, @conference + if user.remove_role @role.name, role_resource flash[:notice] = "Successfully removed role #{@role.name} from user #{user.email}" else flash[:error] = "Could not remove role #{@role.name} from user #{user.email}" end - elsif user.has_role? @role.name, @conference + elsif user.has_role? @role.name, role_resource flash[:error] = "User #{user.email} already has the role #{@role.name}" # Add user - elsif user.add_role @role.name, @conference + elsif user.add_role @role.name, role_resource flash[:notice] = "Successfully added role #{@role.name} to user #{user.email}" else flash[:error] = "Coud not add role #{@role.name} to #{user.email}" @@ -67,7 +97,7 @@ module Admin respond_to do |format| format.js - format.html { redirect_to admin_conference_role_path(@conference.short_title, @role.name) } + format.html { redirect_to url } end end @@ -77,7 +107,12 @@ module Admin # Set 'organizer' as default role, when there is no other selection @selection = params[:id] ? params[:id].parameterize.underscore : 'organizer' - @role = Role.find_by(name: @selection, resource: @conference) + if @selection == 'track_organizer' + @track = @conference.program.tracks.find_by(short_name: params[:track_name]) + @role = Role.find_by(name: @selection, resource: @track) + else + @role = Role.find_by(name: @selection, resource: @conference) + end end def role_params diff --git a/app/controllers/admin/tracks_controller.rb b/app/controllers/admin/tracks_controller.rb index 4fc9d9c7..c229b9b8 100644 --- a/app/controllers/admin/tracks_controller.rb +++ b/app/controllers/admin/tracks_controller.rb @@ -50,10 +50,19 @@ module Admin end end + def toggle_cfp_inclusion + @track.cfp_active = !@track.cfp_active + if @track.save + head :ok + else + head :unprocessable_entity + end + end + private def track_params - params.require(:track).permit(:name, :description, :color, :short_name) + params.require(:track).permit(:name, :description, :color, :short_name, :cfp_active) end end end diff --git a/app/controllers/tracks_controller.rb b/app/controllers/tracks_controller.rb new file mode 100644 index 00000000..f346b0d1 --- /dev/null +++ b/app/controllers/tracks_controller.rb @@ -0,0 +1,47 @@ +class TracksController < ApplicationController + load_resource :conference, find_by: :short_title + load_resource :program, through: :conference, singleton: true + load_and_authorize_resource through: :program, find_by: :short_name + + def index + @tracks = current_user.tracks.where(program: @program) + end + + def show; end + + def new + @track = @program.tracks.new(color: @conference.next_color_for_collection(:tracks)) + end + + def edit; end + + def create + @track = @program.tracks.new(track_params) + @track.submitter = current_user + @track.state = 'new' + @track.cfp_active = false + if @track.save + redirect_to conference_program_tracks_path(conference_id: @conference.short_title), + notice: 'Track request successfully created.' + else + flash.now[:error] = "Creating Track request failed: #{@track.errors.full_messages.join('. ')}." + render :new + end + end + + def update + if @track.update_attributes(track_params) + redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title), + notice: 'Track request successfully updated.' + else + flash.now[:error] = "Track request update failed: #{@track.errors.full_messages.join('. ')}." + render :edit + end + end + + private + + def track_params + params.require(:track).permit(:name, :description, :color, :short_name) + end +end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 006e919a..d43683fd 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -70,6 +70,11 @@ class AdminAbility cannot :destroy, Venue do |venue| venue.conference.program.events.where.not(room_id: nil).any? end + + # Prevent requests for tracks from being destroyed + cannot :destroy, Track do |track| + track.self_organized? + end end # Abilities for signed in users with roles @@ -79,6 +84,7 @@ class AdminAbility signed_in_with_cfp_role(user) if user.has_role? :cfp, :any signed_in_with_info_desk_role(user) if user.has_role? :info_desk, :any signed_in_with_volunteers_coordinator_role(user) if user.has_role? :volunteers_coordinator, :any + signed_in_with_track_organizer_role(user) if user.has_role? :track_organizer, :any common_abilities_for_roles(user) end @@ -100,6 +106,9 @@ class AdminAbility # 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' conf_ids = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq + # ids of all the tracks that belong to the programs of the above conferences + track_ids = Track.joins(:program).where('programs.conference_id IN (?)', conf_ids).pluck(:id) + can :manage, Resource, conference_id: conf_ids can [:read, :update, :destroy], Conference, id: conf_ids can :manage, Splashpage, conference_id: conf_ids @@ -140,11 +149,12 @@ class AdminAbility # Abilities for Role (Conference resource) can [:index, :show], Role do |role| - role.resource_type == 'Conference' + role.resource_type == 'Conference' || role.resource_type == 'Track' end can [:edit, :update, :toggle_user], Role do |role| - role.resource_type == 'Conference' && (conf_ids.include? role.resource_id) + role.resource_type == 'Conference' && (conf_ids.include? role.resource_id) || + role.resource_type == 'Track' && (track_ids.include? role.resource_id) end can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| @@ -178,7 +188,7 @@ class AdminAbility # Abilities for Role (Conference resource) can [:index, :show], Role do |role| - role.resource_type == 'Conference' + role.resource_type == 'Conference' || role.resource_type == 'Track' end # Can add or remove users from role, when user has that same role for the conference # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') @@ -211,7 +221,7 @@ class AdminAbility # Abilities for Role (Conference resource) can [:index, :show], Role do |role| - role.resource_type == 'Conference' + role.resource_type == 'Conference' || role.resource_type == 'Track' end # Can add or remove users from role, when user has that same role for the conference # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') @@ -234,7 +244,7 @@ class AdminAbility # Abilities for Role (Conference resource) can [:index, :show], Role do |role| - role.resource_type == 'Conference' + role.resource_type == 'Conference' || role.resource_type == 'Track' end # Can add or remove users from role, when user has that same role for the conference # Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP') @@ -243,4 +253,34 @@ class AdminAbility (Conference.with_role(:volunteers_coordinator, user).pluck(:id).include? role.resource_id) end end + + def signed_in_with_track_organizer_role(user) + # ids of all the conferences for which the user has the 'track organizer' role + conf_ids_for_track_organizer = Track.with_role(:track_organizer, user).joins(:program).pluck(:conference_id) + # ids of all the tracks for which the user has the 'track_organizer' role + track_ids_for_track_organizer = Track.with_role(:track_organizer, user).pluck(:id) + + can :show, Conference do |conf| + conf_ids_for_track_organizer.include?(conf.id) + end + + # Show Program in the admin sidebar + can :show, Program, conference_id: conf_ids_for_track_organizer + + # Show Tracks in the admin sidebar + can :update, Track do |track| + track.new_record? && conf_ids_for_track_organizer.include?(track.program.conference_id) + end + + can :manage, Track, id: track_ids_for_track_organizer + + # Show Roles in the admin sidebar and allow authorization of the index action + can [:index, :show], Role do |role| + role.resource_type == 'Conference' || role.resource_type == 'Track' + end + + can :toggle_user, Role do |role| + role.resource_type == 'Track' && track_ids_for_track_organizer.include?(role.resource_id) + end + end end diff --git a/app/models/track.rb b/app/models/track.rb index f65506d8..a38cf458 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -1,6 +1,10 @@ class Track < ActiveRecord::Base include RevisionCount + + resourcify :roles, dependent: :delete_all + belongs_to :program + belongs_to :submitter, class_name: 'User' has_many :events, dependent: :nullify has_paper_trail only: [:name, :description, :color], meta: { conference_id: :conference_id } @@ -14,13 +18,27 @@ class Track < ActiveRecord::Base uniqueness: { scope: :program } + validates :state, presence: true, if: :self_organized? + validates :cfp_active, inclusion: { in: [true, false] }, if: :self_organized? before_validation :capitalize_color + after_create :create_organizer_role, if: :self_organized? + def conference program.conference end + ## + # Checks if the track is self-organized + # ====Returns + # * +true+ -> If the track has a submitter + # * +false+ -> if the track doesn't have a submitter + def self_organized? + return true if submitter + false + end + private def generate_guid @@ -38,4 +56,10 @@ class Track < ActiveRecord::Base def conference_id program.conference_id end + + ## + # Creates the role of the track organizer + def create_organizer_role + Role.where(name: 'track_organizer', resource: self).first_or_create(description: 'For the organizers of the Track') + end end diff --git a/app/models/user.rb b/app/models/user.rb index 6ffb739f..e79d0b2a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -55,6 +55,7 @@ class User < ActiveRecord::Base has_many :votes, dependent: :destroy has_many :voted_events, through: :votes, source: :events has_many :subscriptions, dependent: :destroy + has_many :tracks, foreign_key: 'submitter_id' accepts_nested_attributes_for :roles scope :admin, -> { where(is_admin: true) } diff --git a/app/views/admin/roles/_form.html.haml b/app/views/admin/roles/_form.html.haml index eb10b23f..2204ef89 100644 --- a/app/views/admin/roles/_form.html.haml +++ b/app/views/admin/roles/_form.html.haml @@ -7,7 +7,7 @@ .text-muted = @role.description -= semantic_form_for @role, url: admin_conference_role_path(@conference.short_title, @role.name) do |f| += semantic_form_for @role, url: @url do |f| .row .col-md-5 = f.input :description diff --git a/app/views/admin/roles/_users.html.haml b/app/views/admin/roles/_users.html.haml index 9d73421b..f32c9a99 100644 --- a/app/views/admin/roles/_users.html.haml +++ b/app/views/admin/roles/_users.html.haml @@ -14,7 +14,7 @@ - if ( can? :toggle_user, @role ) %td.text-right = hidden_field_tag "role[user_ids][]", nil - = check_box_tag @conference.short_title, @role.id, (@role.user_ids.include? user.id), method: :post, url: "/admin/conferences/#{@conference.short_title}/roles/#{@role.name}/toggle_user?user[email]=#{user.email}&user[state]=", class: 'switch-checkbox', data: { size: 'small', off_color: 'warning', on_text: 'Yes', off_text: 'No' } + = check_box_tag @conference.short_title, @role.id, (@role.user_ids.include? user.id), method: :post, url: "#{@url}?user[email]=#{user.email}&user[state]=", class: 'switch-checkbox', data: { size: 'small', off_color: 'warning', on_text: 'Yes', off_text: 'No' } %td= user.id %td= user.name %td= user.email diff --git a/app/views/admin/roles/index.html.haml b/app/views/admin/roles/index.html.haml index c6e4c773..1310b133 100644 --- a/app/views/admin/roles/index.html.haml +++ b/app/views/admin/roles/index.html.haml @@ -19,13 +19,23 @@ %tr %td= role.id %td= role.name.titleize - %td= role.description + %td + = role.description + - if role.resource_type == 'Track' + - track = Track.find(role.resource_id) + = link_to track.name, admin_conference_program_track_path(@conference.short_title, track) %td = role.users.pluck(:name).first(5).join ', ' - if role.users.count > 5 = link_to '...', admin_conference_role_path(@conference.short_title, role.name) %td .btn-group - = link_to 'Users', admin_conference_role_path(@conference.short_title, role.name), class: 'btn btn-success' - - if can? :edit, role - = link_to 'Edit', edit_admin_conference_role_path(@conference.short_title, role.name), class: 'btn btn-primary' + - if role.resource_type == 'Track' + - track_name = Track.find(role.resource_id).short_name + = link_to 'Users', track_admin_conference_role_path(@conference.short_title, role.name, track_name), class: 'btn btn-success' + - if can? :edit, role + = link_to 'Edit', track_edit_admin_conference_role_path(@conference.short_title, role.name, track_name), class: 'btn btn-primary' + - else + = link_to 'Users', admin_conference_role_path(@conference.short_title, role.name), class: 'btn btn-success' + - if can? :edit, role + = link_to 'Edit', edit_admin_conference_role_path(@conference.short_title, role.name), class: 'btn btn-primary' diff --git a/app/views/admin/roles/show.html.haml b/app/views/admin/roles/show.html.haml index 69d02f6b..d7dcef8d 100644 --- a/app/views/admin/roles/show.html.haml +++ b/app/views/admin/roles/show.html.haml @@ -6,14 +6,20 @@ Role = @role.name.titleize - if can? :edit, @role - = link_to 'Edit', edit_admin_conference_role_path(@conference.short_title, @role.name), class: 'btn btn-primary pull-right' + - if @track + = link_to 'Edit', track_edit_admin_conference_role_path(@conference.short_title, @role.name, @track.short_name), class: 'btn btn-primary pull-right' + - else + = link_to 'Edit', edit_admin_conference_role_path(@conference.short_title, @role.name), class: 'btn btn-primary pull-right' .text-muted = @role.description + - if @track + = link_to @track.name, admin_conference_program_track_path(@conference.short_title, @track) + .row.col-md-3 - if ( can? :toggle_user, @role ) && !@role.new_record? - = semantic_form_for :user, url: toggle_user_admin_conference_role_path(@conference.short_title, @role.name), method: :post do |u| + = semantic_form_for :user, url: @url, method: :post do |u| = u.label 'Add user by email: ' .input-group diff --git a/app/views/admin/tracks/_form.html.haml b/app/views/admin/tracks/_form.html.haml index c3c7cf26..76833e66 100644 --- a/app/views/admin/tracks/_form.html.haml +++ b/app/views/admin/tracks/_form.html.haml @@ -13,4 +13,6 @@ = f.input :short_name, hint: "A short and unique handle for the track, using only letters, numbers, underscores, and dashes. This will be used to identify the track in URLs etc. Example: 'my_awesome_track'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' } = f.input :color, input_html: {size: 6, type: 'color'}, required: true = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, hint: markdown_hint + - if @track.self_organized? + = f.input :cfp_active, label: 'Allow event submitters to select this track for their proposal' = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index f9ed9036..94193088 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -11,7 +11,10 @@ %th Name %th Short name %th Description + %th Submitter %th Color + %th State + %th Included in the Cfp %th Actions %tbody - @tracks.each do |track| @@ -24,9 +27,31 @@ %td %p = truncate(track.description) + %td + - if track.self_organized? + = link_to track.submitter.name, admin_user_path(track.submitter) + - else + N/A %td %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} = track.color + %td + - if track.self_organized? + = track.state + - else + N/A + %td + - if track.self_organized? + = check_box_tag "#{@conference.short_title}_#{track.id}", track.id, track.cfp_active, + class: 'switch-checkbox', method: :patch, + url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.id)+"?included=", + data: { size: 'small', + on_color: 'success', + off_color: 'warning', + on_text: 'Yes', + off_text: 'No' } + - else + %i.fa.fa-check %td .btn-group{role: "group"} = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track.short_name), diff --git a/app/views/tracks/_form.html.haml b/app/views/tracks/_form.html.haml new file mode 100644 index 00000000..a10a72a9 --- /dev/null +++ b/app/views/tracks/_form.html.haml @@ -0,0 +1,17 @@ +.container + .row + .col-md-12 + .page-header + %h1 + - if @track.new_record? + New + = @track.name + Track + .row + .col-md-12 + = semantic_form_for(@track, url: (@track.new_record? ? conference_program_tracks_path : conference_program_track_path(@conference.short_title, @track.short_name))) do |f| + = f.input :name + = f.input :short_name, hint: "A short and unique handle for the track, using only letters, numbers, underscores, and dashes. This will be used to identify the track in URLs etc. Example: 'my_awesome_track'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' } + = f.input :color, input_html: {size: 6, type: 'color'}, required: true + = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, required: true, hint: markdown_hint + = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/tracks/index.html.haml b/app/views/tracks/index.html.haml new file mode 100644 index 00000000..a6347747 --- /dev/null +++ b/app/views/tracks/index.html.haml @@ -0,0 +1,43 @@ +.container + .row + .col-md-12.page-header + %h1 + Track requests for + %span.notranslate + = @conference.title + + - if @tracks.any? + .row + .col-md-12 + %table.table.table-hover#tracks + %thead + %th Name + %th Short name + %th Description + %th Color + %th State + %th Actions + %tbody + - @tracks.each do |track| + %tr + %td + = link_to(conference_program_track_path(@conference.short_title, track.short_name)) do + = track.name + %td + = track.short_name + %td + %p + = truncate(track.description) + %td + %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} + = track.color + %td + = track.state + %td + = link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track.short_name), + method: :get, class: 'btn btn-primary' + + .row + .col-md-12 + - if can? :create, @track + = link_to "New Track request", new_conference_program_track_path(@conference.short_title), class: 'btn btn-success pull-right' diff --git a/app/views/tracks/show.html.haml b/app/views/tracks/show.html.haml new file mode 100644 index 00000000..7ea80c58 --- /dev/null +++ b/app/views/tracks/show.html.haml @@ -0,0 +1,26 @@ +.container + .row + .col-md-12 + .page-header + %h1 + = @track.name + Track + .row + .col-md-8 + %dl.dl-horizontal + %dt + Color: + %dd + %span.label{style: "background-color: #{@track.color}; color: #{ contrast_color(@track.color) }"} + = @track.color + %dt + State: + %dd + = @track.state + %dt + Description + %dd + = @track.description + .row + .col-md-12.text-right + = link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track.short_name), class: 'btn btn-primary' diff --git a/config/routes.rb b/config/routes.rb index db88613f..1643fc6b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -54,7 +54,11 @@ Osem::Application.routes.draw do resource :registration_period resource :program do resources :cfps - resources :tracks + resources :tracks do + member do + patch :toggle_cfp_inclusion + end + end resources :event_types resources :difficulty_levels resources :events do @@ -82,9 +86,15 @@ Osem::Application.routes.draw do resources :campaigns, except: [:show] resources :emails, only: [:show, :update, :index] resources :physical_ticket, only: [:index] - resources :roles, except: [ :new, :create ] do + resources :roles, only: [:edit] + resources :roles, except: [ :new, :create, :edit ] do member do post :toggle_user + get ':track_name' => 'roles#show', as: 'track' + get ':track_name/edit' => 'roles#edit', as: 'track_edit' + patch ':track_name' => 'roles#update' + put ':track_name' => 'roles#update' + post ':track_name/toggle_user' => 'roles#toggle_user', as: 'toggle_user_track' end end @@ -120,6 +130,7 @@ Osem::Application.routes.draw do patch '/restart' => 'proposals#restart' end end + resources :tracks, except: :destroy end # TODO: change conference_registrations to singular resource diff --git a/db/migrate/20170705075039_add_state_cfp_active_and_submitter_reference_to_tracks.rb b/db/migrate/20170705075039_add_state_cfp_active_and_submitter_reference_to_tracks.rb new file mode 100644 index 00000000..9cb7f7de --- /dev/null +++ b/db/migrate/20170705075039_add_state_cfp_active_and_submitter_reference_to_tracks.rb @@ -0,0 +1,8 @@ +class AddStateCfpActiveAndSubmitterReferenceToTracks < ActiveRecord::Migration + def change + add_column :tracks, :state, :string + add_column :tracks, :cfp_active, :boolean + add_column :tracks, :submitter_id, :integer + add_index :tracks, :submitter_id + end +end diff --git a/db/schema.rb b/db/schema.rb index b9f8e3f4..f1a213a5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -483,16 +483,21 @@ ActiveRecord::Schema.define(version: 20170711102511) do end create_table "tracks", force: :cascade do |t| - t.string "guid", null: false - t.string "name", null: false + t.string "guid", null: false + t.string "name", null: false t.text "description" t.string "color" t.datetime "created_at" t.datetime "updated_at" t.integer "program_id" - t.string "short_name", null: false + t.string "short_name", null: false + t.string "state" + t.boolean "cfp_active" + t.integer "submitter_id" end + add_index "tracks", ["submitter_id"], name: "index_tracks_on_submitter_id" + create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false diff --git a/spec/factories/tracks.rb b/spec/factories/tracks.rb index 4334cb4c..091d8d07 100644 --- a/spec/factories/tracks.rb +++ b/spec/factories/tracks.rb @@ -5,5 +5,11 @@ FactoryGirl.define do color { Faker::Color.hex_color } short_name { SecureRandom.urlsafe_base64(5) } program + + trait :self_organized do + association :submitter, factory: :user + state 'new' + cfp_active false + end end end diff --git a/spec/features/track_organizer_ability_spec.rb b/spec/features/track_organizer_ability_spec.rb new file mode 100644 index 00000000..f32392ba --- /dev/null +++ b/spec/features/track_organizer_ability_spec.rb @@ -0,0 +1,244 @@ +require 'spec_helper' + +feature 'Has correct abilities' do + + let(:organization) { create(:organization) } + let(:conference) { create(:full_conference, organization: organization) } + let(:self_organized_track) { create(:track, :self_organized, program: conference.program) } + let(:role_track_organizer) { Role.find_by(name: 'track_organizer', resource: self_organized_track) } + let(:user_track_organizer) { create(:user, role_ids: [role_track_organizer.id]) } + + context 'when user is info desk' do + before do + sign_in user_track_organizer + end + + scenario 'for organization and conference attributes' do + visit admin_conference_path(conference.short_title) + expect(current_path).to eq(admin_conference_path(conference.short_title)) + + expect(page).to have_selector('li.nav-header.nav-header-bigger a', text: 'Dashboard') + expect(page).to_not have_link('Basics', href: "/admin/conferences/#{conference.short_title}/edit") + expect(page).to have_text('Basics') + expect(page).to_not have_link('Contact', href: "/admin/conferences/#{conference.short_title}/contact/edit") + expect(page).to have_link('Commercials', href: "/admin/conferences/#{conference.short_title}/commercials") + expect(page).to_not have_link('Splashpage', href: "/admin/conferences/#{conference.short_title}/splashpage") + expect(page).to_not have_link('Venue', href: "/admin/conferences/#{conference.short_title}/venue") + expect(page).to_not have_link('Rooms', href: "/admin/conferences/#{conference.short_title}/venue/rooms") + expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference.short_title}/lodgings") + expect(page).to have_link('Program', href: "/admin/conferences/#{conference.short_title}/program") + expect(page).to_not have_link('Call for Papers', href: "/admin/conferences/#{conference.short_title}/program/cfps") + expect(page).to_not 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_not have_link('Event Types', href: "/admin/conferences/#{conference.short_title}/program/event_types") + expect(page).to_not have_link('Difficulty Levels', href: "/admin/conferences/#{conference.short_title}/program/difficulty_levels") + expect(page).to_not have_link('Schedules', href: "/admin/conferences/#{conference.short_title}/schedules") + expect(page).to_not have_link('Reports', href: "/admin/conferences/#{conference.short_title}/program/reports") + expect(page).to_not have_link('Registrations', href: "/admin/conferences/#{conference.short_title}/registrations") + expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period") + expect(page).to_not have_link('Questions', href: "/admin/conferences/#{conference.short_title}/questions") + expect(page).to_not have_text('Donations') + expect(page).to_not have_link('Sponsorship Levels', href: "/admin/conferences/#{conference.short_title}/sponsorship_levels") + expect(page).to_not have_link('Sponsors', href: "/admin/conferences/#{conference.short_title}/sponsors") + expect(page).to_not have_link('Tickets', href: "/admin/conferences/#{conference.short_title}/tickets") + expect(page).to_not have_text('Objectives') + expect(page).to_not have_link('Campaigns', href: "/admin/conferences/#{conference.short_title}/campaigns") + expect(page).to_not have_link('Goals', href: "/admin/conferences/#{conference.short_title}/targets") + expect(page).to_not have_link('E-Mails', href: "/admin/conferences/#{conference.short_title}/emails") + expect(page).to have_link('Roles', href: "/admin/conferences/#{conference.short_title}/roles") + expect(page).to_not have_link('Resources', href: "/admin/conferences/#{conference.short_title}/resources") + expect(page).to_not have_link('New Conference', href: '/admin/conferences/new') + + visit edit_admin_conference_path(conference.short_title) + expect(current_path).to eq root_path + + visit edit_admin_conference_contact_path(conference.short_title) + expect(current_path).to eq root_path + + visit admin_conference_commercials_path(conference.short_title) + expect(current_path).to eq admin_conference_commercials_path(conference.short_title) + + visit new_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq root_path + + visit edit_admin_conference_splashpage_path(conference.short_title) + expect(current_path).to eq root_path + + visit new_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq root_path + + conference.venue = create(:venue) + visit edit_admin_conference_venue_path(conference.short_title) + expect(current_path).to eq root_path + + visit admin_conference_venue_rooms_path(conference.short_title) + expect(current_path).to eq root_path + + create(:room, venue: conference.venue) + visit edit_admin_conference_venue_room_path(conference.short_title, conference.venue.rooms.first) + expect(current_path).to eq root_path + + visit admin_conference_lodgings_path(conference.short_title) + expect(current_path).to eq root_path + + visit new_admin_conference_lodging_path(conference.short_title) + expect(current_path).to eq root_path + + create(:lodging, conference: conference) + visit edit_admin_conference_lodging_path(conference.short_title, conference.lodgings.first) + expect(current_path).to eq root_path + + visit new_admin_conference_program_path(conference.short_title) + expect(current_path).to eq root_path + + visit edit_admin_conference_program_path(conference.short_title) + expect(current_path).to eq root_path + + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq root_path + + visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) + expect(current_path).to eq root_path + + visit admin_conference_program_events_path(conference.short_title) + expect(current_path).to eq admin_conference_program_events_path(conference.short_title) + + create(:event, program: conference.program) + visit edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first) + expect(current_path).to eq root_path + + visit admin_conference_program_event_types_path(conference.short_title) + expect(current_path).to eq root_path + + visit new_admin_conference_program_event_type_path(conference.short_title) + expect(current_path).to eq root_path + + visit edit_admin_conference_program_event_type_path(conference.short_title, conference.program.event_types.first) + expect(current_path).to eq root_path + + visit admin_conference_program_difficulty_levels_path(conference.short_title) + expect(current_path).to eq root_path + + visit new_admin_conference_program_difficulty_level_path(conference.short_title) + expect(current_path).to eq root_path + + visit edit_admin_conference_program_difficulty_level_path(conference.short_title, conference.program.difficulty_levels.first) + expect(current_path).to eq root_path + + visit admin_conference_schedules_path(conference.short_title) + expect(current_path).to eq root_path + + create(:schedule, program: conference.program) + visit admin_conference_schedule_path(conference.short_title, conference.program.schedules.first) + expect(current_path).to eq root_path + + visit admin_conference_program_reports_path(conference.short_title) + expect(current_path).to eq admin_conference_program_reports_path(conference.short_title) + + visit admin_conference_registrations_path(conference.short_title) + expect(current_path).to eq admin_conference_registrations_path(conference.short_title) + + create(:registration, user: create(:user), conference: conference) + visit edit_admin_conference_registration_path(conference.short_title, conference.registrations.first) + expect(current_path).to eq root_path + + visit new_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq root_path + + create(:registration_period, conference: conference) + visit edit_admin_conference_registration_period_path(conference.short_title) + expect(current_path).to eq root_path + + visit admin_conference_questions_path(conference.short_title) + expect(current_path).to eq root_path + + visit admin_conference_sponsorship_levels_path(conference.short_title) + expect(current_path).to eq root_path + + visit new_admin_conference_sponsorship_level_path(conference.short_title) + expect(current_path).to eq root_path + + create(:sponsorship_level, conference: conference) + visit edit_admin_conference_sponsorship_level_path(conference.short_title, conference.sponsorship_levels.first) + expect(current_path).to eq root_path + + visit admin_conference_sponsors_path(conference.short_title) + expect(current_path).to eq root_path + + visit new_admin_conference_sponsor_path(conference.short_title) + expect(current_path).to eq root_path + + create(:sponsor, conference: conference, sponsorship_level: conference.sponsorship_levels.first) + visit edit_admin_conference_sponsor_path(conference.short_title, conference.sponsors.first) + expect(current_path).to eq root_path + + visit admin_conference_tickets_path(conference.short_title) + expect(current_path).to eq root_path + + visit new_admin_conference_ticket_path(conference.short_title) + expect(current_path).to eq root_path + + create(:ticket, conference: conference) + visit edit_admin_conference_ticket_path(conference.short_title, conference.tickets.first) + expect(current_path).to eq root_path + + visit admin_conference_campaigns_path(conference.short_title) + expect(current_path).to eq root_path + + visit new_admin_conference_campaign_path(conference.short_title) + expect(current_path).to eq root_path + + create(:campaign, conference: conference) + visit edit_admin_conference_campaign_path(conference.short_title, conference.campaigns.first) + expect(current_path).to eq root_path + + visit admin_conference_targets_path(conference.short_title) + expect(current_path).to eq root_path + + visit new_admin_conference_target_path(conference.short_title) + expect(current_path).to eq root_path + + create(:target, conference: conference) + visit edit_admin_conference_target_path(conference.short_title, conference.targets.first) + expect(current_path).to eq root_path + + visit admin_conference_program_tracks_path(conference.short_title) + expect(current_path).to eq admin_conference_program_tracks_path(conference.short_title) + + visit new_admin_conference_program_track_path(conference.short_title) + expect(current_path).to eq root_path + + other_track = create(:track, program: conference.program) + visit admin_conference_program_track_path(conference.short_title, other_track.short_name) + expect(current_path).to eq root_path + + visit edit_admin_conference_program_track_path(conference.short_title, other_track.short_name) + expect(current_path).to eq root_path + + visit admin_conference_program_track_path(conference.short_title, self_organized_track.short_name) + expect(current_path).to eq admin_conference_program_track_path(conference.short_title, self_organized_track.short_name) + + visit edit_admin_conference_program_track_path(conference.short_title, self_organized_track.short_name) + expect(current_path).to eq edit_admin_conference_program_track_path(conference.short_title, self_organized_track.short_name) + + visit admin_conference_roles_path(conference.short_title) + expect(current_path).to eq admin_conference_roles_path(conference.short_title) + + visit admin_conference_emails_path(conference.short_title) + expect(current_path).to eq root_path + + visit admin_conference_resources_path(conference.short_title) + expect(current_path).to eq admin_conference_resources_path(conference.short_title) + + visit new_admin_conference_resource_path(conference.short_title) + expect(current_path).to eq new_admin_conference_resource_path(conference.short_title) + + create(:resource, conference: conference) + visit edit_admin_conference_resource_path(conference.short_title, conference.resources.first) + expect(current_path).to eq root_path + + visit admin_revision_history_path + expect(current_path).to eq root_path + end + end +end diff --git a/spec/models/admin_ability_spec.rb b/spec/models/admin_ability_spec.rb index 486ff295..9baae4a9 100644 --- a/spec/models/admin_ability_spec.rb +++ b/spec/models/admin_ability_spec.rb @@ -44,6 +44,8 @@ describe 'User with admin role' do let!(:my_event_schedule) { create(:event_schedule, schedule: my_schedule) } let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) } + let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program) } + context 'user #is_admin?' do let(:venue) { my_conference.venue } let(:room) { create(:room, venue: venue) } @@ -69,6 +71,19 @@ describe 'User with admin role' do it{ should be_able_to(:show, Role.find_by(name: role, resource: other_conference)) } it{ should be_able_to(:index, Role.find_by(name: role, resource: other_conference)) } end + + context 'accesses track organizers' do + before :each do + other_self_organized_track = create(:track, :self_organized) + @other_track_organizer_role = Role.find_by(name: 'track_organizer', resource: other_self_organized_track) + end + + it{ should_not be_able_to(:toggle_user, @other_track_organizer_role) } + it{ should_not be_able_to(:update, @other_track_organizer_role) } + it{ should_not be_able_to(:edit, @other_track_organizer_role) } + it{ should be_able_to(:show, @other_track_organizer_role) } + it{ should be_able_to(:index, @other_track_organizer_role) } + end end shared_examples 'user with non-organizer role' do |role_name| @@ -83,6 +98,22 @@ describe 'User with admin role' do it{ should be_able_to(:show, Role.find_by(name: role, resource: my_conference)) } it{ should be_able_to(:index, Role.find_by(name: role, resource: my_conference)) } end + + context 'accesses track organizers' do + before :each do + @track_organizer_role = Role.find_by(name: 'track_organizer', resource: my_self_organized_track) + end + + if role_name == 'track_organizer' + it{ should be_able_to(:toggle_user, @track_organizer_role) } + else + it{ should_not be_able_to(:toggle_user, @track_organizer_role) } + end + it{ should_not be_able_to(:update, @track_organizer_role) } + it{ should_not be_able_to(:edit, @track_organizer_role) } + it{ should be_able_to(:show, @track_organizer_role) } + it{ should be_able_to(:index, @track_organizer_role) } + end end context 'when user has the role organization_admin' do @@ -186,6 +217,18 @@ describe 'User with admin role' do it{ should be_able_to(:index, Role.find_by(name: role, resource: my_conference)) } end + context 'can manage track organizers' do + before :each do + @track_organizer_role = Role.find_by(name: 'track_organizer', resource: my_self_organized_track) + end + + it{ should be_able_to(:toggle_user, @track_organizer_role) } + it{ should be_able_to(:edit, @track_organizer_role) } + it{ should be_able_to(:update, @track_organizer_role) } + it{ should be_able_to(:show, @track_organizer_role) } + it{ should be_able_to(:index, @track_organizer_role) } + end + it_behaves_like 'user with any role' end @@ -392,5 +435,74 @@ describe 'User with admin role' do it_behaves_like 'user with any role' it_behaves_like 'user with non-organizer role', 'volunteers_coordinator' end + + context 'when user has the role track_organizer' do + let(:role) { Role.find_by(name: 'track_organizer', resource: my_self_organized_track) } + let(:user) { create(:user, role_ids: [role.id]) } + let(:new_track) { build(:track, program: my_conference.program) } + + it{ should_not be_able_to(:new, Conference.new) } + it{ should_not be_able_to(:create, Conference.new) } + it{ should_not be_able_to(:manage, my_conference) } + it{ should_not be_able_to(:manage, conference_public) } + it{ should_not be_able_to(:manage, my_conference.splashpage) } + it{ should_not be_able_to(:manage, conference_public.splashpage) } + it{ should_not be_able_to(:manage, my_conference.contact) } + it{ should_not be_able_to(:manage, conference_public.contact) } + it{ should_not be_able_to(:manage, my_conference.email_settings) } + it{ should_not be_able_to(:manage, conference_public.email_settings) } + it{ should_not be_able_to(:manage, my_conference.campaigns.first) } + it{ should_not be_able_to(:manage, conference_public.campaigns.first) } + it{ should_not be_able_to(:manage, my_conference.targets.first) } + it{ should_not be_able_to(:manage, conference_public.targets.first) } + it{ should_not be_able_to(:manage, my_conference.commercials.first) } + it{ should_not be_able_to(:manage, conference_public.commercials.first) } + it{ should_not be_able_to(:manage, my_conference.registration_period) } + it{ should_not be_able_to(:manage, conference_public.registration_period) } + it{ should_not be_able_to(:manage, my_conference.questions.first) } + it{ should_not be_able_to(:manage, conference_public.questions.first) } + it{ should_not be_able_to(:manage, my_conference.program.cfp) } + it{ should_not be_able_to(:manage, conference_public.program.cfp) } + it{ should_not be_able_to(:manage, my_schedule) } + it{ should_not be_able_to(:manage, other_schedule) } + it{ should_not be_able_to(:manage, my_event_schedule) } + it{ should_not be_able_to(:manage, other_event_schedule) } + it{ should_not be_able_to(:manage, my_conference.venue) } + it{ should_not be_able_to(:show, my_conference.venue) } + it{ should_not be_able_to(:manage, conference_public.venue) } + it{ should_not be_able_to(:manage, my_conference.lodgings.first) } + it{ should_not be_able_to(:manage, conference_public.lodgings.first) } + it{ should_not be_able_to(:manage, my_conference.sponsors.first) } + it{ should_not be_able_to(:manage, conference_public.sponsors.first) } + it{ should_not be_able_to(:manage, my_conference.sponsorship_levels.first) } + it{ should_not be_able_to(:manage, conference_public.sponsorship_levels.first) } + it{ should_not be_able_to(:manage, my_conference.tickets.first) } + it{ should_not be_able_to(:manage, conference_public.tickets.first) } + + it{ should_not be_able_to(:manage, registration) } + it{ should_not be_able_to(:manage, other_registration) } + + it{ should_not be_able_to(:manage, my_event) } + it{ should_not be_able_to(:manage, other_event) } + it{ should_not be_able_to(:manage, my_event.event_type) } + it{ should_not be_able_to(:manage, other_event.event_type) } + it{ should_not be_able_to(:manage, my_event.track) } + it{ should_not be_able_to(:manage, other_event.track) } + it{ should_not be_able_to(:manage, my_event.difficulty_level) } + it{ should_not be_able_to(:manage, other_event.difficulty_level) } + it{ should_not be_able_to(:manage, my_event.commercials.first) } + it{ should_not be_able_to(:manage, other_event.commercials.first) } + it{ should_not be_able_to(:index, my_event.comment_threads.first) } + it{ should_not be_able_to(:index, other_event.comment_threads.first) } + + it{ should_not be_able_to(:manage, resource) } + + it{ should be_able_to(:show, my_conference.program) } + it{ should be_able_to(:update, new_track) } + it{ should be_able_to(:manage, my_self_organized_track) } + + it_behaves_like 'user with any role' + it_behaves_like 'user with non-organizer role', 'track_organizer' + end end end diff --git a/spec/models/track_spec.rb b/spec/models/track_spec.rb new file mode 100644 index 00000000..840641cb --- /dev/null +++ b/spec/models/track_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' + +describe Track do + subject { create(:track) } + let(:track) { create(:track) } + let(:self_organized_track) { create(:track, :self_organized) } + + describe 'association' do + it { is_expected.to belong_to(:program) } + it { is_expected.to belong_to(:submitter).class_name('User') } + it { is_expected.to have_many(:events) } + end + + describe 'validation' do + it 'has a valid factory' do + expect(build(:track)).to be_valid + end + + it { is_expected.to validate_presence_of(:name) } + it { is_expected.to allow_value('#ABCDEF').for(:color) } + it { is_expected.to allow_value('#124689').for(:color) } + it { is_expected.to validate_presence_of(:short_name) } + it { is_expected.to allow_value('My_track_name').for(:short_name) } + it { is_expected.to_not allow_value('My track name').for(:short_name) } + it { is_expected.to validate_uniqueness_of(:short_name).scoped_to(:program_id) } + + context 'when self-organized' do + before :each do + allow(subject).to receive(:self_organized?).and_return(true) + end + + it { is_expected.to validate_presence_of(:state) } + it { is_expected.to validate_inclusion_of(:cfp_active).in_array([true, false]) } + end + + context 'when regular' do + before :each do + allow(subject).to receive(:self_organized?).and_return(false) + end + + it { is_expected.to_not validate_presence_of(:state) } + it { is_expected.to_not validate_inclusion_of(:cfp_active) } + end + end + + describe '#self_organized?' do + it 'returns true when it has a submitter' do + expect(self_organized_track.submitter).to be_a User + expect(self_organized_track.self_organized?).to eq true + end + + it 'returns false when it doesn\'t have a submitter' do + expect(track.submitter).to eq nil + expect(track.self_organized?).to eq false + end + end +end From 9671696adf7e42d4610b96e381459ecaa22548b8 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Fri, 7 Jul 2017 00:21:26 +0300 Subject: [PATCH 099/237] Add to_param to the Track model And update the urls --- app/controllers/admin/roles_controller.rb | 8 ++++---- app/models/track.rb | 4 ++++ app/views/admin/roles/index.html.haml | 13 +++++++------ app/views/admin/roles/show.html.haml | 2 +- app/views/admin/tracks/_form.html.haml | 2 +- app/views/admin/tracks/index.html.haml | 11 ++++++----- app/views/tracks/_form.html.haml | 2 +- app/views/tracks/index.html.haml | 4 ++-- app/views/tracks/show.html.haml | 2 +- spec/features/track_organizer_ability_spec.rb | 12 ++++++------ 10 files changed, 33 insertions(+), 27 deletions(-) diff --git a/app/controllers/admin/roles_controller.rb b/app/controllers/admin/roles_controller.rb index 15bf5e2b..e4b83241 100644 --- a/app/controllers/admin/roles_controller.rb +++ b/app/controllers/admin/roles_controller.rb @@ -15,7 +15,7 @@ module Admin def show @url = if @track - toggle_user_track_admin_conference_role_path(@conference.short_title, @role.name, @track.name.tr(' ', '_')) + toggle_user_track_admin_conference_role_path(@conference.short_title, @role.name, @track) else toggle_user_admin_conference_role_path(@conference.short_title, @role.name) end @@ -24,7 +24,7 @@ module Admin def edit @url = if @track - track_admin_conference_role_path(@conference.short_title, @role.name, @track.name.tr(' ', '_')) + track_admin_conference_role_path(@conference.short_title, @role.name, @track) else admin_conference_role_path(@conference.short_title, @role.name) end @@ -36,7 +36,7 @@ module Admin if @role.update_attributes(role_params) url = if @track - track_admin_conference_role_path(@conference.short_title, @role.name, @track.name.tr(' ', '_')) + track_admin_conference_role_path(@conference.short_title, @role.name, @track) else admin_conference_role_path(@conference.short_title, @role.name) end @@ -55,7 +55,7 @@ module Admin state = user_params[:state] url = if @track - track_admin_conference_role_path(@conference.short_title, @role.name, @track.name.tr(' ', '_')) + track_admin_conference_role_path(@conference.short_title, @role.name, @track) else admin_conference_role_path(@conference.short_title, @role.name) end diff --git a/app/models/track.rb b/app/models/track.rb index a38cf458..2b37d1bb 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -39,6 +39,10 @@ class Track < ActiveRecord::Base false end + def to_param + short_name + end + private def generate_guid diff --git a/app/views/admin/roles/index.html.haml b/app/views/admin/roles/index.html.haml index 1310b133..4a100025 100644 --- a/app/views/admin/roles/index.html.haml +++ b/app/views/admin/roles/index.html.haml @@ -22,19 +22,20 @@ %td = role.description - if role.resource_type == 'Track' - - track = Track.find(role.resource_id) - = link_to track.name, admin_conference_program_track_path(@conference.short_title, track) + = link_to role.resource.name, admin_conference_program_track_path(@conference.short_title, role.resource) %td = role.users.pluck(:name).first(5).join ', ' - if role.users.count > 5 - = link_to '...', admin_conference_role_path(@conference.short_title, role.name) + - if role.resource_type == 'Track' + = link_to '...', track_admin_conference_role_path(@conference.short_title, role.name, role.resource) + - else + = link_to '...', admin_conference_role_path(@conference.short_title, role.name) %td .btn-group - if role.resource_type == 'Track' - - track_name = Track.find(role.resource_id).short_name - = link_to 'Users', track_admin_conference_role_path(@conference.short_title, role.name, track_name), class: 'btn btn-success' + = link_to 'Users', track_admin_conference_role_path(@conference.short_title, role.name, role.resource), class: 'btn btn-success' - if can? :edit, role - = link_to 'Edit', track_edit_admin_conference_role_path(@conference.short_title, role.name, track_name), class: 'btn btn-primary' + = link_to 'Edit', track_edit_admin_conference_role_path(@conference.short_title, role.name, role.resource), class: 'btn btn-primary' - else = link_to 'Users', admin_conference_role_path(@conference.short_title, role.name), class: 'btn btn-success' - if can? :edit, role diff --git a/app/views/admin/roles/show.html.haml b/app/views/admin/roles/show.html.haml index d7dcef8d..ee249975 100644 --- a/app/views/admin/roles/show.html.haml +++ b/app/views/admin/roles/show.html.haml @@ -7,7 +7,7 @@ = @role.name.titleize - if can? :edit, @role - if @track - = link_to 'Edit', track_edit_admin_conference_role_path(@conference.short_title, @role.name, @track.short_name), class: 'btn btn-primary pull-right' + = link_to 'Edit', track_edit_admin_conference_role_path(@conference.short_title, @role.name, @track), class: 'btn btn-primary pull-right' - else = link_to 'Edit', edit_admin_conference_role_path(@conference.short_title, @role.name), class: 'btn btn-primary pull-right' .text-muted diff --git a/app/views/admin/tracks/_form.html.haml b/app/views/admin/tracks/_form.html.haml index 76833e66..fe7f014a 100644 --- a/app/views/admin/tracks/_form.html.haml +++ b/app/views/admin/tracks/_form.html.haml @@ -8,7 +8,7 @@ Track .row .col-md-12 - = semantic_form_for(@track, url: (@track.new_record? ? admin_conference_program_tracks_path : admin_conference_program_track_path(@conference.short_title, @track.short_name))) do |f| + = semantic_form_for(@track, url: (@track.new_record? ? admin_conference_program_tracks_path : admin_conference_program_track_path(@conference.short_title, @track))) do |f| = f.input :name = f.input :short_name, hint: "A short and unique handle for the track, using only letters, numbers, underscores, and dashes. This will be used to identify the track in URLs etc. Example: 'my_awesome_track'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' } = f.input :color, input_html: {size: 6, type: 'color'}, required: true diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 94193088..9abf1d98 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -20,7 +20,7 @@ - @tracks.each do |track| %tr %td - = link_to(admin_conference_program_track_path(@conference.short_title, track.short_name)) do + = link_to(admin_conference_program_track_path(@conference.short_title, track)) do = track.name %td = track.short_name @@ -54,11 +54,12 @@ %i.fa.fa-check %td .btn-group{role: "group"} - = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track.short_name), + = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), method: :get, class: 'btn btn-primary' - = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track.short_name), - method: :delete, class: 'btn btn-danger', - data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } + - if can? :destroy, track + = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), + method: :delete, class: 'btn btn-danger', + data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } .row .col-md-12.text-right = link_to 'New Track', new_admin_conference_program_track_path(@conference.short_title), class: 'btn btn-success' diff --git a/app/views/tracks/_form.html.haml b/app/views/tracks/_form.html.haml index a10a72a9..0e48a851 100644 --- a/app/views/tracks/_form.html.haml +++ b/app/views/tracks/_form.html.haml @@ -9,7 +9,7 @@ Track .row .col-md-12 - = semantic_form_for(@track, url: (@track.new_record? ? conference_program_tracks_path : conference_program_track_path(@conference.short_title, @track.short_name))) do |f| + = semantic_form_for(@track, url: (@track.new_record? ? conference_program_tracks_path : conference_program_track_path(@conference.short_title, @track))) do |f| = f.input :name = f.input :short_name, hint: "A short and unique handle for the track, using only letters, numbers, underscores, and dashes. This will be used to identify the track in URLs etc. Example: 'my_awesome_track'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' } = f.input :color, input_html: {size: 6, type: 'color'}, required: true diff --git a/app/views/tracks/index.html.haml b/app/views/tracks/index.html.haml index a6347747..d4670bf4 100644 --- a/app/views/tracks/index.html.haml +++ b/app/views/tracks/index.html.haml @@ -21,7 +21,7 @@ - @tracks.each do |track| %tr %td - = link_to(conference_program_track_path(@conference.short_title, track.short_name)) do + = link_to(conference_program_track_path(@conference.short_title, track)) do = track.name %td = track.short_name @@ -34,7 +34,7 @@ %td = track.state %td - = link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track.short_name), + = link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track), method: :get, class: 'btn btn-primary' .row diff --git a/app/views/tracks/show.html.haml b/app/views/tracks/show.html.haml index 7ea80c58..c08818eb 100644 --- a/app/views/tracks/show.html.haml +++ b/app/views/tracks/show.html.haml @@ -23,4 +23,4 @@ = @track.description .row .col-md-12.text-right - = link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track.short_name), class: 'btn btn-primary' + = link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-primary' diff --git a/spec/features/track_organizer_ability_spec.rb b/spec/features/track_organizer_ability_spec.rb index f32392ba..f79eba05 100644 --- a/spec/features/track_organizer_ability_spec.rb +++ b/spec/features/track_organizer_ability_spec.rb @@ -209,17 +209,17 @@ feature 'Has correct abilities' do expect(current_path).to eq root_path other_track = create(:track, program: conference.program) - visit admin_conference_program_track_path(conference.short_title, other_track.short_name) + visit admin_conference_program_track_path(conference.short_title, other_track) expect(current_path).to eq root_path - visit edit_admin_conference_program_track_path(conference.short_title, other_track.short_name) + visit edit_admin_conference_program_track_path(conference.short_title, other_track) expect(current_path).to eq root_path - visit admin_conference_program_track_path(conference.short_title, self_organized_track.short_name) - expect(current_path).to eq admin_conference_program_track_path(conference.short_title, self_organized_track.short_name) + visit admin_conference_program_track_path(conference.short_title, self_organized_track) + expect(current_path).to eq admin_conference_program_track_path(conference.short_title, self_organized_track) - visit edit_admin_conference_program_track_path(conference.short_title, self_organized_track.short_name) - expect(current_path).to eq edit_admin_conference_program_track_path(conference.short_title, self_organized_track.short_name) + visit edit_admin_conference_program_track_path(conference.short_title, self_organized_track) + expect(current_path).to eq edit_admin_conference_program_track_path(conference.short_title, self_organized_track) visit admin_conference_roles_path(conference.short_title) expect(current_path).to eq admin_conference_roles_path(conference.short_title) From e3b51dfc2b818c2ed75df915da900495efa1707d Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Fri, 7 Jul 2017 16:31:24 +0300 Subject: [PATCH 100/237] Add TrackControllers specs --- app/controllers/tracks_controller.rb | 2 +- app/views/admin/tracks/index.html.haml | 4 +- .../admin/tracks_controller_spec.rb | 256 ++++++++++++++++++ spec/controllers/tracks_controller_spec.rb | 179 ++++++++++++ 4 files changed, 438 insertions(+), 3 deletions(-) create mode 100644 spec/controllers/admin/tracks_controller_spec.rb create mode 100644 spec/controllers/tracks_controller_spec.rb diff --git a/app/controllers/tracks_controller.rb b/app/controllers/tracks_controller.rb index f346b0d1..529767cd 100644 --- a/app/controllers/tracks_controller.rb +++ b/app/controllers/tracks_controller.rb @@ -31,7 +31,7 @@ class TracksController < ApplicationController def update if @track.update_attributes(track_params) - redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title), + redirect_to conference_program_tracks_path(conference_id: @conference.short_title), notice: 'Track request successfully updated.' else flash.now[:error] = "Track request update failed: #{@track.errors.full_messages.join('. ')}." diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 9abf1d98..1cda360a 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -42,9 +42,9 @@ N/A %td - if track.self_organized? - = check_box_tag "#{@conference.short_title}_#{track.id}", track.id, track.cfp_active, + = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, class: 'switch-checkbox', method: :patch, - url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.id)+"?included=", + url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.short_name)+"?included=", data: { size: 'small', on_color: 'success', off_color: 'warning', diff --git a/spec/controllers/admin/tracks_controller_spec.rb b/spec/controllers/admin/tracks_controller_spec.rb new file mode 100644 index 00000000..2177af2f --- /dev/null +++ b/spec/controllers/admin/tracks_controller_spec.rb @@ -0,0 +1,256 @@ +require 'spec_helper' + +describe Admin::TracksController do + let(:admin) { create(:admin) } + + let(:conference) { create(:conference) } + let!(:track) { create(:track, program: conference.program, color: '#800080') } + let!(:self_organized_track) { create(:track, :self_organized, program: conference.program) } + + before :each do + sign_in(admin) + end + + describe 'GET #index' do + before :each do + get :index, conference_id: conference.short_title + end + + it 'assigns @tracks with the correct values' do + expect(assigns(:tracks).length).to eq 2 + expect(assigns(:tracks).include?(track)).to eq true + expect(assigns(:tracks).include?(self_organized_track)).to eq true + end + + it 'renders the index template' do + expect(response).to render_template :index + end + end + + describe 'GET #show' do + before :each do + get :show, conference_id: conference.short_title, id: track.short_name + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq track + end + + it 'renders the show template' do + expect(response).to render_template :show + end + end + + describe 'GET #new' do + before :each do + get :new, conference_id: conference.short_title + end + + it 'assigns a new track with the correct conference' do + expect(assigns(:track)).to be_a Track + expect(assigns(:track).new_record?).to eq true + expect(assigns(:track).program_id).to eq conference.program.id + end + + it 'renders the new template' do + expect(response).to render_template :new + end + end + + describe 'POST #create' do + context 'saves successfuly' do + before :each do + post :create, track: attributes_for(:track), conference_id: conference.short_title + end + + it 'assigns a new track with the correct conference' do + expect(assigns(:track)).to be_a Track + expect(assigns(:track).new_record?).to eq false + expect(assigns(:track).program_id).to eq conference.program.id + end + + it 'redirects to admin tracks index path' do + expect(response).to redirect_to admin_conference_program_tracks_path(conference_id: conference.short_title) + end + + it 'shows success message in flash notice' do + expect(flash[:notice]).to match('Track successfully created.') + end + + it 'creates new track' do + expect(Track.find(assigns(:track).id)).to be_a Track + end + end + + context 'save fails' do + before :each do + allow_any_instance_of(Track).to receive(:save).and_return(false) + post :create, track: attributes_for(:track, short_name: 'my_track'), conference_id: conference.short_title + end + + it 'assigns a new track with the correct conference' do + expect(assigns(:track)).to be_a Track + expect(assigns(:track).new_record?).to eq true + expect(assigns(:track).program_id).to eq conference.program.id + end + + it 'renders the new template' do + expect(response).to render_template :new + end + + it 'shows error in flash message' do + expect(flash[:error]).to match("Creating Track failed: #{assigns(:track).errors.full_messages.join('. ')}.") + end + + it 'does not create a new track' do + expect(conference.program.tracks.find_by(short_name: 'my_track')).to eq nil + end + end + end + + describe 'GET #edit' do + before :each do + get :edit, conference_id: conference.short_title, id: track.short_name + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq track + end + + it 'renders the show template' do + expect(response).to render_template :edit + end + end + + describe 'PATCH #update' do + context 'updates successfully' do + before :each do + patch :update, track: attributes_for(:track, color: '#FF0000'), + conference_id: conference.short_title, + id: track.short_name + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq track + end + + it 'redirects to admin tracks index path' do + expect(response).to redirect_to admin_conference_program_tracks_path(conference_id: conference.short_title) + end + + it 'shows success message in flash notice' do + expect(flash[:notice]).to match('Track successfully updated.') + end + + it 'updates the track' do + track.reload + expect(track.color).to eq '#FF0000' + end + end + + context 'update fails' do + before :each do + allow_any_instance_of(Track).to receive(:save).and_return(false) + patch :update, track: attributes_for(:track, color: '#FF0000'), + conference_id: conference.short_title, + id: track.short_name + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq track + end + + it 'renders edit template' do + expect(response).to render_template :edit + end + + it 'shows error in flash message' do + expect(flash[:error]).to match("Track update failed: #{assigns(:track).errors.full_messages.join('. ')}.") + end + + it 'does not update the track' do + track.reload + expect(track.color).to eq '#800080' + end + end + end + + describe 'DELETE #destroy' do + context 'deletes successfully' do + before :each do + delete :destroy, conference_id: conference.short_title, id: track.short_name + end + + it 'redirects to admin tracks index path' do + expect(response).to redirect_to admin_conference_program_tracks_path(conference_id: conference.short_title) + end + + it 'shows success message in flash notice' do + expect(flash[:notice]).to match('Track successfully deleted.') + end + + it 'deletes the track' do + expect(Track.find_by(id: track)).to eq nil + end + end + + context 'delete fails' do + before :each do + allow_any_instance_of(Track).to receive(:destroy).and_return(false) + delete :destroy, conference_id: conference.short_title, id: track.short_name + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq track + end + + it 'redirects to admin tracks index path' do + expect(response).to redirect_to admin_conference_program_tracks_path(conference_id: conference.short_title) + end + + it 'shows error in flash message' do + expect(flash[:error]).to match("Track couldn't be deleted. #{track.errors.full_messages.join('. ')}.") + end + + it 'does not delete the track' do + expect(Track.find(track.id)).to eq track + end + end + end + + describe 'PATCH #toggle_cfp_inclusion' do + context 'cfp_active is false' do + before :each do + self_organized_track.cfp_active = false + self_organized_track.save! + patch :toggle_cfp_inclusion, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'becomes true' do + expect(self_organized_track.cfp_active).to eq true + end + end + + context 'cfp_active is true' do + before :each do + self_organized_track.cfp_active = true + self_organized_track.save! + patch :toggle_cfp_inclusion, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'becomes false' do + expect(self_organized_track.cfp_active).to eq false + end + end + end +end diff --git a/spec/controllers/tracks_controller_spec.rb b/spec/controllers/tracks_controller_spec.rb new file mode 100644 index 00000000..373435c2 --- /dev/null +++ b/spec/controllers/tracks_controller_spec.rb @@ -0,0 +1,179 @@ +require 'spec_helper' + +describe TracksController do + # A regular user should be used when the track requests have been enabled + let(:user) { create(:admin) } + + let(:conference) { create(:conference) } + let!(:regular_track) { create(:track, program: conference.program) } + let!(:self_organized_track) { create(:track, :self_organized, program: conference.program, submitter: user, color: '#800080') } + + before :each do + sign_in(user) + end + + describe 'GET #index' do + before :each do + get :index, conference_id: conference.short_title + end + + it 'assigns @tracks with the correct values' do + expect(assigns(:tracks).length).to eq 1 + expect(assigns(:tracks).include?(regular_track)).to eq false + expect(assigns(:tracks).include?(self_organized_track)).to eq true + end + + it 'renders the index template' do + expect(response).to render_template :index + end + end + + describe 'GET #show' do + before :each do + get :show, conference_id: conference.short_title, id: self_organized_track.short_name + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'renders the show template' do + expect(response).to render_template :show + end + end + + describe 'GET #new' do + before :each do + get :new, conference_id: conference.short_title + end + + it 'assigns a new track with the correct conference' do + expect(assigns(:track)).to be_a Track + expect(assigns(:track).new_record?).to eq true + expect(assigns(:track).program_id).to eq conference.program.id + end + + it 'renders the new template' do + expect(response).to render_template :new + end + end + + describe 'POST #create' do + context 'saves successfuly' do + before :each do + post :create, track: attributes_for(:track, short_name: 'my_track'), conference_id: conference.short_title + end + + it 'redirects to tracks index path' do + expect(response).to redirect_to conference_program_tracks_path(conference_id: conference.short_title) + end + + it 'shows success message in flash notice' do + expect(flash[:notice]).to match('Track request successfully created.') + end + + it 'creates new track' do + expect(assigns(:track).new_record?).to eq false + end + + it 'the new tracks has the correct attributes' do + expect(assigns(:track).program_id).to eq conference.program.id + expect(assigns(:track).submitter).to eq user + expect(assigns(:track).state).to eq 'new' + expect(assigns(:track).cfp_active).to eq false + end + end + + context 'save fails' do + before :each do + allow_any_instance_of(Track).to receive(:save).and_return(false) + post :create, track: attributes_for(:track, short_name: 'my_track'), conference_id: conference.short_title + end + + it 'assigns a new track with the correct conference' do + expect(assigns(:track)).to be_a Track + expect(assigns(:track).new_record?).to eq true + expect(assigns(:track).program_id).to eq conference.program.id + end + + it 'renders the new template' do + expect(response).to render_template :new + end + + it 'shows error in flash message' do + expect(flash[:error]).to match("Creating Track request failed: #{assigns(:track).errors.full_messages.join('. ')}.") + end + + it 'does not create a new track' do + expect(conference.program.tracks.find_by(short_name: 'my_track')).to eq nil + end + end + end + + describe 'GET #edit' do + before :each do + get :edit, conference_id: conference.short_title, id: self_organized_track.short_name + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'renders the show template' do + expect(response).to render_template :edit + end + end + + describe 'PATCH #update' do + context 'updates successfully' do + before :each do + patch :update, track: attributes_for(:track, color: '#FF0000'), + conference_id: conference.short_title, + id: self_organized_track.short_name + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'redirects to tracks index path' do + expect(response).to redirect_to conference_program_tracks_path(conference_id: conference.short_title) + end + + it 'shows success message in flash notice' do + expect(flash[:notice]).to match('Track request successfully updated.') + end + + it 'updates the track' do + self_organized_track.reload + expect(self_organized_track.color).to eq '#FF0000' + end + end + + context 'update fails' do + before :each do + allow_any_instance_of(Track).to receive(:save).and_return(false) + patch :update, track: attributes_for(:track, color: '#FF0000'), + conference_id: conference.short_title, + id: self_organized_track.short_name + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'renders edit template' do + expect(response).to render_template :edit + end + + it 'shows error in flash message' do + expect(flash[:error]).to match("Track request update failed: #{assigns(:track).errors.full_messages.join('. ')}.") + end + + it 'does not update the track' do + self_organized_track.reload + expect(self_organized_track.color).to eq '#800080' + end + end + end +end From 9c58397cd21c19d706227a3c0741c7baea9de07e Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 5 Jul 2017 23:31:22 +0300 Subject: [PATCH 101/237] Enable Style/IndentationWidth cop The offenses were fixed manually --- .rubocop_todo.yml | 11 --- app/helpers/format_helper.rb | 9 +-- app/serializers/conference_serializer.rb | 2 +- ...23203_add_events_per_week_to_conference.rb | 76 +++++++++---------- lib/tasks/demo_data_for_development.rake | 50 ++++++------ spec/models/ability_spec.rb | 6 +- 6 files changed, 71 insertions(+), 83 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 1c188b60..9523593a 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -469,17 +469,6 @@ Style/IndentationConsistency: - 'app/models/event.rb' - 'spec/controllers/subscriptions_controller_spec.rb' -# Offense count: 6 -# Cop supports --auto-correct. -# Configuration parameters: Width, IgnoredPatterns. -Style/IndentationWidth: - Exclude: - - 'app/helpers/format_helper.rb' - - 'app/serializers/conference_serializer.rb' - - 'db/migrate/20140701123203_add_events_per_week_to_conference.rb' - - 'lib/tasks/demo_data_for_development.rake' - - 'spec/models/ability_spec.rb' - # Offense count: 4 # Cop supports --auto-correct. Style/LeadingCommentSpace: diff --git a/app/helpers/format_helper.rb b/app/helpers/format_helper.rb index 472edc38..334c70bf 100644 --- a/app/helpers/format_helper.rb +++ b/app/helpers/format_helper.rb @@ -102,13 +102,12 @@ module FormatHelper end end - # rubocop:disable Lint/EndAlignment def word_pluralize(count, singular, plural = nil) word = if (count == 1 || count =~ /^1(\.0+)?$/) - singular - else - plural || singular.pluralize - end + singular + else + plural || singular.pluralize + end "#{word}" end diff --git a/app/serializers/conference_serializer.rb b/app/serializers/conference_serializer.rb index a7e0c1da..7bb96131 100644 --- a/app/serializers/conference_serializer.rb +++ b/app/serializers/conference_serializer.rb @@ -60,7 +60,7 @@ class ConferenceSerializer < ActiveModel::Serializer def date_range if defined? date_string(object.start_date, object.end_date) - date_string(object.start_date, object.end_date).try(:split, ',').try(:first) + date_string(object.start_date, object.end_date).try(:split, ',').try(:first) end end end diff --git a/db/migrate/20140701123203_add_events_per_week_to_conference.rb b/db/migrate/20140701123203_add_events_per_week_to_conference.rb index 5c2eb9d4..36bbf40d 100644 --- a/db/migrate/20140701123203_add_events_per_week_to_conference.rb +++ b/db/migrate/20140701123203_add_events_per_week_to_conference.rb @@ -22,50 +22,50 @@ class AddEventsPerWeekToConference < ActiveRecord::Migration if event conference = TempConference.find_by_id(event.conference_id) if conference - week = event_version.created_at.end_of_week + week = event_version.created_at.end_of_week - no_events = { - new: 0, - withdrawn: 0, - unconfirmed: 0, - confirmed: 0, - canceled: 0, - rejected: 0, - } - - if !conference.events_per_week - conference.events_per_week = { - week => no_events + no_events = { + new: 0, + withdrawn: 0, + unconfirmed: 0, + confirmed: 0, + canceled: 0, + rejected: 0, } - elsif !conference.events_per_week[week] - conference.events_per_week[week] = no_events - end - if event_version.object_changes && - event_version.event == 'create' - - # Increment the new state - conference.events_per_week[week][:new] += 1 - elsif event_version.object_changes && - event_version.object_changes[:state] - - prev_state = event_version.object_changes[:state][0].to_sym - next_state = event_version.object_changes[:state][1].to_sym - - # Backward compatibility: deprecated state :review now :new - if prev_state == :review - prev_state = :new - elsif next_state == :review - next_state = :new + if !conference.events_per_week + conference.events_per_week = { + week => no_events + } + elsif !conference.events_per_week[week] + conference.events_per_week[week] = no_events end - # Increment the next state - conference.events_per_week[week][next_state] += 1 + if event_version.object_changes && + event_version.event == 'create' - # Decrement the previous state - conference.events_per_week[week][prev_state] -= 1 - end - conference.save + # Increment the new state + conference.events_per_week[week][:new] += 1 + elsif event_version.object_changes && + event_version.object_changes[:state] + + prev_state = event_version.object_changes[:state][0].to_sym + next_state = event_version.object_changes[:state][1].to_sym + + # Backward compatibility: deprecated state :review now :new + if prev_state == :review + prev_state = :new + elsif next_state == :review + next_state = :new + end + + # Increment the next state + conference.events_per_week[week][next_state] += 1 + + # Decrement the previous state + conference.events_per_week[week][prev_state] -= 1 + end + conference.save end end end diff --git a/lib/tasks/demo_data_for_development.rake b/lib/tasks/demo_data_for_development.rake index a86371b3..5be30c8e 100644 --- a/lib/tasks/demo_data_for_development.rake +++ b/lib/tasks/demo_data_for_development.rake @@ -4,37 +4,37 @@ namespace :data do include FactoryGirl::Syntax::Methods def generate_program conference - program = conference.program - user1 = create(:user) - user2 = create(:user) + program = conference.program + user1 = create(:user) + user2 = create(:user) - conference_rooms = conference.venue.rooms + conference_rooms = conference.venue.rooms - selected_schedule = create(:schedule, program: program) - demo_schedule = create(:schedule, program: program) - program.update_attributes!(selected_schedule: selected_schedule) + selected_schedule = create(:schedule, program: program) + demo_schedule = create(:schedule, program: program) + program.update_attributes!(selected_schedule: selected_schedule) - create(:event, program: program, title: 'Demo Event', abstract: 'This is a demo event instance whose state not defined.') - create(:event, program: program, title: 'Demo Rejected Event', state: 'rejected', abstract: 'This is demo event instance in a rejected state.') - create(:event, program: program, title: 'Demo Unconfirmed Event', state: 'unconfirmed', abstract: 'This is a demo event instance in unconfirmed state.') - create(:event, program: program, title: 'Demo Confirmed Unscheduled Event', state: 'confirmed', abstract: 'This is a demo event instance in a confirmed state.') + create(:event, program: program, title: 'Demo Event', abstract: 'This is a demo event instance whose state not defined.') + create(:event, program: program, title: 'Demo Rejected Event', state: 'rejected', abstract: 'This is demo event instance in a rejected state.') + create(:event, program: program, title: 'Demo Unconfirmed Event', state: 'unconfirmed', abstract: 'This is a demo event instance in unconfirmed state.') + create(:event, program: program, title: 'Demo Confirmed Unscheduled Event', state: 'confirmed', abstract: 'This is a demo event instance in a confirmed state.') - first_scheduled_event = create(:event, program: program, title: 'first_scheduled_event', state: 'confirmed', abstract: 'This is a demo scheduled event instance.') - second_scheduled_event = create(:event, program: program, title: 'second_scheduled_event', state: 'confirmed', abstract: 'This is a demo scheduled event instance.') - multiple_speaker_event = create(:event, program: program, title: 'multiple_speaker_event', state: 'confirmed', abstract: 'This is a demo scheduled event instance having multiple speakers.') + first_scheduled_event = create(:event, program: program, title: 'first_scheduled_event', state: 'confirmed', abstract: 'This is a demo scheduled event instance.') + second_scheduled_event = create(:event, program: program, title: 'second_scheduled_event', state: 'confirmed', abstract: 'This is a demo scheduled event instance.') + multiple_speaker_event = create(:event, program: program, title: 'multiple_speaker_event', state: 'confirmed', abstract: 'This is a demo scheduled event instance having multiple speakers.') - create(:event_user, event: multiple_speaker_event, user: user1, event_role: 'speaker') - create(:event_user, event: multiple_speaker_event, user: user2, event_role: 'speaker') + create(:event_user, event: multiple_speaker_event, user: user1, event_role: 'speaker') + create(:event_user, event: multiple_speaker_event, user: user2, event_role: 'speaker') - create(:event_schedule, event: first_scheduled_event, schedule: selected_schedule, start_time: conference.start_date + conference.start_hour.hours, room: conference_rooms.first) - create(:event_schedule, event: second_scheduled_event, schedule: selected_schedule, start_time: conference.start_date + conference.start_hour.hours + 15.minutes, room: conference_rooms.second) - create(:event_schedule, event: multiple_speaker_event, schedule: selected_schedule, start_time: conference.start_date + conference.start_hour.hours + 30.minutes, room: conference_rooms.third) - create(:event_schedule, event: first_scheduled_event, schedule: demo_schedule, start_time: conference.start_date + conference.start_hour.hours + 15.minutes, room: conference_rooms.third) - create(:event_schedule, event: second_scheduled_event, schedule: demo_schedule, start_time: conference.start_date + conference.start_hour.hours + 30.minutes, room: conference_rooms.third) - create(:event_schedule, event: multiple_speaker_event, schedule: demo_schedule, start_time: conference.start_date + conference.start_hour.hours, room: conference_rooms.first) + create(:event_schedule, event: first_scheduled_event, schedule: selected_schedule, start_time: conference.start_date + conference.start_hour.hours, room: conference_rooms.first) + create(:event_schedule, event: second_scheduled_event, schedule: selected_schedule, start_time: conference.start_date + conference.start_hour.hours + 15.minutes, room: conference_rooms.second) + create(:event_schedule, event: multiple_speaker_event, schedule: selected_schedule, start_time: conference.start_date + conference.start_hour.hours + 30.minutes, room: conference_rooms.third) + create(:event_schedule, event: first_scheduled_event, schedule: demo_schedule, start_time: conference.start_date + conference.start_hour.hours + 15.minutes, room: conference_rooms.third) + create(:event_schedule, event: second_scheduled_event, schedule: demo_schedule, start_time: conference.start_date + conference.start_hour.hours + 30.minutes, room: conference_rooms.third) + create(:event_schedule, event: multiple_speaker_event, schedule: demo_schedule, start_time: conference.start_date + conference.start_hour.hours, room: conference_rooms.first) - create(:registration, user: user1, conference: conference) - create(:registration, user: user2, conference: conference) + create(:registration, user: user1, conference: conference) + create(:registration, user: user2, conference: conference) end # This is a full conference demo instance that will happen in the future. @@ -73,5 +73,5 @@ namespace :data do # Registration for this conference has reached its limit. conference = create(:full_conference, title: 'Zypper Docker Conference', short_title: 'zypper', registration_limit: 2, start_date: 3.days.from_now, end_date: 7.days.from_now, start_hour: 7, end_hour: 19, description: 'This is a full conference demo instance. Its registrations has reached the limit.') generate_program conference - end + end end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 55f430f2..2144cec6 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -40,9 +40,9 @@ describe 'User' do it{ should_not be_able_to(:show, conference_not_public)} it do - conference_public.program.schedule_public = true - conference_public.program.save - should be_able_to(:schedule, conference_public) + conference_public.program.schedule_public = true + conference_public.program.save + should be_able_to(:schedule, conference_public) end it{ should_not be_able_to(:schedule, conference_not_public)} From b86472ac3c732c65715bd6462fef39a44a0d36fe Mon Sep 17 00:00:00 2001 From: nasia Date: Fri, 7 Jul 2017 16:13:35 +0300 Subject: [PATCH 102/237] Add Call for Booths --- .haml-lint_todo.yml | 1 + app/models/cfp.rb | 2 +- app/views/admin/cfps/_booths_cfp.html.haml | 12 ++++++++++ spec/factories/cfps.rb | 2 +- spec/features/cfp_ability_spec.rb | 22 ++++++++++++++++--- .../organization_admin_ability_spec.rb | 22 ++++++++++++++++--- spec/features/organizer_ability_spec.rb | 22 ++++++++++++++++--- spec/models/program_spec.rb | 22 +++++++++++++++++-- 8 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 app/views/admin/cfps/_booths_cfp.html.haml diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index df4d0708..4644a6bb 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -180,6 +180,7 @@ linters: InstanceVariables: exclude: - "app/views/admin/campaigns/_form.html.haml" + - "app/views/admin/cfps/_booths_cfp.html.haml" - "app/views/admin/cfps/_form.html.haml" - "app/views/admin/conferences/_todo_list.html.haml" - "app/views/admin/difficulty_levels/_form.html.haml" diff --git a/app/models/cfp.rb b/app/models/cfp.rb index f06bec7b..97f276c9 100644 --- a/app/models/cfp.rb +++ b/app/models/cfp.rb @@ -1,7 +1,7 @@ # cannot delete program if there are events submitted class Cfp < ActiveRecord::Base - TYPES = %w(events).freeze + TYPES = %w(events booths).freeze scope :for_events, (-> { find_by(cfp_type: 'events') }) diff --git a/app/views/admin/cfps/_booths_cfp.html.haml b/app/views/admin/cfps/_booths_cfp.html.haml new file mode 100644 index 00000000..89012336 --- /dev/null +++ b/app/views/admin/cfps/_booths_cfp.html.haml @@ -0,0 +1,12 @@ +%dt + Start Date +%dd + = @cfp.start_date.strftime('%A, %B %e. %Y') +%dt + End Date +%dd + = @cfp.end_date.strftime('%A, %B %e. %Y') +%dt + Days Left +%dd + = pluralize(@cfp.remaining_days, 'day') diff --git a/spec/factories/cfps.rb b/spec/factories/cfps.rb index 6a8e96ed..6b061d53 100644 --- a/spec/factories/cfps.rb +++ b/spec/factories/cfps.rb @@ -3,7 +3,7 @@ FactoryGirl.define do factory :cfp do start_date { 1.day.ago } - end_date { 6.days.from_now } + end_date { 2.days.from_now } cfp_type 'events' program diff --git a/spec/features/cfp_ability_spec.rb b/spec/features/cfp_ability_spec.rb index 7af4e119..b12a2ef5 100644 --- a/spec/features/cfp_ability_spec.rb +++ b/spec/features/cfp_ability_spec.rb @@ -60,16 +60,32 @@ feature 'Has correct abilities' do visit edit_admin_conference_program_path(conference.short_title) expect(current_path).to eq(edit_admin_conference_program_path(conference.short_title)) + # Only event type exists + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) + + # Both event and booth exists + cfb = create(:cfp, cfp_type: 'booths', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq root_path + visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + conference.program.cfp.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) - create(:cfp, program: conference.program) - visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) - expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + # Only booth exists + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) + + visit edit_admin_conference_program_cfp_path(conference.short_title, cfb) + expect(current_path). to eq(edit_admin_conference_program_cfp_path(conference.short_title, cfb)) + + cfb.destroy + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) create(:event, program: conference.program) visit edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first) diff --git a/spec/features/organization_admin_ability_spec.rb b/spec/features/organization_admin_ability_spec.rb index aefb89f4..274d345f 100644 --- a/spec/features/organization_admin_ability_spec.rb +++ b/spec/features/organization_admin_ability_spec.rb @@ -102,16 +102,32 @@ feature 'Has correct abilities' do visit edit_admin_conference_program_path(conference.short_title) expect(current_path).to eq(edit_admin_conference_program_path(conference.short_title)) + # Only event exists + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) + + # Both event and booth exists + cfb = create(:cfp, cfp_type: 'booths', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq root_path + visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + conference.program.cfp.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) - create(:cfp, program: conference.program) - visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) - expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + # Only booth exists + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) + + visit edit_admin_conference_program_cfp_path(conference.short_title, cfb) + expect(current_path). to eq(edit_admin_conference_program_cfp_path(conference.short_title, cfb)) + + cfb.destroy + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) visit admin_conference_program_events_path(conference.short_title) expect(current_path).to eq(admin_conference_program_events_path(conference.short_title)) diff --git a/spec/features/organizer_ability_spec.rb b/spec/features/organizer_ability_spec.rb index 34d87b0a..10c5d726 100644 --- a/spec/features/organizer_ability_spec.rb +++ b/spec/features/organizer_ability_spec.rb @@ -108,16 +108,32 @@ feature 'Has correct abilities' do visit edit_admin_conference_program_path(conference.short_title) expect(current_path).to eq(edit_admin_conference_program_path(conference.short_title)) + # Only event type exists + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) + + # Both event and booth exists + cfb = create(:cfp, cfp_type: 'booths', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq root_path + visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) + expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + conference.program.cfp.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) - create(:cfp, program: conference.program) - visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) - expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + # Only booth exists + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) + + visit edit_admin_conference_program_cfp_path(conference.short_title, cfb) + expect(current_path). to eq(edit_admin_conference_program_cfp_path(conference.short_title, cfb)) + + cfb.destroy + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) visit admin_conference_program_events_path(conference.short_title) expect(current_path).to eq(admin_conference_program_events_path(conference.short_title)) diff --git a/spec/models/program_spec.rb b/spec/models/program_spec.rb index 208ca386..d81e32bc 100644 --- a/spec/models/program_spec.rb +++ b/spec/models/program_spec.rb @@ -253,10 +253,28 @@ describe Program do end describe '#remaining_cfp_types' do - it 'returns an array with the types for which a cfp doesn\'t exist' do + it 'returns an array with the types for which a cfp doesn\'t exist, when only the Event type does' do expect(program.remaining_cfp_types).to eq(Cfp::TYPES) - create(:cfp, cfp_type: 'events', program: program, end_date: Date.current + 1) + create(:cfp, cfp_type: 'events', program: program) + expect(program.remaining_cfp_types).to eq(['booths']) + end + + it 'returns an array with the types for which a cfp doesn\'t exist, when only the Booth type does' do + expect(program.remaining_cfp_types).to eq(Cfp::TYPES) + create(:cfp, cfp_type: 'booths', program: program) + expect(program.remaining_cfp_types).to eq(['events']) + end + + it 'returns an empty array when all the cfp types exist' do + expect(program.remaining_cfp_types).to eq(Cfp::TYPES) + create(:cfp, cfp_type: 'events', program: program) + create(:cfp, cfp_type: 'booths', program: program) expect(program.remaining_cfp_types).to eq([]) end + + it 'returns all the possible cfp types when there is no existed cfp type' do + expect(program.remaining_cfp_types).to eq(Cfp::TYPES) + expect(program.remaining_cfp_types). to eq(%w[events booths]) + end end end From b2bd6080c2e3949389d47731d965b510ef35a84d Mon Sep 17 00:00:00 2001 From: Hernan Schmidt Date: Fri, 14 Jul 2017 14:02:55 +0200 Subject: [PATCH 103/237] Update Rubocop to 0.49.1 --- Gemfile | 2 +- Gemfile.lock | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 1af89f34..46c8731e 100644 --- a/Gemfile +++ b/Gemfile @@ -205,7 +205,7 @@ group :development do gem 'spring-commands-rspec' gem 'haml_lint', '~> 0.24.0' # for static code analisys - gem 'rubocop', '~> 0.48.1', require: false + gem 'rubocop', '~> 0.49.0', require: false # as database gem 'sqlite3' # to open mails diff --git a/Gemfile.lock b/Gemfile.lock index 5ef3f60c..effbde5b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -323,6 +323,7 @@ GEM activerecord (>= 3.0, < 6.0) activesupport (>= 3.0, < 6.0) request_store (~> 1.1) + parallel (1.11.2) parser (2.4.0.0) ast (~> 2.2) pdf-core (0.2.5) @@ -405,7 +406,8 @@ GEM activesupport (= 4.2.7.1) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.2.1) + rainbow (2.2.2) + rake rake (10.5.0) rb-fsevent (0.9.4) rb-inotify (0.9.4) @@ -453,7 +455,8 @@ GEM rspec-mocks (~> 3.0.0) rspec-support (~> 3.0.0) rspec-support (3.0.2) - rubocop (0.48.1) + rubocop (0.49.1) + parallel (~> 1.10) parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) @@ -521,7 +524,7 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.7.2) - unicode-display_width (1.2.1) + unicode-display_width (1.3.0) unicode_utils (1.4.0) unobtrusive_flash (3.1.0) railties @@ -634,7 +637,7 @@ DEPENDENCIES rqrcode rspec-activemodel-mocks rspec-rails - rubocop (~> 0.48.1) + rubocop (~> 0.49.0) ruby-oembed sass-rails (>= 4.0.2) selectize-rails From 523203ac74910d83f7ecad944317a73b059cc4d7 Mon Sep 17 00:00:00 2001 From: Hernan Schmidt Date: Fri, 14 Jul 2017 14:04:46 +0200 Subject: [PATCH 104/237] Update rubocop_todo.yml Generated automatically by `rubocop --auto-gen-config` --- .rubocop_todo.yml | 762 +++++++++++++++++----------------------------- 1 file changed, 287 insertions(+), 475 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 9523593a..7a9ab03c 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,12 +1,12 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2017-05-06 17:45:40 +0530 using RuboCop version 0.48.1. +# on 2017-07-14 12:03:16 +0000 using RuboCop version 0.49.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 13 +# Offense count: 15 # Cop supports --auto-correct. # Configuration parameters: Include, TreatCommentsAsGroupSeparators. # Include: **/Gemfile, **/gems.rb @@ -14,29 +14,271 @@ Bundler/OrderedGems: Exclude: - 'Gemfile' -# Offense count: 29 -Lint/AmbiguousBlockAssociation: +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: with_first_parameter, with_fixed_indentation +Layout/AlignParameters: Exclude: - - 'app/models/comment.rb' - - 'app/models/event.rb' - - 'app/models/event_schedule.rb' - - 'app/models/ticket_purchase.rb' - - 'app/models/user.rb' - - 'spec/controllers/admin/conferences_controller_spec.rb' - - 'spec/controllers/admin/event_schedules_controller_spec.rb' - - 'spec/controllers/admin/registration_periods_controller_spec.rb' - - 'spec/controllers/proposals_controller_spec.rb' - - 'spec/controllers/schedules_controller_spec.rb' - - 'spec/models/user_spec.rb' - - 'spec/controllers/admin/users_controller_spec.rb' + - 'Vagrantfile' + +# Offense count: 9 +# Cop supports --auto-correct. +Layout/ClosingParenthesisIndentation: + Exclude: + - 'app/controllers/conference_registrations_controller.rb' + - 'spec/support/omniauth_macros.rb' + +# Offense count: 14 +# Cop supports --auto-correct. +Layout/CommentIndentation: + Exclude: + - 'app/controllers/admin/comments_controller.rb' + - 'app/controllers/admin/difficulty_levels_controller.rb' + - 'app/models/conference.rb' + - 'app/models/program.rb' + - 'app/models/track.rb' + - 'spec/features/volunteers_spec.rb' # Offense count: 1 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyleAlignWith, SupportedStylesAlignWith. -# SupportedStylesAlignWith: either, start_of_block, start_of_line -Lint/BlockAlignment: +Layout/EmptyLineAfterMagicComment: Exclude: - - 'lib/tasks/demo_data_for_development.rake' + - 'spec/models/conference_spec.rb' + +# Offense count: 104 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: empty_lines, no_empty_lines +Layout/EmptyLinesAroundBlockBody: + Enabled: false + +# Offense count: 1 +# Cop supports --auto-correct. +Layout/EmptyLinesAroundExceptionHandlingKeywords: + Exclude: + - 'app/models/payment.rb' + +# Offense count: 9 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. +Layout/ExtraSpacing: + Exclude: + - 'Guardfile' + - 'app/controllers/application_controller.rb' + - 'config.ru' + - 'db/migrate/20140623101032_create_ahoy_events.rb' + - 'db/migrate/20140701123203_add_events_per_week_to_conference.rb' + - 'db/migrate/20140719160903_create_delayed_jobs.rb' + - 'spec/models/conference_spec.rb' + +# Offense count: 42 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: consistent, special_for_inner_method_call, special_for_inner_method_call_in_parentheses +Layout/FirstParameterIndentation: + Enabled: false + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_brackets +Layout/IndentArray: + Exclude: + - 'app/models/conference.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: IndentationWidth. +Layout/IndentAssignment: + Exclude: + - 'app/helpers/format_helper.rb' + - 'app/models/conference.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_braces +Layout/IndentHash: + Exclude: + - 'app/models/user.rb' + - 'db/migrate/20140701123203_add_events_per_week_to_conference.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: normal, rails +Layout/IndentationConsistency: + Exclude: + - 'app/controllers/users_controller.rb' + - 'app/models/event.rb' + - 'spec/controllers/subscriptions_controller_spec.rb' + +# Offense count: 4 +# Cop supports --auto-correct. +Layout/LeadingCommentSpace: + Exclude: + - 'Guardfile' + - 'app/models/comment.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: symmetrical, new_line, same_line +Layout/MultilineArrayBraceLayout: + Exclude: + - 'app/controllers/conference_registrations_controller.rb' + +# Offense count: 5 +# Cop supports --auto-correct. +Layout/MultilineBlockLayout: + Exclude: + - 'app/serializers/conference_serializer.rb' + +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: symmetrical, new_line, same_line +Layout/MultilineHashBraceLayout: + Exclude: + - 'app/serializers/conference_serializer.rb' + - 'spec/models/event_spec.rb' + +# Offense count: 40 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: symmetrical, new_line, same_line +Layout/MultilineMethodCallBraceLayout: + Enabled: false + +# Offense count: 55 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: aligned, indented, indented_relative_to_receiver +Layout/MultilineMethodCallIndentation: + Enabled: false + +# Offense count: 23 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: aligned, indented +Layout/MultilineOperationIndentation: + Exclude: + - 'app/controllers/admin/events_controller.rb' + - 'app/controllers/application_controller.rb' + - 'app/models/conference.rb' + - 'app/models/event.rb' + - 'db/migrate/20140701123203_add_events_per_week_to_conference.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Layout/SpaceAfterComma: + Exclude: + - 'lib/tasks/data_demo.rake' + +# Offense count: 3 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: space, no_space +Layout/SpaceAroundEqualsInParameterDefault: + Exclude: + - 'app/helpers/format_helper.rb' + - 'app/models/event.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment. +Layout/SpaceAroundOperators: + Exclude: + - 'lib/tasks/data.rake' + +# Offense count: 416 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: space, no_space +Layout/SpaceBeforeBlockBraces: + Enabled: false + +# Offense count: 1 +# Cop supports --auto-correct. +Layout/SpaceBeforeComma: + Exclude: + - 'lib/tasks/data_demo.rake' + +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment. +Layout/SpaceBeforeFirstArg: + Exclude: + - 'spec/controllers/admin/roles_controller_spec.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Layout/SpaceBeforeSemicolon: + Exclude: + - 'Guardfile' + +# Offense count: 51 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. +# SupportedStyles: space, no_space +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceInsideBlockBraces: + Exclude: + - 'app/controllers/admin/comments_controller.rb' + - 'app/controllers/admin/events_controller.rb' + - 'app/controllers/admin/questions_controller.rb' + - 'app/helpers/application_helper.rb' + - 'app/models/program.rb' + - 'app/models/ticket.rb' + - 'app/models/user.rb' + - 'lib/tasks/events_registrations.rake' + - 'spec/controllers/admin/event_schedules_controller_spec.rb' + - 'spec/controllers/admin/schedules_controller_spec.rb' + - 'spec/features/splashpage_spec.rb' + - 'spec/models/ability_spec.rb' + - 'spec/models/user_spec.rb' + +# Offense count: 19 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces. +# SupportedStyles: space, no_space, compact +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceInsideHashLiteralBraces: + Exclude: + - 'app/controllers/admin/conferences_controller.rb' + - 'app/controllers/api/v1/speakers_controller.rb' + - 'app/models/conference.rb' + - 'app/models/event_type.rb' + - 'app/models/user.rb' + - 'spec/models/event_spec.rb' + - 'spec/models/payment_spec.rb' + +# Offense count: 2 +# Cop supports --auto-correct. +Layout/SpaceInsidePercentLiteralDelimiters: + Exclude: + - 'Gemfile' + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: final_newline, final_blank_line +Layout/TrailingBlankLines: + Exclude: + - 'lib/tasks/event_attatchments.rake' + - 'lib/tasks/roles.rake' + +# Offense count: 13 +Lint/AmbiguousBlockAssociation: + Exclude: + - 'spec/controllers/admin/conferences_controller_spec.rb' + - 'spec/controllers/admin/event_schedules_controller_spec.rb' + - 'spec/controllers/admin/registration_periods_controller_spec.rb' + - 'spec/controllers/admin/users_controller_spec.rb' + - 'spec/controllers/proposals_controller_spec.rb' + - 'spec/controllers/schedules_controller_spec.rb' + - 'spec/models/user_spec.rb' # Offense count: 2 Lint/DuplicatedKey: @@ -50,6 +292,12 @@ Lint/IneffectiveAccessModifier: - 'app/models/commercial.rb' - 'app/models/conference.rb' +# Offense count: 2 +Lint/ScriptPermission: + Exclude: + - 'Guardfile' + - 'Rakefile' + # Offense count: 1 # Cop supports --auto-correct. # Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. @@ -57,194 +305,40 @@ Lint/UnusedBlockArgument: Exclude: - 'lib/tasks/user.rake' -# Offense count: 108 +# Offense count: 114 Metrics/AbcSize: - Max: 75 - Exclude: - - 'app/controllers/admin/conferences_controller.rb' + Max: 86 -# Offense count: 202 +# Offense count: 233 # Configuration parameters: CountComments, ExcludedMethods. Metrics/BlockLength: - Max: 487 + Max: 471 -# Offense count: 21 +# Offense count: 23 Metrics/CyclomaticComplexity: Max: 12 -# Offense count: 1991 +# Offense count: 2353 # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. # URISchemes: http, https Metrics/LineLength: Max: 619 -# Offense count: 115 +# Offense count: 120 # Configuration parameters: CountComments. Metrics/MethodLength: Max: 56 -# Offense count: 2 +# Offense count: 3 # Configuration parameters: CountComments. Metrics/ModuleLength: - Max: 472 - Exclude: - - 'app/helpers/application_helper.rb' + Max: 159 - -# Offense count: 14 +# Offense count: 15 Metrics/PerceivedComplexity: - Max: 15 - Exclude: - - 'app/controllers/admin/roles_controller.rb' + Max: 16 -# Offense count: 11 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, Include. -# SupportedStyles: action, filter -# Include: app/controllers/**/*.rb -Rails/ActionFilter: - Exclude: - - 'app/controllers/admin/base_controller.rb' - - 'app/controllers/admin/registrations_controller.rb' - - 'app/controllers/application_controller.rb' - - 'app/controllers/conference_registrations_controller.rb' - - 'app/controllers/subscriptions_controller.rb' - - 'app/controllers/ticket_purchases_controller.rb' - - 'app/controllers/tickets_controller.rb' - - 'app/controllers/users/omniauth_callbacks_controller.rb' - -# Offense count: 7 -# Cop supports --auto-correct. -# Configuration parameters: NilOrEmpty, NotPresent, UnlessPresent. -Rails/Blank: - Exclude: - - 'app/models/program.rb' - - 'app/models/user.rb' - - 'spec/factories/event_schedule.rb' - -# Offense count: 139 -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: strict, flexible -Rails/Date: - Enabled: false - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: Whitelist. -# Whitelist: find_by_sql -Rails/DynamicFindBy: - Exclude: - - 'app/controllers/admin/events_controller.rb' - - 'db/migrate/20140701123203_add_events_per_week_to_conference.rb' - -# Offense count: 4 -Rails/FilePath: - Exclude: - - 'spec/features/lodgings_spec.rb' - - 'spec/features/sponsor_spec.rb' - - 'spec/spec_helper.rb' - -# Offense count: 6 -# Cop supports --auto-correct. -# Configuration parameters: Include. -# Include: app/models/**/*.rb -Rails/FindBy: - Exclude: - - 'app/models/conference.rb' - - 'app/models/event.rb' - - 'app/models/openid.rb' - - 'app/models/ticket_purchase.rb' - - 'app/models/user.rb' - -# Offense count: 7 -# Configuration parameters: Include. -# Include: app/models/**/*.rb -Rails/HasAndBelongsToMany: - Exclude: - - 'app/models/conference.rb' - - 'app/models/qanswer.rb' - - 'app/models/question.rb' - - 'app/models/registration.rb' - - 'app/models/vchoice.rb' - -# Offense count: 170 -# Cop supports --auto-correct. -# Configuration parameters: Include. -# Include: spec/**/*, test/**/* -Rails/HttpPositionalArguments: - Enabled: false - -# Offense count: 2 -Rails/OutputSafety: - Exclude: - - 'app/helpers/format_helper.rb' - - 'app/models/commercial.rb' - - 'app/helpers/application_helper.rb' - -# Offense count: 10 -# Cop supports --auto-correct. -Rails/PluralizationGrammar: - Exclude: - - 'spec/models/conference_spec.rb' - -# Offense count: 22 -# Cop supports --auto-correct. -# Configuration parameters: NotNilAndNotEmpty, NotBlank, UnlessBlank. -Rails/Present: - Exclude: - - 'app/helpers/users_helper.rb' - - 'app/models/campaign.rb' - - 'app/models/cfp.rb' - - 'app/models/email_settings.rb' - - 'app/models/event.rb' - - 'app/models/program.rb' - - 'app/models/venue.rb' - -# Offense count: 52 -# Configuration parameters: Include. -# Include: db/migrate/*.rb -Rails/ReversibleMigration: - Exclude: - - 'db/migrate/20140530082708_remove_color_defaults.rb' - - 'db/migrate/20140605125153_update_event_states.rb' - - 'db/migrate/20140610173021_change_person_id_to_user_id_in_registrations.rb' - - 'db/migrate/20140611123926_change_person_id_to_user_id_in_votes.rb' - - 'db/migrate/20140623150541_drop_person_and_event_person_tables.rb' - - 'db/migrate/20140731165107_move_conference_contact_details_to_contact.rb' - - 'db/migrate/20140801164901_move_conference_media_to_commercial.rb' - - 'db/migrate/20140801170430_move_event_media_to_commercial.rb' - - 'db/migrate/20140820093735_migrating_supporter_registrations_to_ticket_users.rb' - - 'db/migrate/20140821103643_split_ticket_price_in_price_and_currency.rb' - - 'db/migrate/20140825093132_move_splashpage_attributes_from_conference_to_splashpage.rb' - - 'db/migrate/20140930092923_move_sponsor_email_to_contact.rb' - - 'db/migrate/20141117222919_drop_splash_descriptions_and_photo.rb' - - 'db/migrate/20141130182139_drop_table_event_attachments.rb' - -# Offense count: 5 -# Configuration parameters: Blacklist. -# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters -Rails/SkipsModelValidations: - Exclude: - - 'app/controllers/payments_controller.rb' - - 'app/models/revision_observer.rb' - - 'db/migrate/20140730104658_migrate_roles_for_cancancan.rb' - - 'lib/tasks/user.rake' - -# Offense count: 46 -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: strict, flexible -Rails/TimeZone: - Exclude: - - 'app/models/comment.rb' - - 'app/models/conference.rb' - - 'lib/tasks/dump_db.rake' - - 'spec/controllers/admin/comments_controller_spec.rb' - - 'spec/controllers/admin/programs_controller_spec.rb' - - 'spec/factories/users.rb' - - 'spec/models/campaign_spec.rb' - - 'spec/models/conference_spec.rb' - -# Offense count: 18 +# Offense count: 20 Style/AccessorMethodName: Exclude: - 'app/controllers/admin/events_controller.rb' @@ -256,33 +350,17 @@ Style/AccessorMethodName: # Offense count: 1 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: with_first_parameter, with_fixed_indentation -Style/AlignParameters: - Exclude: - - 'Vagrantfile' - -# Offense count: 2 -# Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: is_a?, kind_of? Style/ClassCheck: Exclude: - 'app/models/email_settings.rb' - - 'app/models/revision_observer.rb' # Offense count: 1 Style/ClassVars: Exclude: - 'spec/support/kneet_connections.rb' -# Offense count: 9 -# Cop supports --auto-correct. -Style/ClosingParenthesisIndentation: - Exclude: - - 'app/controllers/conference_registrations_controller.rb' - - 'spec/support/omniauth_macros.rb' - # Offense count: 2 # Cop supports --auto-correct. Style/ColonMethodCall: @@ -290,42 +368,20 @@ Style/ColonMethodCall: - 'app/models/commercial.rb' - 'app/models/contact.rb' -# Offense count: 14 -# Cop supports --auto-correct. -Style/CommentIndentation: - Exclude: - - 'app/controllers/admin/comments_controller.rb' - - 'app/controllers/admin/difficulty_levels_controller.rb' - - 'app/models/conference.rb' - - 'app/models/program.rb' - - 'app/models/track.rb' - - 'spec/features/volunteers_spec.rb' - # Offense count: 3 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly, IncludeTernaryExpressions. # SupportedStyles: assign_to_condition, assign_inside_condition Style/ConditionalAssignment: Exclude: - - 'app/controllers/admin/volunteers_controller.rb' - - 'app/controllers/conference_registrations_controller.rb' - 'app/helpers/format_helper.rb' - - 'app/models/conference.rb' - - 'app/models/ticket_purchase.rb' - - 'app/models/user.rb' - 'db/migrate/20140610165551_migrate_data_person_to_user.rb' - 'db/migrate/20140820124117_undo_wrong_migration20140801080705_add_users_to_events.rb' -# Offense count: 436 +# Offense count: 464 Style/Documentation: Enabled: false -# Offense count: 1 -# Cop supports --auto-correct. -Style/ElseAlignment: - Exclude: - - 'app/helpers/format_helper.rb' - # Offense count: 2 # Cop supports --auto-correct. Style/EmptyCaseCondition: @@ -333,25 +389,6 @@ Style/EmptyCaseCondition: - 'app/helpers/format_helper.rb' - 'app/helpers/versions_helper.rb' -# Offense count: 1 -# Cop supports --auto-correct. -Style/EmptyLineAfterMagicComment: - Exclude: - - 'spec/models/conference_spec.rb' - -# Offense count: 109 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: empty_lines, no_empty_lines -Style/EmptyLinesAroundBlockBody: - Enabled: false - -# Offense count: 1 -# Cop supports --auto-correct. -Style/EmptyLinesAroundExceptionHandlingKeywords: - Exclude: - - 'app/models/payment.rb' - # Offense count: 1 # Cop supports --auto-correct. Style/EmptyLiteral: @@ -373,19 +410,6 @@ Style/EmptyMethod: - 'db/migrate/20130206192339_rename_attending_social_events_with_partner.rb' - 'db/migrate/20130216122155_set_registration_defaults_to_false.rb' -# Offense count: 9 -# Cop supports --auto-correct. -# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. -Style/ExtraSpacing: - Exclude: - - 'Guardfile' - - 'app/controllers/application_controller.rb' - - 'config.ru' - - 'db/migrate/20140623101032_create_ahoy_events.rb' - - 'db/migrate/20140701123203_add_events_per_week_to_conference.rb' - - 'db/migrate/20140719160903_create_delayed_jobs.rb' - - 'spec/models/conference_spec.rb' - # Offense count: 2 # Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms. # AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS @@ -394,14 +418,7 @@ Style/FileName: - 'Gemfile' - 'Vagrantfile' -# Offense count: 42 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: consistent, special_for_inner_method_call, special_for_inner_method_call_in_parentheses -Style/FirstParameterIndentation: - Enabled: false - -# Offense count: 23 +# Offense count: 24 # Configuration parameters: MinBodyLength. Style/GuardClause: Enabled: false @@ -434,48 +451,6 @@ Style/IfUnlessModifier: - 'spec/controllers/admin/conferences_controller_spec.rb' - 'spec/support/flash.rb' -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: special_inside_parentheses, consistent, align_brackets -Style/IndentArray: - Exclude: - - 'app/models/conference.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: IndentationWidth. -Style/IndentAssignment: - Exclude: - - 'app/helpers/format_helper.rb' - - 'app/models/conference.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: special_inside_parentheses, consistent, align_braces -Style/IndentHash: - Exclude: - - 'app/models/user.rb' - - 'db/migrate/20140701123203_add_events_per_week_to_conference.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: normal, rails -Style/IndentationConsistency: - Exclude: - - 'app/controllers/users_controller.rb' - - 'app/models/event.rb' - - 'spec/controllers/subscriptions_controller_spec.rb' - -# Offense count: 4 -# Cop supports --auto-correct. -Style/LeadingCommentSpace: - Exclude: - - 'Guardfile' - - 'app/models/comment.rb' - # Offense count: 8 # Cop supports --auto-correct. Style/LineEndConcatenation: @@ -494,29 +469,6 @@ Style/MethodDefParentheses: - 'app/models/user.rb' - 'lib/tasks/demo_data_for_development.rake' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: symmetrical, new_line, same_line -Style/MultilineArrayBraceLayout: - Exclude: - - 'app/controllers/conference_registrations_controller.rb' - -# Offense count: 5 -# Cop supports --auto-correct. -Style/MultilineBlockLayout: - Exclude: - - 'app/serializers/conference_serializer.rb' - -# Offense count: 6 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: symmetrical, new_line, same_line -Style/MultilineHashBraceLayout: - Exclude: - - 'app/serializers/conference_serializer.rb' - - 'spec/models/event_spec.rb' - # Offense count: 7 # Cop supports --auto-correct. Style/MultilineIfModifier: @@ -527,33 +479,6 @@ Style/MultilineIfModifier: - 'app/models/event.rb' - 'app/models/registration_period.rb' -# Offense count: 40 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: symmetrical, new_line, same_line -Style/MultilineMethodCallBraceLayout: - Enabled: false - -# Offense count: 55 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: aligned, indented, indented_relative_to_receiver -Style/MultilineMethodCallIndentation: - Enabled: false - -# Offense count: 27 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: aligned, indented -Style/MultilineOperationIndentation: - Exclude: - - 'app/controllers/admin/events_controller.rb' - - 'app/controllers/application_controller.rb' - - 'app/models/ability.rb' - - 'app/models/conference.rb' - - 'app/models/event.rb' - - 'db/migrate/20140701123203_add_events_per_week_to_conference.rb' - # Offense count: 2 # Cop supports --auto-correct. Style/MutableConstant: @@ -622,23 +547,21 @@ Style/ParenthesesAroundCondition: - 'app/controllers/application_controller.rb' - 'app/helpers/format_helper.rb' -# Offense count: 17 +# Offense count: 14 # Cop supports --auto-correct. # Configuration parameters: PreferredDelimiters. Style/PercentLiteralDelimiters: Exclude: - 'Gemfile' - 'app/controllers/admin/users_controller.rb' - - 'app/models/ability.rb' + - 'app/models/cfp.rb' - 'app/models/comment.rb' - 'app/models/commercial.rb' - 'app/models/conference.rb' - 'app/models/contact.rb' - 'app/models/registration.rb' - 'app/models/subscription.rb' - - 'app/models/cfp.rb' - 'app/uploaders/picture_uploader.rb' - - 'spec/models/ability_spec.rb' - 'spec/models/program_spec.rb' # Offense count: 2 @@ -667,12 +590,6 @@ Style/PreferredHashMethods: Style/RaiseArgs: EnforcedStyle: compact -# Offense count: 1 -# Cop supports --auto-correct. -Style/RedundantBegin: - Exclude: - - 'app/models/revision_observer.rb' - # Offense count: 1 # Cop supports --auto-correct. Style/RedundantParentheses: @@ -713,96 +630,6 @@ Style/SingleLineMethods: Exclude: - 'Guardfile' -# Offense count: 1 -# Cop supports --auto-correct. -Style/SpaceAfterComma: - Exclude: - - 'lib/tasks/data_demo.rake' - -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: space, no_space -Style/SpaceAroundEqualsInParameterDefault: - Exclude: - - 'app/helpers/format_helper.rb' - - 'app/models/event.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: AllowForAlignment. -Style/SpaceAroundOperators: - Exclude: - - 'lib/tasks/data.rake' - -# Offense count: 319 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: space, no_space -Style/SpaceBeforeBlockBraces: - Enabled: false - -# Offense count: 1 -# Cop supports --auto-correct. -Style/SpaceBeforeComma: - Exclude: - - 'lib/tasks/data_demo.rake' - -# Offense count: 1 -# Cop supports --auto-correct. -Style/SpaceBeforeSemicolon: - Exclude: - - 'Guardfile' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/SpaceInsideArrayPercentLiteral: - Exclude: - - 'spec/models/ability_spec.rb' - -# Offense count: 62 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. -# SupportedStyles: space, no_space -# SupportedStylesForEmptyBraces: space, no_space -Style/SpaceInsideBlockBraces: - Exclude: - - 'app/controllers/admin/comments_controller.rb' - - 'app/controllers/admin/events_controller.rb' - - 'app/controllers/admin/questions_controller.rb' - - 'app/helpers/application_helper.rb' - - 'app/models/program.rb' - - 'app/models/ticket.rb' - - 'app/models/user.rb' - - 'lib/tasks/events_registrations.rake' - - 'spec/controllers/admin/event_schedules_controller_spec.rb' - - 'spec/controllers/admin/schedules_controller_spec.rb' - - 'spec/features/splashpage_spec.rb' - - 'spec/models/ability_spec.rb' - - 'spec/models/user_spec.rb' - -# Offense count: 25 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces. -# SupportedStyles: space, no_space, compact -# SupportedStylesForEmptyBraces: space, no_space -Style/SpaceInsideHashLiteralBraces: - Exclude: - - 'app/controllers/admin/conferences_controller.rb' - - 'app/controllers/api/v1/speakers_controller.rb' - - 'app/models/ability.rb' - - 'app/models/conference.rb' - - 'app/models/event_type.rb' - - 'app/models/user.rb' - - 'spec/models/event_spec.rb' - - 'spec/models/payment_spec.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -Style/SpaceInsidePercentLiteralDelimiters: - Exclude: - - 'Gemfile' - # Offense count: 16 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline. @@ -824,14 +651,14 @@ Style/StringLiteralsInInterpolation: Exclude: - 'lib/tasks/dump_db.rake' -# Offense count: 60 +# Offense count: 73 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. +# Configuration parameters: EnforcedStyle, MinSize, SupportedStyles. # SupportedStyles: percent, brackets Style/SymbolArray: Enabled: false -# Offense count: 10 +# Offense count: 11 # Cop supports --auto-correct. # Configuration parameters: IgnoredMethods. # IgnoredMethods: respond_to, define_method @@ -854,15 +681,6 @@ Style/TernaryParentheses: Exclude: - 'app/helpers/format_helper.rb' -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: final_newline, final_blank_line -Style/TrailingBlankLines: - Exclude: - - 'lib/tasks/event_attatchments.rake' - - 'lib/tasks/roles.rake' - # Offense count: 23 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyleForMultiline, SupportedStylesForMultiline. @@ -873,12 +691,6 @@ Style/TrailingCommaInLiteral: - 'db/migrate/20140701123203_add_events_per_week_to_conference.rb' - 'spec/models/conference_spec.rb' -# Offense count: 1 -# Cop supports --auto-correct. -Style/TrailingWhitespace: - Exclude: - - 'Gemfile' - # Offense count: 3 # Cop supports --auto-correct. Style/UnneededInterpolation: From d9a3b0de72a737ae830efbbd44e5d944dbe41297 Mon Sep 17 00:00:00 2001 From: Hernan Schmidt Date: Fri, 14 Jul 2017 14:12:54 +0200 Subject: [PATCH 105/237] Fix Style/ConditionalAssignment errors They did not get excluded by `--auto-gen-config` --- .../admin/volunteers_controller.rb | 10 +++++----- .../conference_registrations_controller.rb | 12 +++++------ app/models/conference.rb | 20 +++++++++---------- app/models/ticket_purchase.rb | 10 +++++----- app/models/user.rb | 10 +++++----- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/app/controllers/admin/volunteers_controller.rb b/app/controllers/admin/volunteers_controller.rb index e8676bae..aefa682a 100644 --- a/app/controllers/admin/volunteers_controller.rb +++ b/app/controllers/admin/volunteers_controller.rb @@ -13,11 +13,11 @@ module Admin def show if can_manage_volunteers?(@conference) - if @conference.use_vpositions - @volunteers = @conference.registrations.joins(:vchoices).uniq - else - @volunteers = @conference.registrations.where(volunteer: true) - end + @volunteers = if @conference.use_vpositions + @conference.registrations.joins(:vchoices).uniq + else + @conference.registrations.where(volunteer: true) + end else authorize! :index, :volunteer end diff --git a/app/controllers/conference_registrations_controller.rb b/app/controllers/conference_registrations_controller.rb index c229440e..c2037318 100644 --- a/app/controllers/conference_registrations_controller.rb +++ b/app/controllers/conference_registrations_controller.rb @@ -38,12 +38,12 @@ class ConferenceRegistrationsController < ApplicationController def create @registration = @conference.registrations.new(registration_params) - if current_user.nil? - # @user variable needs to be set so that _sign_up_form_embedded works properly - @user = @registration.build_user(user_params) - else - @user = current_user - end + @user = if current_user.nil? + # @user variable needs to be set so that _sign_up_form_embedded works properly + @registration.build_user(user_params) + else + current_user + end @registration.user = @user authorize! :create, @registration diff --git a/app/models/conference.rb b/app/models/conference.rb index 68cdc186..db6b4745 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -563,11 +563,11 @@ class Conference < ActiveRecord::Base # ====Returns # * +hash+ -> track => {color, value} def tracks_distribution(state = nil) - if state - tracks_grouped = program.events.select(:track_id).where('state = ?', state).group(:track_id) - else - tracks_grouped = program.events.select(:track_id).group(:track_id) - end + tracks_grouped = if state + program.events.select(:track_id).where('state = ?', state).group(:track_id) + else + program.events.select(:track_id).group(:track_id) + end tracks_counted = tracks_grouped.count calculate_track_distribution_hash(tracks_grouped, tracks_counted) @@ -1001,11 +1001,11 @@ class Conference < ActiveRecord::Base # ====Returns # * +hash+ -> object_type => {color, value} def calculate_event_distribution(group_by_id, association_symbol, state = nil) - if state - grouped = program.events.select(group_by_id).where('state = ?', 'confirmed').group(group_by_id) - else - grouped = program.events.select(group_by_id).group(group_by_id) - end + grouped = if state + program.events.select(group_by_id).where('state = ?', 'confirmed').group(group_by_id) + else + program.events.select(group_by_id).group(group_by_id) + end counted = grouped.count calculate_distribution_hash(grouped, counted, association_symbol) diff --git a/app/models/ticket_purchase.rb b/app/models/ticket_purchase.rb index 88e1f4de..a19678a7 100644 --- a/app/models/ticket_purchase.rb +++ b/app/models/ticket_purchase.rb @@ -29,11 +29,11 @@ class TicketPurchase < ActiveRecord::Base conference.tickets.each do |ticket| quantity = purchases[ticket.id.to_s].to_i # if the user bought the ticket and is still unpaid, just update the quantity - if ticket.bought?(user) && ticket.unpaid?(user) - purchase = update_quantity(conference, quantity, ticket, user) - else - purchase = purchase_ticket(conference, quantity, ticket, user) - end + purchase = if ticket.bought?(user) && ticket.unpaid?(user) + update_quantity(conference, quantity, ticket, user) + else + purchase_ticket(conference, quantity, ticket, user) + end if purchase && !purchase.save errors.push(purchase.errors.full_messages) diff --git a/app/models/user.rb b/app/models/user.rb index e79d0b2a..54a9deba 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -30,13 +30,13 @@ class User < ActiveRecord::Base # :lockable, :timeoutable and :omniauthable devise_modules = [] - if ENV['OSEM_ICHAIN_ENABLED'] == 'true' - devise_modules += [:ichain_authenticatable, :ichain_registerable, :omniauthable, omniauth_providers: []] - else - devise_modules += [:database_authenticatable, :registerable, + devise_modules += if ENV['OSEM_ICHAIN_ENABLED'] == 'true' + [:ichain_authenticatable, :ichain_registerable, :omniauthable, omniauth_providers: []] + else + [:database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :omniauthable, omniauth_providers: [:suse, :google, :facebook, :github]] - end + end devise(*devise_modules) From e2a4cfd9fd5a9e2a47da9656ed734f58c07b1e5c Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Sat, 15 Jul 2017 03:37:32 +0530 Subject: [PATCH 106/237] Added ticket pdf prawn document --- app/controllers/physical_ticket_controller.rb | 10 +++ app/pdfs/ticket_pdf.rb | 81 +++++++++++++++++++ app/views/physical_ticket/show.pdf.prawn | 62 -------------- 3 files changed, 91 insertions(+), 62 deletions(-) create mode 100644 app/pdfs/ticket_pdf.rb delete mode 100644 app/views/physical_ticket/show.pdf.prawn diff --git a/app/controllers/physical_ticket_controller.rb b/app/controllers/physical_ticket_controller.rb index 8617e0d9..6bb7f50b 100644 --- a/app/controllers/physical_ticket_controller.rb +++ b/app/controllers/physical_ticket_controller.rb @@ -13,5 +13,15 @@ class PhysicalTicketController < ApplicationController @file_name = "ticket_for_#{@conference.short_title}" @user = @physical_ticket.user @ticket_layout = @conference.ticket_layout.to_sym + respond_to do |format| + format.html + format.pdf do + pdf = TicketPdf.new(@conference, @user, @physical_ticket, @ticket_layout, @file_name) + send_data pdf.render, + filename: @file_name, + type: 'application/pdf', + disposition: 'attachment' + end + end end end diff --git a/app/pdfs/ticket_pdf.rb b/app/pdfs/ticket_pdf.rb new file mode 100644 index 00000000..1c26ec77 --- /dev/null +++ b/app/pdfs/ticket_pdf.rb @@ -0,0 +1,81 @@ +class TicketPdf < Prawn::Document + def initialize(conference, user, physical_ticket, ticket_layout, file_name) + super(page_layout: ticket_layout, page_size: 'A4', filename: file_name) + @user = user + @physical_ticket = physical_ticket + @conference = conference + + @left = bounds.left + @right = bounds.right + @mid_vertical = (bounds.top - bounds.bottom) / 2 + @mid_horizontal = (bounds.right - bounds.left) / 2 + @x = 0 + + draw_first_square + draw_second_square + draw_third_square + draw_fourth_square + end + + def draw_first_square + move_down @mid_vertical + dash(2, space: 1) + stroke_horizontal_rule + stroke_vertical_line bounds.top, bounds.bottom, at: @mid_horizontal + move_up @mid_vertical + draw_text 'TICKET HOLDER', at: [@x, cursor - 30], size: 17 + dash(2, space: 0) + stroke_rectangle [@x, cursor - 50], 230, 150 + move_down 80 + draw_text 'NAME', at: [@x + 10, cursor], size: 13 + fill_color '808080' + draw_text @user.name.to_s, at: [@x + 10, cursor - 25], size: 20 + fill_color '000000' + draw_text 'EMAIL', at: [@x + 10, cursor - 50], size: 13 + fill_color '808080' + draw_text @user.email.to_s, at: [@x + 10, cursor - 75], size: 20 + fill_color '000000' + move_up 20 + end + + def draw_second_square + if @conference.picture? + if 7 * @conference.picture.image[:width] > 12 * @conference.picture.image[:height] + image "#{Rails.root}/public#{@conference.picture_url}", at: [@mid_horizontal + 30, cursor], width: 120 + else + image "#{Rails.root}/public#{@conference.picture_url}", at: [@mid_horizontal + 30, cursor], height: 70 + end + else + image "#{Rails.root}/public/img/osem-logo.png", at: [@mid_horizontal + 30, cursor], height: 70 + end + move_down 70 + draw_text @conference.title.to_s, at: [@mid_horizontal + 30, cursor - 30], size: 12 + draw_text @conference.organization.name.to_s, at: [@mid_horizontal + 30, cursor - 50], size: 12 + draw_text @conference.venue.name.to_s, at: [@mid_horizontal + 30, cursor - 70] + move_up 130 + move_down @mid_vertical + end + + def draw_third_square + draw_text 'EVENT', at: [@x, cursor - 40], size: 15 + fill_color '808080' + draw_text @conference.title.to_s, at: [@x, cursor - 60], size: 12 + draw_text @conference.start_date.strftime('%B %d, %Y').to_s, at: [@x, cursor - 80], size: 12 + move_down 80 + fill_color '000000' + draw_text 'TICKET', at: [@x, cursor - 30], size: 15 + fill_color '808080' + draw_text @physical_ticket.ticket.title.to_s, at: [@x, cursor - 50], size: 12 + move_down 50 + fill_color '000000' + draw_text 'TICKET REF.', at: [@x, cursor - 30], size: 15 + fill_color '808080' + draw_text @physical_ticket.ticket_purchase.id.to_s, at: [@x, cursor - 50], size: 12 + move_down 50 + fill_color '000000' + draw_text 'Powered By OSEM', at: [(@mid_horizontal - @left - 100) / 2, cursor - 100], size: 11 + move_up 180 + end + + def draw_fourth_square; end +end diff --git a/app/views/physical_ticket/show.pdf.prawn b/app/views/physical_ticket/show.pdf.prawn deleted file mode 100644 index 92206baf..00000000 --- a/app/views/physical_ticket/show.pdf.prawn +++ /dev/null @@ -1,62 +0,0 @@ -prawn_document(filename: @file_name, page_layout: @ticket_layout, :page_size =>'A4' ) do |pdf| - # Vertical Layout - top = pdf.bounds.top - bottom = pdf.bounds.bottom - left = pdf.bounds.left - right = pdf.bounds.right - mid_vertical = (pdf.bounds.top-pdf.bounds.bottom)/2 - mid_horizontal = (pdf.bounds.right-pdf.bounds.left)/2 - x = 0 - - pdf.move_down mid_vertical - pdf.dash(2, :space => 1) - pdf.stroke_horizontal_rule - pdf.stroke_vertical_line pdf.bounds.top, pdf.bounds.bottom, :at => mid_horizontal - pdf.move_up mid_vertical - pdf.draw_text "TICKET HOLDER", :at => [x,pdf.cursor-30], :size => 17 - pdf.dash(2, :space => 0) - pdf.stroke_rectangle [x, pdf.cursor-50], 230, 150 - pdf.move_down 80 - pdf.draw_text "NAME", :at => [x+10,pdf.cursor], :size => 13 - pdf.fill_color "808080" - pdf.draw_text "#{@user.name}", :at => [x+10,pdf.cursor-25], size: 20 - pdf.fill_color "000000" - pdf.draw_text "EMAIL", :at => [x+10,pdf.cursor-50], :size => 13 - pdf.fill_color "808080" - pdf.draw_text "#{@user.email}", :at => [x+10,pdf.cursor-75], size: 20 - pdf.fill_color "000000" - pdf.move_up 20 - if @conference.picture? - if 7 * @conference.picture.image[:width] > 12 * @conference.picture.image[:height] - pdf.image "#{Rails.root}/public#{@conference.picture_url}", :at => [mid_horizontal+30, pdf.cursor], :width => 120 - else - pdf.image "#{Rails.root}/public#{@conference.picture_url}", :at => [mid_horizontal+30, pdf.cursor], :height => 70 - end - else - pdf.image "#{Rails.root}/public/img/osem-logo.png", :at => [mid_horizontal+30, pdf.cursor], :height => 70 - end - pdf.move_down 70 - pdf.draw_text "#{@conference.title}", :at => [mid_horizontal+30,pdf.cursor-30], :size => 12 - pdf.draw_text "#{@conference.organization.name}", :at => [mid_horizontal+30,pdf.cursor-50], :size => 12 - pdf.draw_text "#{@conference.venue.name}", :at => [mid_horizontal+30,pdf.cursor-70] - pdf.move_up 130 - pdf.move_down mid_vertical - pdf.draw_text "EVENT", :at => [x,pdf.cursor-40], :size => 15 - pdf.fill_color "808080" - pdf.draw_text "#{@conference.title}", :at => [x,pdf.cursor-60], size: 12 - pdf.draw_text "#{@conference.start_date.strftime('%B %d, %Y')}", :at => [x,pdf.cursor-80], size: 12 - pdf.move_down 80 - pdf.fill_color "000000" - pdf.draw_text "TICKET", :at => [x,pdf.cursor-30], :size => 15 - pdf.fill_color "808080" - pdf.draw_text "#{@physical_ticket.ticket.title}", :at => [x,pdf.cursor-50], size: 12 - pdf.move_down 50 - pdf.fill_color "000000" - pdf.draw_text "TICKET REF.", :at => [x,pdf.cursor-30], :size => 15 - pdf.fill_color "808080" - pdf.draw_text "#{@physical_ticket.ticket_purchase.id}", :at => [x,pdf.cursor-50], size: 12 - pdf.move_down 50 - pdf.fill_color "000000" - pdf.draw_text "Powered By OSEM", :at => [(mid_horizontal-left-100)/2,pdf.cursor-100], :size => 11 - pdf.move_up 180 -end From f9d8c9715c241d0bf9a3bb735ea37630c2dd6cf5 Mon Sep 17 00:00:00 2001 From: Svante Date: Fri, 14 Jul 2017 15:21:05 +0200 Subject: [PATCH 107/237] Add bootstrap styling to sign in form Add class `.form-control` to inputs and remove additional width styling --- app/assets/stylesheets/osem-navbar.css.scss | 8 -------- app/views/layouts/_navigation.html.haml | 8 ++++---- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/app/assets/stylesheets/osem-navbar.css.scss b/app/assets/stylesheets/osem-navbar.css.scss index 385cf93d..ef05c0a9 100644 --- a/app/assets/stylesheets/osem-navbar.css.scss +++ b/app/assets/stylesheets/osem-navbar.css.scss @@ -20,14 +20,6 @@ color: black; background-color: #eeeeee; } - input[type=text], - input[type=password] { - text-align: center; - padding: 5px; - display: block; - margin: auto; - width: 255px; - } .btn-group { width: 100%; text-align: center; diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index 48066cd7..6683ea23 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -60,13 +60,13 @@ .dropdown-menu - if ENV['OSEM_ICHAIN_ENABLED'] == 'true' = form_tag User.ichain_login_url do - = text_field_tag 'username', nil, id: 'user_ichain_email_dd', placeholder: 'Username' - = password_field_tag 'password', nil, id: 'user_ichain_password_dd', placeholder: 'Password' + = text_field_tag 'username', nil, id: 'user_ichain_email_dd', class: 'form-control', placeholder: 'Username' + = password_field_tag 'password', nil, id: 'user_ichain_password_dd', class: 'form-control', placeholder: 'Password' %button.btn.btn-success.btn-block Sign in - else = form_tag new_user_session_path do - = text_field_tag 'user[login]', nil, id: 'user_login_dd', placeholder: 'Username / E-Mail' - = password_field_tag 'user[password]', nil, id: 'user_password_dd', placeholder: 'Password' + = text_field_tag 'user[login]', nil, id: 'user_login_dd', class: 'form-control', placeholder: 'Username / E-Mail' + = password_field_tag 'user[password]', nil, id: 'user_password_dd', class: 'form-control', placeholder: 'Password' %p.text-right %small %label{for: 'user_remember_me'} Remember me From e71b06bd572992d9fcb1f61a0b66a5076574b687 Mon Sep 17 00:00:00 2001 From: rahul Date: Fri, 14 Jul 2017 01:23:03 +0530 Subject: [PATCH 108/237] Add ruby 2.4 to travis and vagrant --- .travis.yml | 2 +- bootstrap.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6c83258b..9191bbd7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ dist: trusty language: ruby cache: bundler rvm: - - 2.2.3 + - 2.4.0 before_install: - "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc" - "echo `phantomjs -v`" diff --git a/bootstrap.sh b/bootstrap.sh index 197b6be2..f0ac49fb 100644 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -2,7 +2,7 @@ pushd /vagrant echo -e "\ninstalling required software packages...\n" -zypper -q -n install update-alternatives ruby2.2-devel make gcc gcc-c++ \ +zypper -q -n install update-alternatives ruby2.4-devel make gcc gcc-c++ \ libxml2-devel libxslt-devel nodejs screen mariadb \ libmysqld-devel sqlite3-devel ImageMagick @@ -10,7 +10,7 @@ echo -e "\ndisabling versioned gem binary names...\n" echo 'install: --no-format-executable' >> /etc/gemrc echo -e "\ninstalling bundler...\n" -gem.ruby2.2 install bundler +gem.ruby2.4 install bundler echo -e "\ninstalling your bundle...\n" su - vagrant -c "cd /vagrant/; bundle install --quiet" From 7f28ff3ac9041c1a791d4f7587979673e487130b Mon Sep 17 00:00:00 2001 From: rahul Date: Fri, 14 Jul 2017 01:32:27 +0530 Subject: [PATCH 109/237] Updated rdoc-generator-fivefish gem This update is required to update yajl-ruby 1.2 to yajl-ruby 1.3 that support ruby 2.4 --- Gemfile.lock | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index effbde5b..583286a0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -228,8 +228,8 @@ GEM domain_name (~> 0.5) i18n (0.7.0) i18n_data (0.7.0) - inversion (0.12.3) - loggability (~> 0.4) + inversion (1.0.0) + loggability (~> 0.12) iso-639 (0.2.5) jquery-datatables-rails (2.2.3) jquery-rails @@ -257,7 +257,7 @@ GEM celluloid-io (>= 0.15.0) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9) - loggability (0.11.0) + loggability (0.14.0) loofah (2.0.3) nokogiri (>= 1.5.9) lumberjack (1.0.5) @@ -412,13 +412,12 @@ GEM rb-fsevent (0.9.4) rb-inotify (0.9.4) ffi (>= 0.5.0) - rdoc (4.1.1) - json (~> 1.4) - rdoc-generator-fivefish (0.1.0) - inversion (~> 0.12) - loggability (~> 0.6) - rdoc (~> 4.0) - yajl-ruby (~> 1.1) + rdoc (5.1.0) + rdoc-generator-fivefish (0.3.0) + inversion (~> 1.0) + loggability (~> 0.12) + rdoc (~> 5.0) + yajl-ruby (~> 1.3) redcarpet (3.2.3) referer-parser (0.2.1) request_store (1.1.0) @@ -548,7 +547,7 @@ GEM chronic (>= 0.6.3) xpath (2.0.0) nokogiri (~> 1.3) - yajl-ruby (1.2.0) + yajl-ruby (1.3.0) PLATFORMS ruby From a6f9fdbb4350ea0beb81e1ac79038c2c48613f04 Mon Sep 17 00:00:00 2001 From: rahul Date: Fri, 14 Jul 2017 01:48:47 +0530 Subject: [PATCH 110/237] Updated rails to 4.2.8 Rails update to 4.2.8 is necessary to get rid of Bignum and Fixnum warnings. Ruby had two visible Integer classes: Fixnum and Bignum. Ruby 2.4 unifies them into Integer. All C extensions which touch the Fixnum or Bignum class need to be fixed. --- Gemfile | 2 +- Gemfile.lock | 94 +++++++++++++++++++++++++++------------------------- 2 files changed, 49 insertions(+), 47 deletions(-) diff --git a/Gemfile b/Gemfile index 46c8731e..d58a9fe2 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ if Gem::Version.new(Bundler::VERSION) < Gem::Version.new('1.8.4') end # as web framework -gem 'rails', '~> 4.2' +gem 'rails', '~> 4.2.8' # enables serving assets in production and setting your logger to standard out # both of which are required to run an application on a twelve-factor provider diff --git a/Gemfile.lock b/Gemfile.lock index 583286a0..71c317e2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -12,40 +12,39 @@ GEM remote: https://rubygems.org/ remote: https://rails-assets.org/ specs: - actionmailer (4.2.7.1) - actionpack (= 4.2.7.1) - actionview (= 4.2.7.1) - activejob (= 4.2.7.1) + actionmailer (4.2.9) + actionpack (= 4.2.9) + actionview (= 4.2.9) + activejob (= 4.2.9) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.7.1) - actionview (= 4.2.7.1) - activesupport (= 4.2.7.1) + actionpack (4.2.9) + actionview (= 4.2.9) + activesupport (= 4.2.9) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.7.1) - activesupport (= 4.2.7.1) + actionview (4.2.9) + activesupport (= 4.2.9) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.2) + rails-html-sanitizer (~> 1.0, >= 1.0.3) active_model_serializers (0.9.4) activemodel (>= 3.2) - activejob (4.2.7.1) - activesupport (= 4.2.7.1) + activejob (4.2.9) + activesupport (= 4.2.9) globalid (>= 0.3.0) - activemodel (4.2.7.1) - activesupport (= 4.2.7.1) + activemodel (4.2.9) + activesupport (= 4.2.9) builder (~> 3.1) - activerecord (4.2.7.1) - activemodel (= 4.2.7.1) - activesupport (= 4.2.7.1) + activerecord (4.2.9) + activemodel (= 4.2.9) + activesupport (= 4.2.9) arel (~> 6.0) - activesupport (4.2.7.1) + activesupport (4.2.9) i18n (~> 0.7) - json (~> 1.7, >= 1.7.7) minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) @@ -67,7 +66,7 @@ GEM request_store user_agent_parser uuidtools - arel (6.0.3) + arel (6.0.4) ast (2.3.0) autoprefixer-rails (5.1.9) execjs @@ -88,8 +87,11 @@ GEM bootstrap3-datetimepicker-rails (3.0.3) momentjs-rails (>= 2.8.1) browser (0.6.0) - builder (3.2.2) byebug (9.0.6) + + builder (3.2.3) + columnize (~> 0.8) + debugger-linecache (~> 1.2) cancancan (1.13.1) capybara (2.6.2) addressable @@ -193,8 +195,8 @@ GEM formtastic-bootstrap (3.1.1) formtastic (>= 3.0) geocoder (1.2.2) - globalid (0.3.6) - activesupport (>= 4.1.0) + globalid (0.4.0) + activesupport (>= 4.2.0) gravtastic (3.2.6) guard (2.6.0) formatador (>= 0.2.4) @@ -261,17 +263,17 @@ GEM loofah (2.0.3) nokogiri (>= 1.5.9) lumberjack (1.0.5) - mail (2.6.3) - mime-types (>= 1.16, < 3) + mail (2.6.6) + mime-types (>= 1.16, < 4) method_source (0.8.2) - mime-types (2.99.1) + mime-types (2.99.3) mimemagic (0.3.2) mina (0.3.8) open4 (~> 1.3.4) rake mini_magick (4.5.1) mini_portile2 (2.2.0) - minitest (5.10.1) + minitest (5.10.2) momentjs-rails (2.8.1) railties (>= 3.1) monetize (1.4.0) @@ -284,7 +286,7 @@ GEM monetize (~> 1.4.0) money (~> 6.7) railties (>= 3.0) - multi_json (1.11.2) + multi_json (1.12.1) multi_xml (0.5.5) multipart-post (2.0.0) mysql2 (0.4.2) @@ -351,22 +353,22 @@ GEM coderay (~> 1.0) method_source (~> 0.8) slop (~> 3.4) - rack (1.6.4) + rack (1.6.8) rack-openid (1.3.1) rack (>= 1.1.0) ruby-openid (>= 2.1.8) rack-test (0.6.3) rack (>= 1.0) - rails (4.2.7.1) - actionmailer (= 4.2.7.1) - actionpack (= 4.2.7.1) - actionview (= 4.2.7.1) - activejob (= 4.2.7.1) - activemodel (= 4.2.7.1) - activerecord (= 4.2.7.1) - activesupport (= 4.2.7.1) + rails (4.2.9) + actionmailer (= 4.2.9) + actionpack (= 4.2.9) + actionview (= 4.2.9) + activejob (= 4.2.9) + activemodel (= 4.2.9) + activerecord (= 4.2.9) + activesupport (= 4.2.9) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.7.1) + railties (= 4.2.9) sprockets-rails rails-assets-bootstrap (3.3.6) rails-assets-jquery (>= 1.9.1, < 3) @@ -401,14 +403,14 @@ GEM rails_stdout_logging rails_serve_static_assets (0.0.4) rails_stdout_logging (0.0.3) - railties (4.2.7.1) - actionpack (= 4.2.7.1) - activesupport (= 4.2.7.1) + railties (4.2.9) + actionpack (= 4.2.9) + activesupport (= 4.2.9) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.2.2) - rake - rake (10.5.0) + + rainbow (2.2.1) + rake (12.0.0) rb-fsevent (0.9.4) rb-inotify (0.9.4) ffi (>= 0.5.0) @@ -506,7 +508,7 @@ GEM sysexits (1.2.0) term-ansicolor (1.3.2) tins (~> 1.0) - thor (0.19.1) + thor (0.19.4) thread_safe (0.3.6) tilt (1.4.1) timecop (0.7.1) @@ -615,7 +617,7 @@ DEPENDENCIES poltergeist prawn-qrcode (~> 0.2.2.1) prawn_rails - rails (~> 4.2) + rails (~> 4.2.8) rails-assets-bootstrap-markdown! rails-assets-date.format! rails-assets-holderjs! From d4d1512c61b39291816ffa42a07054af03203008 Mon Sep 17 00:00:00 2001 From: rahul Date: Fri, 14 Jul 2017 01:56:49 +0530 Subject: [PATCH 111/237] Updated rspec-rails and guard rspec Updated this gem to fix nomethoderror old version of rspec use last_comment method which is deprecated in latest versions --- Gemfile | 4 +- Gemfile.lock | 101 +++++++++--------- .../admin/roles_controller_spec.rb | 2 +- 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/Gemfile b/Gemfile index d58a9fe2..1b0a3c1d 100644 --- a/Gemfile +++ b/Gemfile @@ -201,7 +201,7 @@ gem 'selectize-rails' # Use guard and spring for testing in development group :development do # to launch specs when files are modified - gem 'guard-rspec', '~> 4.2.8' + gem 'guard-rspec' gem 'spring-commands-rspec' gem 'haml_lint', '~> 0.24.0' # for static code analisys @@ -220,7 +220,7 @@ end group :test do # as test framework - gem 'rspec-rails' + gem 'rspec-rails', '~> 3.5', '>= 3.5.2' gem 'database_cleaner' gem 'capybara' gem 'poltergeist' diff --git a/Gemfile.lock b/Gemfile.lock index 71c317e2..928c3b84 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,11 +109,6 @@ GEM activesupport (>= 3.2.0) carrierwave fastimage - celluloid (0.15.2) - timers (~> 1.1.0) - celluloid-io (0.15.0) - celluloid (>= 0.15.0) - nio4r (>= 0.5.0) chart-js-rails (0.0.6) railties (> 3.1) chronic (0.10.2) @@ -123,7 +118,7 @@ GEM aws_cf_signer rest-client cocoon (1.2.6) - coderay (1.1.0) + coderay (1.1.1) coffee-rails (4.1.1) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.1.x) @@ -165,7 +160,7 @@ GEM warden (~> 1.2.3) devise_ichain_authenticatable (0.3.1) devise (>= 2.2) - diff-lcs (1.2.5) + diff-lcs (1.3) docile (1.1.5) domain_name (0.5.20160310) unf (>= 0.0.5, < 1.0.0) @@ -186,10 +181,10 @@ GEM multipart-post (>= 1.2, < 3) fastimage (2.0.0) addressable (~> 2) - ffi (1.9.3) + ffi (1.9.18) font-awesome-rails (4.1.0.0) railties (>= 3.2, < 5.0) - formatador (0.2.4) + formatador (0.2.5) formtastic (3.1.3) actionpack (>= 3.2.13) formtastic-bootstrap (3.1.1) @@ -198,15 +193,20 @@ GEM globalid (0.4.0) activesupport (>= 4.2.0) gravtastic (3.2.6) - guard (2.6.0) + guard (2.14.1) formatador (>= 0.2.4) - listen (~> 2.7) + listen (>= 2.7, < 4.0) lumberjack (~> 1.0) + nenv (~> 0.1) + notiffany (~> 0.0) pry (>= 0.9.12) + shellany (~> 0.0) thor (>= 0.18.1) - guard-rspec (4.2.8) + guard-compat (1.2.1) + guard-rspec (4.7.3) guard (~> 2.1) - rspec (>= 2.14, < 4.0) + guard-compat (~> 1.1) + rspec (>= 2.99.0, < 4.0) haml (4.0.5) tilt haml-rails (0.5.3) @@ -254,15 +254,14 @@ GEM actionmailer (>= 3.2) letter_opener (~> 1.0) railties (>= 3.2) - listen (2.7.2) - celluloid (>= 0.15.2) - celluloid-io (>= 0.15.0) - rb-fsevent (>= 0.9.3) - rb-inotify (>= 0.9) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) loggability (0.14.0) loofah (2.0.3) nokogiri (>= 1.5.9) - lumberjack (1.0.5) + lumberjack (1.0.12) mail (2.6.6) mime-types (>= 1.16, < 4) method_source (0.8.2) @@ -290,10 +289,13 @@ GEM multi_xml (0.5.5) multipart-post (2.0.0) mysql2 (0.4.2) + nenv (0.3.0) netrc (0.11.0) - nio4r (1.2.1) nokogiri (1.8.0) mini_portile2 (~> 2.2.0) + notiffany (0.1.1) + nenv (~> 0.1) + shellany (~> 0.0) oauth2 (0.9.4) faraday (>= 0.8, < 0.10) jwt (~> 1.0) @@ -349,9 +351,9 @@ GEM prawn_rails (0.0.11) prawn (>= 0.11.1) railties (>= 3.0.0) - pry (0.9.12.6) - coderay (~> 1.0) - method_source (~> 0.8) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) slop (~> 3.4) rack (1.6.8) rack-openid (1.3.1) @@ -411,9 +413,9 @@ GEM rainbow (2.2.1) rake (12.0.0) - rb-fsevent (0.9.4) - rb-inotify (0.9.4) - ffi (>= 0.5.0) + rb-fsevent (0.10.2) + rb-inotify (0.9.10) + ffi (>= 0.5.0, < 2) rdoc (5.1.0) rdoc-generator-fivefish (0.3.0) inversion (~> 1.0) @@ -432,32 +434,33 @@ GEM rolify (5.1.0) rqrcode (0.10.1) chunky_png (~> 1.0) - rspec (3.0.0) - rspec-core (~> 3.0.0) - rspec-expectations (~> 3.0.0) - rspec-mocks (~> 3.0.0) + rspec (3.6.0) + rspec-core (~> 3.6.0) + rspec-expectations (~> 3.6.0) + rspec-mocks (~> 3.6.0) rspec-activemodel-mocks (1.0.1) activemodel (>= 3.0) activesupport (>= 3.0) rspec-mocks (>= 2.99, < 4.0) - rspec-core (3.0.2) - rspec-support (~> 3.0.0) - rspec-expectations (3.0.2) + rspec-core (3.6.0) + rspec-support (~> 3.6.0) + rspec-expectations (3.6.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.0.0) - rspec-mocks (3.0.2) - rspec-support (~> 3.0.0) - rspec-rails (3.0.0) + rspec-support (~> 3.6.0) + rspec-mocks (3.6.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.6.0) + rspec-rails (3.6.0) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec-core (~> 3.0.0) - rspec-expectations (~> 3.0.0) - rspec-mocks (~> 3.0.0) - rspec-support (~> 3.0.0) - rspec-support (3.0.2) - rubocop (0.49.1) - parallel (~> 1.10) + + rspec-core (~> 3.6.0) + rspec-expectations (~> 3.6.0) + rspec-mocks (~> 3.6.0) + rspec-support (~> 3.6.0) + rspec-support (3.6.0) + rubocop (0.48.1) parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) @@ -466,6 +469,7 @@ GEM ruby-oembed (0.8.14) ruby-openid (2.5.0) ruby-progressbar (1.8.1) + ruby_dep (1.5.0) rubyzip (1.2.1) safe_yaml (1.0.4) sass (3.2.19) @@ -475,6 +479,7 @@ GEM sprockets (~> 2.8, < 2.12) sprockets-rails (~> 2.0) selectize-rails (0.12.4) + shellany (0.0.1) shoulda-matchers (2.8.0) activesupport (>= 3.0.0) simplecov (0.11.2) @@ -512,7 +517,6 @@ GEM thread_safe (0.3.6) tilt (1.4.1) timecop (0.7.1) - timers (1.1.0) tins (1.6.0) transitions (0.1.12) ttfunk (1.1.1) @@ -590,7 +594,7 @@ DEPENDENCIES formtastic (~> 3.1.1) formtastic-bootstrap gravtastic - guard-rspec (~> 4.2.8) + guard-rspec haml-rails haml_lint (~> 0.24.0) hoptoad_notifier (~> 2.3) @@ -637,8 +641,9 @@ DEPENDENCIES rolify rqrcode rspec-activemodel-mocks - rspec-rails - rubocop (~> 0.49.0) + + rspec-rails (~> 3.5, >= 3.5.2) + rubocop (~> 0.48.1) ruby-oembed sass-rails (>= 4.0.2) selectize-rails diff --git a/spec/controllers/admin/roles_controller_spec.rb b/spec/controllers/admin/roles_controller_spec.rb index 964346ef..d5cdc67e 100644 --- a/spec/controllers/admin/roles_controller_spec.rb +++ b/spec/controllers/admin/roles_controller_spec.rb @@ -55,7 +55,7 @@ describe Admin::RolesController do end describe 'POST #toggle' do - before:each do + before :each do sign_in admin post :toggle_user, conference_id: conference.short_title, user: { email: 'user1@osem.io' }, From 5c0a565e8d5f136c9d668e840decd8f4bd74cbc0 Mon Sep 17 00:00:00 2001 From: rahul Date: Sat, 15 Jul 2017 19:59:02 +0530 Subject: [PATCH 112/237] webmock updated Updated Webmock as previous version was not compatible with the new gems --- Gemfile.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 928c3b84..8f7ef5d6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -57,7 +57,8 @@ GEM awesome_nested_set (>= 2.0) acts_as_list (0.4.0) activerecord (>= 3.0) - addressable (2.3.6) + addressable (2.5.1) + public_suffix (~> 2.0, >= 2.0.2) ahoy_matey (1.0.0) addressable browser (>= 0.4.0) @@ -87,11 +88,8 @@ GEM bootstrap3-datetimepicker-rails (3.0.3) momentjs-rails (>= 2.8.1) browser (0.6.0) - byebug (9.0.6) - builder (3.2.3) - columnize (~> 0.8) - debugger-linecache (~> 1.2) + byebug (9.0.6) cancancan (1.13.1) capybara (2.6.2) addressable @@ -140,7 +138,7 @@ GEM term-ansicolor (~> 1.3) thor (~> 0.19.1) tins (~> 1.6.0) - crack (0.4.2) + crack (0.4.3) safe_yaml (~> 1.0.0) currencies (0.4.2) daemons (1.1.9) @@ -220,6 +218,7 @@ GEM rake (>= 10, < 13) rubocop (>= 0.47.0) sysexits (~> 1.1) + hashdiff (0.3.4) hashie (2.1.1) hike (1.2.3) hoptoad_notifier (2.4.11) @@ -355,6 +354,7 @@ GEM coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) + public_suffix (2.0.5) rack (1.6.8) rack-openid (1.3.1) rack (>= 1.1.0) @@ -410,8 +410,8 @@ GEM activesupport (= 4.2.9) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - - rainbow (2.2.1) + rainbow (2.2.2) + rake rake (12.0.0) rb-fsevent (0.10.2) rb-inotify (0.9.10) @@ -454,13 +454,13 @@ GEM actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec-core (~> 3.6.0) rspec-expectations (~> 3.6.0) rspec-mocks (~> 3.6.0) rspec-support (~> 3.6.0) rspec-support (3.6.0) - rubocop (0.48.1) + rubocop (0.49.1) + parallel (~> 1.10) parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) @@ -542,9 +542,10 @@ GEM binding_of_caller (>= 0.7.2) railties (>= 4.0) sprockets-rails (>= 2.0, < 4.0) - webmock (1.20.4) + webmock (3.0.1) addressable (>= 2.3.6) crack (>= 0.3.2) + hashdiff websocket-driver (0.6.3) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) @@ -641,9 +642,8 @@ DEPENDENCIES rolify rqrcode rspec-activemodel-mocks - rspec-rails (~> 3.5, >= 3.5.2) - rubocop (~> 0.48.1) + rubocop (~> 0.49.0) ruby-oembed sass-rails (>= 4.0.2) selectize-rails From f4f05b4e9bed440f486ca81cc07c1fdc70d7fb88 Mon Sep 17 00:00:00 2001 From: gotens1211 Date: Tue, 21 Mar 2017 17:57:01 +0530 Subject: [PATCH 113/237] Fixes #1195 Made the charts responsive for small screens --- .../conferences/_doughnut_chart.html.haml | 19 ++++++++++++++++++- .../admin/conferences/_line_chart.html.haml | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/app/views/admin/conferences/_doughnut_chart.html.haml b/app/views/admin/conferences/_doughnut_chart.html.haml index c8ef55fc..f4a8f0ba 100644 --- a/app/views/admin/conferences/_doughnut_chart.html.haml +++ b/app/views/admin/conferences/_doughnut_chart.html.haml @@ -1,6 +1,23 @@ .text-center %h4 #{title} - %canvas.doughnut_chart{ 'data-chart' => data.to_json } + %canvas.doughnut_chart{ id: "dough_#{title}", 'data-chart' => data.to_json } - if data - data.each do |key, value| %span{ 'style' => "border-bottom: 3px solid #{value['color']}" } #{key}: #{value['value']} + +:javascript + $(document).ready( function(){ + + var d = $("#dough_#{title}"); + var dt = d.get(0).getContext('2d'); + + $(window).resize( respondCanvas ); + + function respondCanvas(){ + dt.canvas.width = 150; + dt.canvas.height = 150; + } + + respondCanvas(); + + }); diff --git a/app/views/admin/conferences/_line_chart.html.haml b/app/views/admin/conferences/_line_chart.html.haml index cd49df10..12d825e7 100644 --- a/app/views/admin/conferences/_line_chart.html.haml +++ b/app/views/admin/conferences/_line_chart.html.haml @@ -27,3 +27,21 @@ %span{ 'style' => "border-bottom: 3px solid #{conference[:color]};", 'data-chart' => "#{name}" } %input{ 'type' => 'checkbox', 'name' => "#{conference[:short_title]}" } #{conference[:short_title]} + +:javascript + $(document).ready( function(){ + + var c = $("#line_chart_#{name}"); + var ct = c.get(0).getContext('2d'); + var container = $(c).parent(); + + $(window).resize( respondCanvas ); + + function respondCanvas(){ + c.attr('width', $(container).width() ); + c.attr('height', $(container).height() ); + } + + respondCanvas(); + + }); From 003926ea8f0c78e5586b576a150bfcaafa4721fe Mon Sep 17 00:00:00 2001 From: Stella Rouzi Date: Fri, 14 Jul 2017 15:03:14 +0300 Subject: [PATCH 114/237] Move some contributing info on wiki --- CONTRIBUTING.md | 101 ------------------------------------------------ 1 file changed, 101 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c0688999..5193725d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,59 +71,6 @@ You can access the app [localhost:3000](http://localhost:3000). Whatever you cha * If you are already a contributor and you get a positive review, you can merge your pull-request yourself * If you are not already a contributor please request a merge via the pull-request comments -### Getting Started - -* When you get involved with OSEM for the first time, you can choose issues labeled as [Junior]( https://github.com/openSUSE/osem/issues?q=is%3Aissue+is%3Aopen+label%3AJunior) -* Leave a comment on the issue that you want to work on it - * We expect you to work on it and show progress by either opening a PR or commenting on the issue - * If you change your mind, and do not want to work on the issue any more, please be fair to others and leave a comment to let us know - * Do **not** work on issues that are assigned to others. If you are uncertain, ask and wait for a **contributor** to reply -* Avoid working on issues that have no label - * If you have opened a new issue, please wait for a contributor to add relevant labels -* If an issue is a feature, we should first have a rough idea on how we want to implement it - * If there is already such a discussion on the issue, you can go ahead and pick this up - * If not, please first leave a comment on how you want to implement it and wait for contributors' feedback - -### Commits -* Commit title should be short and descriptive - * title (or summary line) is the first line of the commit message - * that says what the commit is doing - * in no more than 50 characters - * starting with a word like 'Fix' or 'Add' or 'Change' - * **without** a period (.) at the end - * followed by a blank line -* Commit messages are - * up to 72 characters - * with break lines -* Reference the issue(s) the commit closes - * https://help.github.com/articles/closing-issues-via-commit-messages - * If you haven't done so since the beginning, you should reference the issue when you squash your commits - -### Pull Requests workflow -Please open a pull request (PR) only when you have finished coding, and your changes are ready to be reviewed for merging. - -* Title - * Include a comprehensive title about what this PR is doing - * Referencing the issue number on the PR title is not giving any information about what this PR is about - * The title should be short (50 characters maximum); you can add more information in the description -* Description - * Add a couple of lines about what is the problem you are trying to solve and how you have addressed it - * Add bullet points about the new things you are introducing, if applicable - * Reference the issue(s) you are solving - * Add a screenshot of your change, if you are working on something that changes how the app looks like -* Automated checks - * We automatically run the [test suite](https://github.com/openSUSE/osem/blob/master/CONTRIBUTING.md#test-suite) and security checks on every PR - * Check back later to see if all checks were successful, if not, address them or leave a comment to ask for help -* Pushing new changes to your PR - * Always add **new** commits; this tremendously helps reviewers - * Do not squash commits, unless explicitly requested by the reviewer -* Take care of your PR - * Make sure you check the status of your PR regularly - * Address your reviews, make the necessary changes, ask if something is not clear to you - * Rebase against newest changes, when needed; we cannot properly review PRs that are not rebased - -Reviewing your PR might take some time, as we are all volunteers. Please be responsive and respectful. - ### Coding Style We are using [rubocop](https://github.com/bbatsov/rubocop) as a style checker. It is checking code style each time the test suite runs. You can run it locally with @@ -141,16 +88,6 @@ We are using [rspec](http://rspec.info/)+[capybara](http://jnicklas.github.io/ca vagrant exec bundle exec rspec ``` -### Review App of your PR - -OSEM uses [Review Apps](https://devcenter.heroku.com/articles/github-integration-review-apps) on Heroku. - -* The review app can be manually created by a maintainer, and when that happens you will see a relevant message in the PR - -* Please help reviewers by adding the necessary data relevant to your PR, -eg. if your PR is doing something related to conference registrations, go to the review app and make sure there is a conference with registrations. - - ### Email Notifications **Note**: We use [letter_opener](https://github.com/ryanb/letter_opener) in development environment. You can check out your mails by visiting [localhost:3000/letter_opener](http://localhost:3000/letter_opener). @@ -181,44 +118,6 @@ OSEM_GITHUB_SECRET='sample' If you don't already have a `.env` file you can use the `dotenv.example` as a template. -## Labels for issues and PRs -...and what they mean! - -1. **Bug** - * A bug in the application, something is wrong and needs to be fixed! - * Ideally the issue includes details on how to reproduce the bug - * Reproduce the bug in master branch, and send a PR that solves it -2. **Design** - * Related to the looks and/or usability of the application; needs attention from someone who understands front-end and UX - * If you are good with graphics and design, give it a shot! -3. **Documentation** - * Related to the documentation of our application, eg our INSTALL.md file or a wiki page with instructions on how to use the app, or part of it. - * If you are working on a documentation issue, make sure you are covering all cases. -4. **Epic** - * We may, or may not, solve this, thus it is epic. It's bigger than a feature request, because it fundamentally changes or affects the app, or a significant part of it. - * Do **not** work on this without prior discussion with the maintainers, it's called epic for a reason! -5. **Feature** - * This is a new feature for something new in the app! - * If an issue is labeled *Feature*, don't work on the issue, unless the maintainers have decided on how to proceed - * Ideally, leave a comment with your proposed solution in the issue and wait for feedback -6. **Grooming** - * This is working, but could look better, thus needs some attention and grooming. -7. **Hacktoberfest** - * This is for the issues included in the coding event of Hacktoberfest. You can ignore it, when the event is not on -8. **in progress** -9. **Junior** - * For new comers! RoR beginners or people unfamiliar with the application. Where you must start if you are interested in a mentoring program we participate in. -10. **need feedback** - * Maintainers' attention is needed to decide if this is something we want in the app, and/or how it should be implemented -11. **Operation** -12. **ready** -13. **Refactorization** - * Our code needs to be re-written; to avoid code duplication, or make the code more readable, or do things in a simpler way! -14. **Research** - * Ideas to explore; and think if there is anything we want to include in our app. -15. **GSoC** - * To group all the issues and PRs related to Google Summer of Code together. - ## Code of Conduct OSEM is part of the openSUSE project. We follow all the [openSUSE Guiding Principles!](http://en.opensuse.org/openSUSE:Guiding_principles) If you think someone doesn't do that, please let us know at maintainers@osem.io From 526b7ed2a3819a5814ac6fdd901e15bc45d08ce6 Mon Sep 17 00:00:00 2001 From: Stella Rouzi Date: Mon, 17 Jul 2017 17:05:02 +0300 Subject: [PATCH 115/237] Add code of conduct file --- CODE_OF_CONDUCT.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..7e9792fa --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1 @@ +OSEM is part of the openSUSE project. We follow all the [openSUSE Guiding Principles!](http://en.opensuse.org/openSUSE:Guiding_principles) If you think someone doesn't do that, please let us know at maintainers@osem.io From f7c0b64eb51a210bdfe6f719cf7e82ed07809914 Mon Sep 17 00:00:00 2001 From: nasia Date: Wed, 17 May 2017 13:31:27 +0300 Subject: [PATCH 116/237] Introduce Booths for admin --- .haml-lint_todo.yml | 4 + app/controllers/admin/booths_controller.rb | 94 +++++++++++++++++++ app/helpers/application_helper.rb | 7 ++ app/models/admin_ability.rb | 2 + app/models/booth.rb | 75 +++++++++++++++ app/models/booth_request.rb | 9 ++ app/models/conference.rb | 1 + app/models/user.rb | 3 + .../booths/_change_state_dropdown.html.haml | 29 ++++++ app/views/admin/booths/_form.html.haml | 33 +++++++ app/views/admin/booths/edit.html.haml | 5 + app/views/admin/booths/index.html.haml | 58 ++++++++++++ app/views/admin/booths/new.html.haml | 3 + app/views/admin/booths/show.html.haml | 57 +++++++++++ config/routes.rb | 13 +++ db/migrate/20170516190048_create_booths.rb | 16 ++++ .../20170530112510_create_booth_requests.rb | 11 +++ db/schema.rb | 26 ++++- spec/factories/booths.rb | 15 +++ spec/features/cfp_ability_spec.rb | 10 ++ spec/features/organizer_ability_spec.rb | 10 ++ spec/models/booth_spec.rb | 54 +++++++++++ 22 files changed, 534 insertions(+), 1 deletion(-) create mode 100644 app/controllers/admin/booths_controller.rb create mode 100644 app/models/booth.rb create mode 100644 app/models/booth_request.rb create mode 100644 app/views/admin/booths/_change_state_dropdown.html.haml create mode 100644 app/views/admin/booths/_form.html.haml create mode 100644 app/views/admin/booths/edit.html.haml create mode 100644 app/views/admin/booths/index.html.haml create mode 100644 app/views/admin/booths/new.html.haml create mode 100644 app/views/admin/booths/show.html.haml create mode 100644 db/migrate/20170516190048_create_booths.rb create mode 100644 db/migrate/20170530112510_create_booth_requests.rb create mode 100644 spec/factories/booths.rb create mode 100644 spec/models/booth_spec.rb diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 4644a6bb..b42ccb06 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -11,6 +11,9 @@ linters: # Offense count: 945 LineLength: exclude: + - "app/views/admin/booths/_form.html.haml" + - "app/views/admin/booths/index.html.haml" + - "app/views/admin/booths/show.html.haml" - "app/views/admin/campaigns/_form.html.haml" - "app/views/admin/campaigns/index.html.haml" - "app/views/admin/cfps/_form.html.haml" @@ -179,6 +182,7 @@ linters: # Offense count: 223 InstanceVariables: exclude: + - "app/views/admin/booths/_change_state_dropdown.html.haml" - "app/views/admin/campaigns/_form.html.haml" - "app/views/admin/cfps/_booths_cfp.html.haml" - "app/views/admin/cfps/_form.html.haml" diff --git a/app/controllers/admin/booths_controller.rb b/app/controllers/admin/booths_controller.rb new file mode 100644 index 00000000..f5096c34 --- /dev/null +++ b/app/controllers/admin/booths_controller.rb @@ -0,0 +1,94 @@ +module Admin + class BoothsController < Admin::BaseController + load_and_authorize_resource :conference, find_by: :short_title + load_and_authorize_resource through: :conference + + def index; end + + def show; end + + def new; end + + def create + @booth = @conference.booths.new(booth_params) + + @booth.submitter = current_user + + if @booth.save + redirect_to admin_conference_booths_path, + notice: 'Booth successfully created.' + else + flash[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}." + render :new + end + end + + def edit; end + + def update + @booth.update_attributes(booth_params) + + if @booth.save + redirect_to admin_conference_booths_path, + notice: "Successfully updated booth for #{@booth.title}." + else + flash[:error] = "An error prohibited the Booth for #{@booth.title} "\ + "#{@booth.errors.full_messages.join('. ')}." + render :edit + end + end + + def destroy + if @booth.destroy + redirect_to admin_conference_booths_path, + notice: 'Booth successfully destroyed.' + else + redirect_to admin_conference_booths_path, + error: "Booth couldn't be deleted. #{@booth.errors.full_messages.join('. ')}." + end + end + + def accept + update_state(:accept, 'Booth accepted!') + end + + def to_accept + update_state(:to_accept, 'Booth to accept') + end + + def to_reject + update_state(:to_reject, 'Booth to reject') + end + + def reject + update_state(:reject, 'Booth rejected') + end + + def restart + update_state(:restart, 'Booth is submitted') + end + + def cancel + update_state(:cancel, 'Booth is canceled') + end + + private + + def update_state(transition, notice) + alert = @booth.update_state(transition, notice) + + if alert.blank? + flash[:notice] = notice + redirect_back_or_to(admin_conference_booths_path(conference_id: @conference.short_title)) && return + else + flash[:error] = alert + return redirect_back_or_to(admin_conference_booths_path(conference_id: @conference.short_title)) && return + end + end + + def booth_params + params.require(:booth).permit(:title, :description, :reasoning, :state, :picture, :conference_id, + :created_at, :updated_at, :submitter_relationship, :website_url, responsible_ids: []) + end + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index fe81dfad..0abf6088 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -162,6 +162,13 @@ module ApplicationHelper include_blank: false, label: 'Speakers', input_html: { class: 'select-help-toggle', multiple: 'true' } end + def responsibles_selector_input(form) + users = User.active.pluck(:id, :name, :username, :email).map { |user| [user[0], user[1].blank? ? user[2] : user[1], user[2], user[3]] }.sort_by { |user| user[1].downcase } + form.input :responsibles, as: :select, + collection: options_for_select(users.map {|user| ["#{user[1]} (#{user[2]}) #{user[3]}", user[0]]}, @booth.responsibles.map(&:id)), + include_blank: false, label: 'Responsibles', input_html: { class: 'select-help-toggle', multiple: 'true' } + end + def event_types(conference) conference.program.event_types.map { |et| et.title.pluralize }.to_sentence end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index d43683fd..4244d049 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -120,6 +120,7 @@ class AdminAbility commercialable_id: conf_ids can :manage, Registration, conference_id: conf_ids can :manage, RegistrationPeriod, conference_id: conf_ids + can :manage, Booth, conference_id: conf_ids can :manage, Question, conference_id: conf_ids can :manage, Question do |question| !(question.conferences.pluck(:id) & conf_ids).empty? @@ -170,6 +171,7 @@ class AdminAbility conf_ids_for_cfp.include?(conf.id) end can [:index, :show, :update], Resource, conference_id: conf_ids_for_cfp + 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, Track, program: { conference_id: conf_ids_for_cfp } diff --git a/app/models/booth.rb b/app/models/booth.rb new file mode 100644 index 00000000..e692c663 --- /dev/null +++ b/app/models/booth.rb @@ -0,0 +1,75 @@ +class Booth < ActiveRecord::Base + include ActiveRecord::Transitions + + belongs_to :conference + has_many :booth_requests, dependent: :destroy + has_many :users, through: :booth_requests + + has_one :submitter_booth_user, -> { where(role: 'submitter') }, class_name: 'BoothRequest' + has_one :submitter, through: :submitter_booth_user, source: :user + + has_many :responsibles_booth_user, -> { where(role: 'responsible') }, class_name: 'BoothRequest' + has_many :responsibles, through: :responsibles_booth_user, source: :user + + validates :title, + uniqueness: { case_sensitive: false }, + presence: true + + validates :description, + :reasoning, + :state, + :responsibles, + :conference_id, + :website_url, + :submitter_relationship, + presence: true + + mount_uploader :picture, PictureUploader, mount_on: :logo_link + + state_machine initial: :new do + state :new + state :withdrawn + state :to_accept + state :accepted + state :to_reject + state :rejected + state :canceled + + event :restart do + transitions to: :new, from: [:withdrawn, :to_accept, :to_reject, :canceled] + end + event :withdraw do + transitions to: :withdrawn, from: [:new, :to_accept, :accepted, :to_reject, :rejected] + end + event :to_accept do + transitions to: :to_accept, from: [:new, :to_reject] + end + event :to_reject do + transitions to: :to_reject, from: [:new, :to_accept] + end + event :accept do + transitions to: :accepted, from: [:new, :to_accept] + end + event :reject do + transitions to: :rejected, from: [:new, :to_reject] + end + event :cancel do + transitions to: :canceled, from: [:accepted, :rejected] + end + end + + def transition_possible?(transition) + self.class.state_machine.events_for(current_state).include?(transition) + end + + def update_state(transition, _notice) + alert = '' + begin + send(transition) + save + rescue Transitions::InvalidTransition => e + alert = "Update state failed. #{e.message}" + end + alert + end +end diff --git a/app/models/booth_request.rb b/app/models/booth_request.rb new file mode 100644 index 00000000..438b4167 --- /dev/null +++ b/app/models/booth_request.rb @@ -0,0 +1,9 @@ +class BoothRequest < ActiveRecord::Base + belongs_to :booth + belongs_to :user + + validates :role, + presence: true + + ROLES = %w[submitter responsible].freeze +end diff --git a/app/models/conference.rb b/app/models/conference.rb index db6b4745..b528d755 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -28,6 +28,7 @@ class Conference < ActiveRecord::Base has_many :supporters, through: :ticket_purchases, source: :user has_many :tickets, dependent: :destroy has_many :resources, dependent: :destroy + has_many :booths, dependent: :destroy has_many :lodgings, dependent: :destroy has_many :registrations, dependent: :destroy diff --git a/app/models/user.rb b/app/models/user.rb index 54a9deba..f3f03ab7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -56,6 +56,9 @@ class User < ActiveRecord::Base has_many :voted_events, through: :votes, source: :events has_many :subscriptions, dependent: :destroy has_many :tracks, foreign_key: 'submitter_id' + has_many :booth_requests + has_many :booth_requests, dependent: :destroy + has_many :booths, through: :booth_requests accepts_nested_attributes_for :roles scope :admin, -> { where(is_admin: true) } diff --git a/app/views/admin/booths/_change_state_dropdown.html.haml b/app/views/admin/booths/_change_state_dropdown.html.haml new file mode 100644 index 00000000..c0418d67 --- /dev/null +++ b/app/views/admin/booths/_change_state_dropdown.html.haml @@ -0,0 +1,29 @@ +- if booth.transition_possible? :accept + %li= link_to 'Accept booth', + accept_admin_conference_booth_path(@conference.short_title, booth), + method: :patch, id: "accept_booth_#{booth.id}" + +- if booth.transition_possible? :reject + %li= link_to 'Reject booth', + reject_admin_conference_booth_path(@conference.short_title, booth), + method: :patch, confirm: 'Are you sure?', id: "reject_booth_#{booth.id}" + +- if booth.transition_possible? :to_reject + %li= link_to 'To reject booth', + to_reject_admin_conference_booth_path(@conference.short_title, booth), + method: :patch, confirm: 'Are you sure?', id: "to_reject_booth_#{booth.id}" + +- if booth.transition_possible? :restart + %li= link_to 'Start review', + restart_admin_conference_booth_path(@conference.short_title, booth), + method: :patch, id: "restart_booth_#{booth.id}" + +- if booth.transition_possible? :to_accept + %li= link_to 'To accept booth', + to_accept_admin_conference_booth_path(@conference.short_title, booth), + method: :patch, id: "to_accept_booth_#{booth.id}" + +- if booth.transition_possible? :cancel + %li= link_to 'Cancel booth', + cancel_admin_conference_booth_path(@conference.short_title, booth), + method: :patch, id: "cancel_booth_#{booth.id}" diff --git a/app/views/admin/booths/_form.html.haml b/app/views/admin/booths/_form.html.haml new file mode 100644 index 00000000..41637ac0 --- /dev/null +++ b/app/views/admin/booths/_form.html.haml @@ -0,0 +1,33 @@ +.row + .col-md-12 + .page-header + %title Request a Booth +.row + .col-md-8 + = semantic_form_for(@booth, url: @booth.new_record? ? admin_conference_booths_path(@conference.short_title) : admin_conference_booth_path(@conference.short_title, @booth.id), html: { multipart: true }) do |f| + = f.input :title, as: :string, required: true + = f.input :description, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, + hint: 'This field becomes public upon request acceptance' + = f.input :reasoning, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, + label: 'How it fits the conference' + = f.input :submitter_relationship, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, + label: 'Your personal relationship with the organization you are applying for', + hint: 'e.g. employee, member of the open source community etc' + = f.input :website_url + = responsibles_selector_input f + = image_tag f.object.picture.thumb.url if f.object.picture? + = f.input :picture + + %p.text-right + - if @booth.new_record? + = f.submit 'Create Booth Request', class: 'btn btn-success' + - else + = f.submit 'Update Booth Request', class: 'btn btn-success' + +:javascript + $(document).ready(function() { + $('#booth_responsible_ids').selectize({ + plugins: ['remove_button'], + minItems: 2 + } ) + }); diff --git a/app/views/admin/booths/edit.html.haml b/app/views/admin/booths/edit.html.haml new file mode 100644 index 00000000..9f9a5a61 --- /dev/null +++ b/app/views/admin/booths/edit.html.haml @@ -0,0 +1,5 @@ +%h1 + Editing + = @booth.title + += render 'form' diff --git a/app/views/admin/booths/index.html.haml b/app/views/admin/booths/index.html.haml new file mode 100644 index 00000000..0bcccb91 --- /dev/null +++ b/app/views/admin/booths/index.html.haml @@ -0,0 +1,58 @@ +.row + .col-md-12 + .page-header + %h1 + Booths + = "(#{@booths.length})" if @booths.any? + .pull-right + - if can? :create, Booth + = link_to 'Add Booth', new_admin_conference_booth_path(@conference.short_title), class: 'button btn btn-primary' + %p.text-muted + All the booth requests +.row + .col-md-12 + .margin-booth-table + %table.table.table-striped.table-bordered.table-hover.datatable + %thead + %th + %b ID + %th + %b Logo + %th + %b Title + %th + %b Submitter + %th + %b Responsibles + %th + %b State + %th + %b Actions + - @booths.each do |booth| + %tr + %td + = booth.id + %td + = image_tag(booth.picture.thumb.url, width: '20%') + %td + = link_to booth.title, admin_conference_booth_path(@conference.short_title, booth) + %td + = link_to booth.submitter.name, admin_user_path(booth.submitter) if booth.submitter + %td + .responsibles + - booth.responsibles.each do |responsible| + = link_to responsible.name, admin_user_path(responsible) + %td + .btn-group + %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } + = booth.state.humanize + %span.caret + %ul.dropdown-menu{ role: 'menu' } + = render 'change_state_dropdown', booth: booth + %td + .btn-group{ role: "group" } + = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id), + class: 'btn btn-primary' + = link_to 'Delete', admin_conference_booth_path(@conference.short_title, booth.id), + method: :delete, class: 'btn btn-danger', + data: {confirm: "Do you really want to delete this booth request?"} diff --git a/app/views/admin/booths/new.html.haml b/app/views/admin/booths/new.html.haml new file mode 100644 index 00000000..db1c4736 --- /dev/null +++ b/app/views/admin/booths/new.html.haml @@ -0,0 +1,3 @@ +%h1 New booth + += render 'form' diff --git a/app/views/admin/booths/show.html.haml b/app/views/admin/booths/show.html.haml new file mode 100644 index 00000000..8c692bc4 --- /dev/null +++ b/app/views/admin/booths/show.html.haml @@ -0,0 +1,57 @@ +.row + .col-md-12 + %h3 + = image_tag(@booth.picture.thumb.url, size: '20%', alt: '') + = @booth.title + .btn-group.pull-right + = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, @booth), class: 'btn btn-mini btn-primary' + +.row + .col-md-12 + %table.table + %tr + %td.col-md-2 + %b Description + %td + = markdown(@booth.description) + %tr + %td.col-md-2 + %b Reasoning + %td + = markdown(@booth.reasoning) + %tr + %td.col-md-2 + %b Website + %td + - if @booth.website_url.present? + = link_to @booth.website_url, @booth.website_url + %tr + %td.col-md-2 + %b Submitter + %td + = link_to @booth.submitter.name, admin_user_path(@booth.submitter) + %tr + %td.col-md-2 + %b Submitter's relationship + %td + = @booth.submitter_relationship + %tr + %td.col-md-2 + %b Responsibles + %td + - @booth.responsibles.each do |responsibles| + .responsibles + = link_to responsibles.name, admin_user_path(responsibles) + ( + = responsibles.email + ) + %tr + %td.col-md-2 + %b Submitted on + %td + = @booth.created_at + %tr + %td.col-md-2 + %b Last updated on + %td + = @booth.updated_at diff --git a/config/routes.rb b/config/routes.rb index 1643fc6b..5a17d314 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -37,6 +37,19 @@ Osem::Application.routes.draw do get '/volunteers' => 'volunteers#index', as: 'volunteers_info' patch '/volunteers' => 'volunteers#update', as: 'volunteers_update' + resources :booths do + member do + patch :accept + patch :restart + patch :withdrawn + patch :to_accept + patch :reject + patch :reset + patch :to_reject + patch :cancel + end + end + resources :registrations, except: [:create, :new] do member do patch :toggle_attendance diff --git a/db/migrate/20170516190048_create_booths.rb b/db/migrate/20170516190048_create_booths.rb new file mode 100644 index 00000000..d2aa0be6 --- /dev/null +++ b/db/migrate/20170516190048_create_booths.rb @@ -0,0 +1,16 @@ +class CreateBooths < ActiveRecord::Migration + def change + create_table :booths do |t| + t.string :title + t.text :description + t.text :reasoning + t.string :state + t.string :logo_link + t.string :website_url + t.text :submitter_relationship + t.references :conference + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20170530112510_create_booth_requests.rb b/db/migrate/20170530112510_create_booth_requests.rb new file mode 100644 index 00000000..75e73a93 --- /dev/null +++ b/db/migrate/20170530112510_create_booth_requests.rb @@ -0,0 +1,11 @@ +class CreateBoothRequests < ActiveRecord::Migration + def change + create_table :booth_requests do |t| + t.references :booth, index: true, foreign_key: true + t.references :user, index: true, foreign_key: true + t.string :role + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index f1a213a5..64ac0393 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -14,7 +14,7 @@ ActiveRecord::Schema.define(version: 20170711102511) do create_table "ahoy_events", force: :cascade do |t| - t.uuid "visit_id", limit: 16 + t.integer "visit_id" t.integer "user_id" t.string "name" t.text "properties" @@ -31,6 +31,30 @@ ActiveRecord::Schema.define(version: 20170711102511) do t.datetime "updated_at" end + create_table "booth_requests", force: :cascade do |t| + t.integer "booth_id" + t.integer "user_id" + t.string "role" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "booth_requests", ["booth_id"], name: "index_booth_requests_on_booth_id" + add_index "booth_requests", ["user_id"], name: "index_booth_requests_on_user_id" + + create_table "booths", force: :cascade do |t| + t.string "title" + t.text "description" + t.text "reasoning" + t.string "state" + t.string "logo_link" + t.string "website_url" + t.text "submitter_relationship" + t.integer "conference_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "campaigns", force: :cascade do |t| t.integer "conference_id" t.string "name" diff --git a/spec/factories/booths.rb b/spec/factories/booths.rb new file mode 100644 index 00000000..a67d30f0 --- /dev/null +++ b/spec/factories/booths.rb @@ -0,0 +1,15 @@ +FactoryGirl.define do + factory :booth do + title { Faker::Hipster.sentence } + description { Faker::Lorem.paragraph } + reasoning { Faker::Lorem.paragraph } + website_url { Faker::Internet.url } + submitter_relationship { Faker::Lorem.paragraph } + + conference + + after(:build) do |booth| + booth.responsibles << create(:user) + end + end +end diff --git a/spec/features/cfp_ability_spec.rb b/spec/features/cfp_ability_spec.rb index b12a2ef5..46db11c2 100644 --- a/spec/features/cfp_ability_spec.rb +++ b/spec/features/cfp_ability_spec.rb @@ -249,6 +249,16 @@ feature 'Has correct abilities' do visit admin_conference_roles_path(conference.short_title) expect(current_path).to eq(admin_conference_roles_path(conference.short_title)) + visit admin_conference_booths_path(conference.short_title) + expect(current_path).to eq(admin_conference_booths_path(conference.short_title)) + + visit new_admin_conference_booth_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_booth_path(conference.short_title)) + + create(:booth, conference: conference) + visit edit_admin_conference_booth_path(conference.short_title, conference.booths.first) + expect(current_path).to eq(edit_admin_conference_booth_path(conference.short_title, conference.booths.first)) + visit admin_conference_resources_path(conference.short_title) expect(current_path).to eq(admin_conference_resources_path(conference.short_title)) diff --git a/spec/features/organizer_ability_spec.rb b/spec/features/organizer_ability_spec.rb index 10c5d726..06a2a836 100644 --- a/spec/features/organizer_ability_spec.rb +++ b/spec/features/organizer_ability_spec.rb @@ -237,6 +237,16 @@ feature 'Has correct abilities' do visit edit_admin_conference_target_path(conference.short_title, conference.targets.first) expect(current_path).to eq(edit_admin_conference_target_path(conference.short_title, conference.targets.first)) + visit admin_conference_booths_path(conference.short_title) + expect(current_path).to eq(admin_conference_booths_path(conference.short_title)) + + visit new_admin_conference_booth_path(conference.short_title) + expect(current_path).to eq(new_admin_conference_booth_path(conference.short_title)) + + create(:booth, conference: conference) + visit edit_admin_conference_booth_path(conference.short_title, conference.booths.first) + expect(current_path).to eq(edit_admin_conference_booth_path(conference.short_title, conference.booths.first)) + visit admin_conference_program_tracks_path(conference.short_title) expect(current_path).to eq(admin_conference_program_tracks_path(conference.short_title)) diff --git a/spec/models/booth_spec.rb b/spec/models/booth_spec.rb new file mode 100644 index 00000000..f13eb536 --- /dev/null +++ b/spec/models/booth_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +describe 'Booth' do + subject { create(:booth) } + let!(:conference) { create(:conference) } + + describe 'validation' do + it 'has a valid factory' do + expect(build(:booth)).to be_valid + end + + it { is_expected.to validate_presence_of(:reasoning) } + it { is_expected.to validate_presence_of(:description) } + it { is_expected.to validate_presence_of(:responsibles) } + it { is_expected.to validate_presence_of(:submitter_relationship) } + it { is_expected.to validate_presence_of(:website_url) } + + it 'is not valid without a title' do + is_expected.to validate_presence_of(:title) + end + end + + describe 'association' do + it { is_expected.to belong_to(:conference) } + it { is_expected.to have_many(:booth_requests) } + end + + describe '#transition_possible?(transition)' do + shared_examples 'transition_possible?(transition)' do |state, transition, expected| + it "returns #{expected} for #{transition} transition, when the booth is #{state}}" do + my_booth = create(:booth, state: state) + expect(my_booth.transition_possible?(transition.to_sym)).to eq expected + end + end + + states = [:new, :withdrawn, :to_accept, :accepted, :to_reject, :rejected, :canceled] + transitions = [:restart, :withdraw, :accept, :reject, :to_accept, :to_reject, :cancel] + + states_transitions = { new: { restart: false, withdraw: true, accept: true, to_accept: true, to_reject: true, reject: true, cancel: false }, + withdrawn: { restart: true, withdraw: false, accept: false, to_accept: false, to_reject: false, reject: false, cancel: false }, + to_accept: { restart: true, withdraw: true, accept: true, to_accept: false, to_reject: true, reject: false, cancel: false }, + to_reject: { restart: true, withdraw: true, accept: false, to_accept: true, to_reject: false, reject: true, cancel: false }, + accepted: { restart: false, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true }, + rejected: { restart: false, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true }, + canceled: { restart: true, withdraw: false, accept: false, to_accept: false, to_reject: false, reject: false, cancel: false } } + + states.each do |state| + transitions.each do |transition| + it_behaves_like 'transition_possible?(transition)', state, transition, states_transitions[state.to_sym][transition.to_sym] + end + end + end + +end From d9b2ebfc369143c01c3c626026a7b609182b405e Mon Sep 17 00:00:00 2001 From: nasia Date: Mon, 17 Jul 2017 12:00:06 +0300 Subject: [PATCH 117/237] Add paper_trail --- app/models/booth.rb | 1 + app/views/admin/booths/_form.html.haml | 4 ++-- app/views/admin/booths/index.html.haml | 3 ++- app/views/admin/versions/_object_desc_and_link.html.haml | 6 ++++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/models/booth.rb b/app/models/booth.rb index e692c663..911f9485 100644 --- a/app/models/booth.rb +++ b/app/models/booth.rb @@ -1,5 +1,6 @@ class Booth < ActiveRecord::Base include ActiveRecord::Transitions + has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id } belongs_to :conference has_many :booth_requests, dependent: :destroy diff --git a/app/views/admin/booths/_form.html.haml b/app/views/admin/booths/_form.html.haml index 41637ac0..e4a7d05d 100644 --- a/app/views/admin/booths/_form.html.haml +++ b/app/views/admin/booths/_form.html.haml @@ -11,8 +11,8 @@ = f.input :reasoning, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, label: 'How it fits the conference' = f.input :submitter_relationship, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, - label: 'Your personal relationship with the organization you are applying for', - hint: 'e.g. employee, member of the open source community etc' + label: 'Submitter\'s relation', + hint: 'e.g. employee, comunity manager, etc' = f.input :website_url = responsibles_selector_input f = image_tag f.object.picture.thumb.url if f.object.picture? diff --git a/app/views/admin/booths/index.html.haml b/app/views/admin/booths/index.html.haml index 0bcccb91..15833bd7 100644 --- a/app/views/admin/booths/index.html.haml +++ b/app/views/admin/booths/index.html.haml @@ -33,7 +33,8 @@ %td = booth.id %td - = image_tag(booth.picture.thumb.url, width: '20%') + - if booth.logo_link + = image_tag(booth.picture.thumb.url, width: '20%') %td = link_to booth.title, admin_conference_booth_path(@conference.short_title, booth) %td diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index 83542ef1..d29e5f9b 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -80,6 +80,12 @@ = link_if_alive version, 'contact details', edit_admin_conference_contact_path(conference_id: Conference.find(version.conference_id).short_title) +- when 'Booth' + = 'booth' + - booth = current_or_last_object_state(version.item_type, version.item_id) + = link_if_alive version, booth.title, + admin_conference_booth_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id ) + - when 'Program' = link_if_alive version, 'program', admin_conference_program_path(conference_id: Conference.find(version.conference_id).short_title) From 4779bef9f7d486e5d316a732589929b268193735 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Wed, 19 Jul 2017 17:47:02 +0530 Subject: [PATCH 118/237] Fixed flickering proposal feature test Test were sometimes failing because of the delay between the click_link and the actual completion of the code that is run as a result of that click. --- spec/features/proposals_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index b5620475..70bcbf63 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -32,7 +32,7 @@ feature Event do click_button 'New' click_link "reject_event_#{@event.id}" - expect(flash).to eq('Event rejected!') + expect(page).to have_content 'Event rejected!' @event.reload expect(@event.state).to eq('rejected') end @@ -43,7 +43,7 @@ feature Event do click_button 'New' click_link "accept_event_#{@event.id}" - expect(flash).to eq('Event accepted!') + expect(page).to have_content 'Event accepted!' expect(page.has_content?('Unconfirmed')).to be true @event.reload expect(@event.state).to eq('unconfirmed') @@ -56,7 +56,7 @@ feature Event do click_button 'Rejected' click_link "restart_event_#{@event.id}" - expect(flash).to eq('Review started!') + expect(page).to have_content 'Review started!' @event.reload expect(@event.state).to eq('new') end From 0501ecd8f6fce5883fc68b5cfe340846c8e1c6f7 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Thu, 20 Jul 2017 17:30:27 +0530 Subject: [PATCH 119/237] Refactored proposal feature spec. Fixes #1561. --- spec/features/proposals_spec.rb | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index 70bcbf63..9dda06bf 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -28,7 +28,7 @@ feature Event do scenario 'rejects a proposal', feature: true, js: true do visit admin_conference_program_events_path(conference.short_title) - expect(page.has_content?('Example Proposal')).to be true + expect(page).to have_content 'Example Proposal' click_button 'New' click_link "reject_event_#{@event.id}" @@ -39,12 +39,12 @@ feature Event do scenario 'accepts a proposal', feature: true, js: true do visit admin_conference_program_events_path(conference.short_title) - expect(page.has_content?('Example Proposal')).to be true + expect(page).to have_content 'Example Proposal' click_button 'New' click_link "accept_event_#{@event.id}" expect(page).to have_content 'Event accepted!' - expect(page.has_content?('Unconfirmed')).to be true + expect(page).to have_content 'Unconfirmed' @event.reload expect(@event.state).to eq('unconfirmed') end @@ -52,7 +52,7 @@ feature Event do scenario 'restarts review of a proposal', feature: true, js: true do @event.reject!(@options) visit admin_conference_program_events_path(conference.short_title) - expect(page.has_content?('Example Proposal')).to be true + expect(page).to have_content 'Example Proposal' click_button 'Rejected' click_link "restart_event_#{@event.id}" @@ -83,7 +83,7 @@ feature Event do fill_in 'event_abstract', with: 'Lorem ipsum abstract' click_button 'Create Proposal' - expect(flash).to eq('Proposal was successfully submitted.') + expect(page).to have_content 'Proposal was successfully submitted.' expect(Event.count).to eq(expected_count_event) expect(User.count).to eq(expected_count_user) @@ -101,7 +101,7 @@ feature Event do select('Easy', from: 'event[difficulty_level_id]') click_button 'Update Proposal' - expect(flash).to eq('Proposal was successfully updated.') + expect(page).to have_content 'Proposal was successfully updated.' end scenario 'signed_in user submits a valid proposal', feature: true, js: true do @@ -119,7 +119,7 @@ feature Event do fill_in 'event_description', with: 'Lorem ipsum description' click_button 'Create Proposal' - expect(flash).to eq('Proposal was successfully submitted.') + expect(page).to have_content 'Proposal was successfully submitted.' expect(current_path).to eq(conference_program_proposals_path(conference.short_title)) expect(Event.count).to eq(expected_count) @@ -128,11 +128,10 @@ feature Event do scenario 'confirms a proposal', feature: true, js: true do sign_in participant visit conference_program_proposals_path(conference.short_title) - expect(page.has_content?('Example Proposal')).to be true + expect(page).to have_content 'Example Proposal' expect(@event.state).to eq('unconfirmed') click_link "confirm_proposal_#{@event.id}" - expect(flash) - .to eq('The proposal was confirmed. Please register to attend the conference.') + expect(page).to have_content 'The proposal was confirmed. Please register to attend the conference.' expect(current_path).to eq(new_conference_conference_registration_path(conference.short_title)) @event.reload expect(@event.state).to eq('confirmed') @@ -142,9 +141,9 @@ feature Event do sign_in participant @event.confirm! visit conference_program_proposals_path(conference.short_title) - expect(page.has_content?('Example Proposal')).to be true + expect(page).to have_content 'Example Proposal' click_link "delete_proposal_#{@event.id}" - expect(flash).to eq('Proposal was successfully withdrawn.') + expect(page).to have_content 'Proposal was successfully withdrawn.' @event.reload expect(@event.state).to eq('withdrawn') end From 1c9891215d27a9d4764c7fae7e3bd7fca96df71b Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Thu, 20 Jul 2017 18:14:38 +0530 Subject: [PATCH 120/237] Authorize ticket purchase --- app/controllers/ticket_purchases_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/ticket_purchases_controller.rb b/app/controllers/ticket_purchases_controller.rb index 792122e2..f15fc993 100644 --- a/app/controllers/ticket_purchases_controller.rb +++ b/app/controllers/ticket_purchases_controller.rb @@ -2,6 +2,7 @@ class TicketPurchasesController < ApplicationController before_filter :authenticate_user! load_resource :conference, find_by: :short_title authorize_resource :conference_registrations, class: Registration + authorize_resource def create current_user.ticket_purchases.by_conference(@conference).unpaid.destroy_all From 34456fa205da4dce4eee16944c716fa7733e0911 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Fri, 21 Jul 2017 04:13:23 +0530 Subject: [PATCH 121/237] Remove float point number on y axis --- app/assets/javascripts/osem-dashboard.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/osem-dashboard.js b/app/assets/javascripts/osem-dashboard.js index c8d5b853..83d2b468 100644 --- a/app/assets/javascripts/osem-dashboard.js +++ b/app/assets/javascripts/osem-dashboard.js @@ -55,7 +55,6 @@ $(function() { } function draw_line_chart(animation, $canvas){ - var options = get_animation({}, animation); var chart_data = create_dataset($canvas); var weeks = $canvas.parent().data('weeks'); var data = { @@ -63,10 +62,27 @@ $(function() { datasets : chart_data } + var options = get_animation(wholeNumberAxisFix(data), animation); var ctx = $canvas.get(0).getContext("2d"); new Chart(ctx).Line(data, options); } + function wholeNumberAxisFix(data){ + var maxValue = false; + for(datasetIndex = 0; datasetIndex < data.datasets.length; ++datasetIndex){ + var setMax = Math.max.apply(null, data.datasets[datasetIndex].data); + if (maxValue === false || setMax > maxValue) maxValue = setMax; + } + + var steps = maxValue; + var stepWidth = 1; + if (maxValue > 10) { + stepWidth = Math.floor(maxValue / 10); + steps = Math.ceil(maxValue / stepWidth); + } + return { scaleOverride: true, scaleSteps: steps, scaleStepWidth: stepWidth, scaleStartValue: 0 }; + } + function create_dataset($canvas){ var selected = getSelectedConferences($canvas); var chart_data = $canvas.parent().data('chart'); From c6b0a1f52e9936aeff7705d3037b409a89e3e0c0 Mon Sep 17 00:00:00 2001 From: nasia Date: Sun, 16 Jul 2017 18:20:12 +0300 Subject: [PATCH 122/237] Add tests for booth controller --- app/models/booth.rb | 2 +- app/views/admin/booths/_form.html.haml | 2 +- .../admin/booths_controller_spec.rb | 148 ++++++++++++++++++ spec/factories/booth_request.rb | 8 + spec/factories/booths.rb | 4 +- spec/models/booth_spec.rb | 4 +- 6 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 spec/controllers/admin/booths_controller_spec.rb create mode 100644 spec/factories/booth_request.rb diff --git a/app/models/booth.rb b/app/models/booth.rb index 911f9485..5c20550a 100644 --- a/app/models/booth.rb +++ b/app/models/booth.rb @@ -55,7 +55,7 @@ class Booth < ActiveRecord::Base transitions to: :rejected, from: [:new, :to_reject] end event :cancel do - transitions to: :canceled, from: [:accepted, :rejected] + transitions to: :canceled, from: [:accepted, :rejected, :to_accept, :to_reject] end end diff --git a/app/views/admin/booths/_form.html.haml b/app/views/admin/booths/_form.html.haml index e4a7d05d..f70079fa 100644 --- a/app/views/admin/booths/_form.html.haml +++ b/app/views/admin/booths/_form.html.haml @@ -5,7 +5,7 @@ .row .col-md-8 = semantic_form_for(@booth, url: @booth.new_record? ? admin_conference_booths_path(@conference.short_title) : admin_conference_booth_path(@conference.short_title, @booth.id), html: { multipart: true }) do |f| - = f.input :title, as: :string, required: true + = f.input :title, as: :string, autofocus: true, required: true = f.input :description, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, hint: 'This field becomes public upon request acceptance' = f.input :reasoning, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, diff --git a/spec/controllers/admin/booths_controller_spec.rb b/spec/controllers/admin/booths_controller_spec.rb new file mode 100644 index 00000000..569862d1 --- /dev/null +++ b/spec/controllers/admin/booths_controller_spec.rb @@ -0,0 +1,148 @@ +require 'spec_helper' + +describe Admin::BoothsController do + + let(:admin) { create(:admin) } + let(:conference) { create(:conference) } + let(:booth) { create(:booth, title: 'Title', conference: conference) } + let(:admin) { create(:admin) } + + context 'not logged in user' do + + describe 'GET index' do + it 'does not render admin/booths#index' do + get :index, conference_id: conference.short_title + expect(response).to redirect_to(user_session_path) + end + end + + describe 'GET show' do + it 'does not render admin/booths#show' do + get :show, id: booth.id, conference_id: conference.short_title + expect(response).to redirect_to(user_session_path) + end + end + end + + context 'user is admin' do + before :each do + sign_in admin + end + + describe 'GET index' do + before { get :index, conference_id: conference.short_title } + + it 'assigns attributes for booths' do + expect(assigns(:booths)).to eq([booth]) + end + + it 'renders index template' do + expect(response).to render_template('index') + end + end + + describe 'GET new' do + before { get :new, conference_id: conference.short_title } + + it 'assigns attributes for booths' do + expect(assigns(:booth)).to be_a_new(Booth) + end + + it 'renders new template' do + expect(response).to render_template('new') + end + end + + describe 'POST #create' do + context 'successfully created' do + before { post :create, booth: attributes_for(:booth), conference_id: conference.short_title } + + it 'creates a new booth' do + expected = expect do + post :create, booth: attributes_for(:booth), conference_id: conference.short_title + end + expected.to change { Booth.count }.by(1) + end + + it 'redirects to admin booth index' do + expect(response).to redirect_to(admin_conference_booths_path) + end + + it 'has responsibles' do + expect(booth.responsibles.count).to_not eq(0) + end + + it 'shows success message' do + expect(flash[:notice]).to match('Booth successfully created.') + end + end + + context 'create action fails' do + before { post :create, booth: attributes_for(:booth, title: ''), conference_id: conference.short_title } + + it 'does not create any record' do + expected = expect do + post :create, booth: attributes_for(:booth, title: ''), conference_id: conference.short_title + end + expected.to_not change(Booth, :count) + end + + it 'redirects to new' do + expect(response).to render_template('new') + end + + it 'shows flash message' do + expect(flash[:error]).to eq("Creating booth failed. Title can't be blank.") + end + end + end + + describe 'GET #edit' do + before { get :edit, id: booth.id, conference_id: conference.short_title } + + it 'renders edit template' do + expect(response).to render_template('edit') + end + + it 'assigns booth variable' do + expect(assigns(:booth)).to eq booth + end + end + + describe 'PATCH #update' do + context 'updates suchessfully' do + before { patch :update, id: booth.id, booth: attributes_for(:booth, title: 'different'), conference_id: conference.short_title } + it 'redirects to admin booth index path' do + expect(response).to redirect_to admin_conference_booths_path + end + + it 'shows success message' do + expect(flash[:notice]).to match 'Successfully updated booth.' + end + + it 'updates booth' do + booth.reload + expect(booth.title).to eq('different') + end + end + end + + describe 'DELETE #destroy' do + context 'deletes successfully' do + before { delete :destroy, id: booth.id, conference_id: conference.short_title } + + it 'booth deleted' do + expect(Booth.count).to eq(0) + end + + it 'redirects to admin booth index path' do + expect(response).to redirect_to(admin_conference_booths_path) + end + + it 'show success message' do + expect(flash[:notice]).to match('Booth successfully destroyed.') + end + end + end + end +end diff --git a/spec/factories/booth_request.rb b/spec/factories/booth_request.rb new file mode 100644 index 00000000..fba0cace --- /dev/null +++ b/spec/factories/booth_request.rb @@ -0,0 +1,8 @@ +FactoryGirl.define do + factory :booth_request do + booth + user + role 'responsible' + + end +end diff --git a/spec/factories/booths.rb b/spec/factories/booths.rb index a67d30f0..b1cd1956 100644 --- a/spec/factories/booths.rb +++ b/spec/factories/booths.rb @@ -8,8 +8,6 @@ FactoryGirl.define do conference - after(:build) do |booth| - booth.responsibles << create(:user) - end + responsible_ids { [create(:user).id] } end end diff --git a/spec/models/booth_spec.rb b/spec/models/booth_spec.rb index f13eb536..5e86a393 100644 --- a/spec/models/booth_spec.rb +++ b/spec/models/booth_spec.rb @@ -38,8 +38,8 @@ describe 'Booth' do states_transitions = { new: { restart: false, withdraw: true, accept: true, to_accept: true, to_reject: true, reject: true, cancel: false }, withdrawn: { restart: true, withdraw: false, accept: false, to_accept: false, to_reject: false, reject: false, cancel: false }, - to_accept: { restart: true, withdraw: true, accept: true, to_accept: false, to_reject: true, reject: false, cancel: false }, - to_reject: { restart: true, withdraw: true, accept: false, to_accept: true, to_reject: false, reject: true, cancel: false }, + to_accept: { restart: true, withdraw: true, accept: true, to_accept: false, to_reject: true, reject: false, cancel: true }, + to_reject: { restart: true, withdraw: true, accept: false, to_accept: true, to_reject: false, reject: true, cancel: true }, accepted: { restart: false, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true }, rejected: { restart: false, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true }, canceled: { restart: true, withdraw: false, accept: false, to_accept: false, to_reject: false, reject: false, cancel: false } } From 2bf7e4bbd343e0a4a062762dd0dfd4a421b997e9 Mon Sep 17 00:00:00 2001 From: Dimitris Date: Sat, 15 Jul 2017 03:02:03 +0300 Subject: [PATCH 123/237] Fix user already subscribed exception Prevent excpetion at user subscription when already is subscribed to a conference and add hanling to the similar unsubscribe event. remove double validation at app/models/subscription.rb update subscription_controller_spec --- app/controllers/subscriptions_controller.rb | 10 ++++++---- app/models/subscription.rb | 1 - spec/controllers/subscriptions_controller_spec.rb | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/controllers/subscriptions_controller.rb b/app/controllers/subscriptions_controller.rb index 351f9e9d..76d5c74a 100644 --- a/app/controllers/subscriptions_controller.rb +++ b/app/controllers/subscriptions_controller.rb @@ -5,17 +5,19 @@ class SubscriptionsController < ApplicationController def create @subscription = current_user.subscriptions.build(conference_id: @conference.id) - if @subscription.save! - redirect_to root_path, notice: "You have been subscribed to receive email notifications for #{@conference.short_title}." + if @subscription.save + redirect_to root_path, notice: "You have subscribed to receive email notifications for #{@conference.title}." else - redirect_to root_path, error: subscription.errors.full_messages.to_sentence + redirect_to root_path, error: @subscription.errors.full_messages.to_sentence end end def destroy @subscription = current_user.subscriptions.find_by(conference_id: @conference.id) + + redirect_to(root_path, error: "You are not subscribed to #{@conference.title}.") && return unless @subscription if @subscription.destroy - redirect_to root_path, notice: "You have been unsubscribed and now you will not be receiving email notifications for #{@conference.short_title}." + redirect_to root_path, notice: "You have unsubscribed and you will not be receiving email notifications for #{@conference.title}." else redirect_to root_path, error: @subscription.errors.full_messages.to_sentence end diff --git a/app/models/subscription.rb b/app/models/subscription.rb index aa688ae8..984c46f3 100644 --- a/app/models/subscription.rb +++ b/app/models/subscription.rb @@ -1,5 +1,4 @@ class Subscription < ActiveRecord::Base - validates :user_id, uniqueness: { scope: [:conference_id] } belongs_to :conference belongs_to :user diff --git a/spec/controllers/subscriptions_controller_spec.rb b/spec/controllers/subscriptions_controller_spec.rb index 193ae23d..ac20a34b 100644 --- a/spec/controllers/subscriptions_controller_spec.rb +++ b/spec/controllers/subscriptions_controller_spec.rb @@ -24,7 +24,7 @@ describe SubscriptionsController do it 'shows success message in flash notice' do post :create, conference_id: conference.short_title - expect(flash[:notice]).to match("You have been subscribed to receive email notifications for #{conference.short_title}") + expect(flash[:notice]).to match("You have subscribed to receive email notifications for #{conference.title}") end it 'subscribes user to conference' do @@ -47,7 +47,7 @@ describe SubscriptionsController do it 'shows success message in flash notice' do delete :destroy, conference_id: conference.short_title - expect(flash[:notice]).to match("You have been unsubscribed and now you will not be receiving email notifications for #{conference.short_title}.") + expect(flash[:notice]).to match("You have unsubscribed and you will not be receiving email notifications for #{conference.title}.") end end end From 9e154a1dcd5d28102d852eb6a26eefba2cf054db Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Mon, 10 Jul 2017 20:43:27 +0530 Subject: [PATCH 124/237] Added Token field for physical_ticket Added token field in physical_ticket model. This token will also be stored in the qr code and will uniqely identify the ticket. --- app/controllers/physical_ticket_controller.rb | 2 +- app/models/physical_ticket.rb | 15 +++++++++++++++ app/views/admin/physical_ticket/index.html.haml | 6 +++--- app/views/physical_ticket/index.html.haml | 4 ++-- app/views/physical_ticket/show.html.haml | 2 +- ...0170721001700_add_index_to_physical_tickets.rb | 6 ++++++ db/schema.rb | 5 ++++- .../physical_ticket_controller_spec.rb | 2 +- 8 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 db/migrate/20170721001700_add_index_to_physical_tickets.rb diff --git a/app/controllers/physical_ticket_controller.rb b/app/controllers/physical_ticket_controller.rb index 6bb7f50b..fb25ae63 100644 --- a/app/controllers/physical_ticket_controller.rb +++ b/app/controllers/physical_ticket_controller.rb @@ -1,7 +1,7 @@ class PhysicalTicketController < ApplicationController before_action :authenticate_user! load_resource :conference, find_by: :short_title - load_and_authorize_resource + load_and_authorize_resource find_by: :token authorize_resource :conference_registrations, class: Registration def index diff --git a/app/models/physical_ticket.rb b/app/models/physical_ticket.rb index 6142c875..689d118a 100644 --- a/app/models/physical_ticket.rb +++ b/app/models/physical_ticket.rb @@ -4,4 +4,19 @@ class PhysicalTicket < ActiveRecord::Base has_one :conference, through: :ticket_purchase has_one :user, through: :ticket_purchase has_many :ticket_scannings + + before_create :set_token + + private + + def set_token + self.token = generate_token + end + + def generate_token + loop do + token = SecureRandom.hex(10) + break token unless PhysicalTicket.exists?(token: token) + end + end end diff --git a/app/views/admin/physical_ticket/index.html.haml b/app/views/admin/physical_ticket/index.html.haml index fe128932..96c5911f 100644 --- a/app/views/admin/physical_ticket/index.html.haml +++ b/app/views/admin/physical_ticket/index.html.haml @@ -32,12 +32,12 @@ .btn-group = link_to 'Show', conference_physical_ticket_path(@conference.short_title, - physical_ticket.id), + physical_ticket.token), class: 'btn btn-primary' = link_to 'Generate PDF', conference_physical_ticket_path(@conference.short_title, - physical_ticket.id, - format: :pdf), + physical_ticket.token, + format: :pdf), class: 'button btn btn-default btn-info' - else %h5 No Tickets sold! diff --git a/app/views/physical_ticket/index.html.haml b/app/views/physical_ticket/index.html.haml index b077400b..cb0710ad 100644 --- a/app/views/physical_ticket/index.html.haml +++ b/app/views/physical_ticket/index.html.haml @@ -24,11 +24,11 @@ .btn-group = link_to 'Show', conference_physical_ticket_path(@conference.short_title, - physical_ticket.id), + physical_ticket.token), class: 'btn btn-primary' = link_to 'Generate PDF', conference_physical_ticket_path(@conference.short_title, - physical_ticket.id, + physical_ticket.token, format: :pdf), class: 'button btn btn-default btn-info' - else diff --git a/app/views/physical_ticket/show.html.haml b/app/views/physical_ticket/show.html.haml index 26fa7853..067f0a9b 100644 --- a/app/views/physical_ticket/show.html.haml +++ b/app/views/physical_ticket/show.html.haml @@ -72,6 +72,6 @@ %p.text-left = link_to 'Generate PDF', conference_physical_ticket_path(@conference.short_title, - @physical_ticket.id, + @physical_ticket.token, format: :pdf), class: 'button btn btn-default btn-info' diff --git a/db/migrate/20170721001700_add_index_to_physical_tickets.rb b/db/migrate/20170721001700_add_index_to_physical_tickets.rb new file mode 100644 index 00000000..46a0b8c0 --- /dev/null +++ b/db/migrate/20170721001700_add_index_to_physical_tickets.rb @@ -0,0 +1,6 @@ +class AddIndexToPhysicalTickets < ActiveRecord::Migration + def change + add_column :physical_tickets, :token, :string + add_index :physical_tickets, :token, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 64ac0393..d49dfa03 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170711102511) do +ActiveRecord::Schema.define(version: 20170721001700) do create_table "ahoy_events", force: :cascade do |t| t.integer "visit_id" @@ -317,8 +317,11 @@ ActiveRecord::Schema.define(version: 20170711102511) do t.integer "ticket_purchase_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "token" end + add_index "physical_tickets", ["token"], name: "index_physical_tickets_on_token", unique: true + create_table "programs", force: :cascade do |t| t.integer "conference_id" t.integer "rating", default: 0 diff --git a/spec/controllers/physical_ticket_controller_spec.rb b/spec/controllers/physical_ticket_controller_spec.rb index 7a430479..863e27af 100644 --- a/spec/controllers/physical_ticket_controller_spec.rb +++ b/spec/controllers/physical_ticket_controller_spec.rb @@ -9,7 +9,7 @@ describe PhysicalTicketController do describe 'GET #show' do before :each do sign_in user - get :show, id: physical_ticket.id, conference_id: conference.short_title + get :show, id: physical_ticket.token, conference_id: conference.short_title end it 'assigns ticket_layout' do From 906f08baf867a11379061a70bb54cd516e6214ea Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Mon, 17 Jul 2017 21:22:53 +0530 Subject: [PATCH 125/237] Send mail on ticket confirmation. Added mailer method to send ticket confirmation email along with the attached pdf for ticket. --- app/mailers/mailbot.rb | 16 ++++++++++++++++ app/models/ticket_purchase.rb | 1 + .../ticket_confirmation_template.text.erb | 8 ++++++++ 3 files changed, 25 insertions(+) create mode 100644 app/views/mailbot/ticket_confirmation_template.text.erb diff --git a/app/mailers/mailbot.rb b/app/mailers/mailbot.rb index 3d70f18d..f5b7f375 100644 --- a/app/mailers/mailbot.rb +++ b/app/mailers/mailbot.rb @@ -8,6 +8,22 @@ class Mailbot < ActionMailer::Base conference.email_settings.registration_body)) end + def ticket_confirmation_mail(ticket_purchase) + @ticket_purchase = ticket_purchase + @conference = ticket_purchase.conference + @user = ticket_purchase.user + + PhysicalTicket.last(ticket_purchase.quantity).each do |physical_ticket| + pdf = TicketPdf.new(@conference, @user, physical_ticket, @conference.ticket_layout.to_sym, "ticket_for_#{@conference.short_title}_#{physical_ticket.id}") + attachments["ticket_for_#{@conference.short_title}_#{physical_ticket.id}"] = pdf.render + end + + mail(to: @user.email, + from: @conference.contact.email, + template_name: 'ticket_confirmation_template', + subject: "#{@conference.title} | Ticket Confirmation and PDF!") + end + def acceptance_mail(event) conference = event.program.conference diff --git a/app/models/ticket_purchase.rb b/app/models/ticket_purchase.rb index a19678a7..a2ed2747 100644 --- a/app/models/ticket_purchase.rb +++ b/app/models/ticket_purchase.rb @@ -69,6 +69,7 @@ class TicketPurchase < ActiveRecord::Base PhysicalTicket.transaction do quantity.times { physical_tickets.create } end + Mailbot.ticket_confirmation_mail(self).deliver_later end end diff --git a/app/views/mailbot/ticket_confirmation_template.text.erb b/app/views/mailbot/ticket_confirmation_template.text.erb new file mode 100644 index 00000000..08f5175a --- /dev/null +++ b/app/views/mailbot/ticket_confirmation_template.text.erb @@ -0,0 +1,8 @@ +Dear <%= @user.name %>, + +Thanks! You have successfully booked <%= @ticket_purchase.quantity %> <%= @ticket_purchase.ticket.title %> ticket(s) for the event <%= @conference.title %>. Your transaction id is <%= @ticket_purchase.id %>. + +Please, find the ticket(s) pdf attached. + +Best wishes, +<%= @conference.title %> Team From 80a95442795a833db09d4a7614b0c77aa3058cd4 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Fri, 14 Jul 2017 21:09:28 +0530 Subject: [PATCH 126/237] move admin/users to be accessed only by site admins --- app/models/admin_ability.rb | 1 - spec/features/cfp_ability_spec.rb | 6 ++++++ spec/features/info_desk_ability_spec.rb | 6 ++++++ spec/features/organizer_ability_spec.rb | 6 ++++++ spec/models/admin_ability_spec.rb | 4 ++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 4244d049..716aecb0 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -18,7 +18,6 @@ class AdminAbility end def common_abilities_for_roles(user) - can :manage, User, id: user.id can :manage, Registration, user_id: user.id can :index, Conference diff --git a/spec/features/cfp_ability_spec.rb b/spec/features/cfp_ability_spec.rb index 46db11c2..d40a54a4 100644 --- a/spec/features/cfp_ability_spec.rb +++ b/spec/features/cfp_ability_spec.rb @@ -269,6 +269,12 @@ feature 'Has correct abilities' do visit edit_admin_conference_resource_path(conference.short_title, conference.resources.first) expect(current_path).to eq(edit_admin_conference_resource_path(conference.short_title, conference.resources.first)) + visit admin_users_path + expect(current_path).to eq(root_path) + + visit admin_user_path(user_cfp) + expect(current_path).to eq(root_path) + visit admin_revision_history_path expect(current_path).to eq(root_path) end diff --git a/spec/features/info_desk_ability_spec.rb b/spec/features/info_desk_ability_spec.rb index 20aa586b..c005f9de 100644 --- a/spec/features/info_desk_ability_spec.rb +++ b/spec/features/info_desk_ability_spec.rb @@ -237,6 +237,12 @@ feature 'Has correct abilities' do visit admin_conference_program_tracks_path(conference.short_title) expect(current_path).to eq(root_path) + visit admin_users_path + expect(current_path).to eq(root_path) + + visit admin_user_path(user_info_desk) + expect(current_path).to eq(root_path) + visit admin_conference_emails_path(conference.short_title) expect(current_path).to eq(root_path) end diff --git a/spec/features/organizer_ability_spec.rb b/spec/features/organizer_ability_spec.rb index 06a2a836..3ed6ee39 100644 --- a/spec/features/organizer_ability_spec.rb +++ b/spec/features/organizer_ability_spec.rb @@ -266,6 +266,12 @@ feature 'Has correct abilities' do visit edit_admin_conference_resource_path(conference.short_title, conference.resources.first) expect(current_path).to eq(edit_admin_conference_resource_path(conference.short_title, conference.resources.first)) + visit admin_users_path + expect(current_path).to eq(root_path) + + visit admin_user_path(user_organizer) + expect(current_path).to eq(root_path) + visit admin_revision_history_path expect(current_path).to eq(admin_revision_history_path) end diff --git a/spec/models/admin_ability_spec.rb b/spec/models/admin_ability_spec.rb index 9baae4a9..5398b7d2 100644 --- a/spec/models/admin_ability_spec.rb +++ b/spec/models/admin_ability_spec.rb @@ -64,6 +64,10 @@ describe 'User with admin role' do it{ should_not be_able_to(:edit, Role.find_by(name: 'organization_admin', resource: other_organization)) } it{ should_not be_able_to(:show, Role.find_by(name: 'organization_admin', resource: other_organization)) } + it{ should_not be_able_to(:new, User.new) } + it{ should_not be_able_to(:create, User.new) } + it{ should_not be_able_to(:manage, User) } + %w[organizer cfp info_desk volunteers_coordinator].each do |role| it{ should_not be_able_to(:toggle_user, Role.find_by(name: role, resource: other_conference)) } it{ should_not be_able_to(:update, Role.find_by(name: role, resource: other_conference)) } From 50c66e2e0221b84aade66cb7aec5a5cb619b2d89 Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Fri, 4 Aug 2017 04:01:42 -0500 Subject: [PATCH 127/237] Explicitly add `.pdf` to make it a PDF file. Some SMTP providers would treat all files w/o suffix as `.txt`s. This patch would make it work in most cases. --- app/mailers/mailbot.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/mailers/mailbot.rb b/app/mailers/mailbot.rb index f5b7f375..837e2c1e 100644 --- a/app/mailers/mailbot.rb +++ b/app/mailers/mailbot.rb @@ -15,7 +15,7 @@ class Mailbot < ActionMailer::Base PhysicalTicket.last(ticket_purchase.quantity).each do |physical_ticket| pdf = TicketPdf.new(@conference, @user, physical_ticket, @conference.ticket_layout.to_sym, "ticket_for_#{@conference.short_title}_#{physical_ticket.id}") - attachments["ticket_for_#{@conference.short_title}_#{physical_ticket.id}"] = pdf.render + attachments["ticket_for_#{@conference.short_title}_#{physical_ticket.id}.pdf"] = pdf.render end mail(to: @user.email, From a4b82bc83060897b60d002e46433cd8feb18680f Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 24 May 2017 18:43:40 +0300 Subject: [PATCH 128/237] Update sass-rails to 5.0.6 --- Gemfile.lock | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8f7ef5d6..ae118542 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -473,11 +473,12 @@ GEM rubyzip (1.2.1) safe_yaml (1.0.4) sass (3.2.19) - sass-rails (4.0.4) - railties (>= 4.0.0, < 5.0) - sass (~> 3.2.2) - sprockets (~> 2.8, < 2.12) - sprockets-rails (~> 2.0) + sass-rails (5.0.6) + railties (>= 4.0.0, < 6) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) selectize-rails (0.12.4) shellany (0.0.1) shoulda-matchers (2.8.0) From da8b72343bce28269599ae6635af732b5b119037 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Tue, 18 Jul 2017 10:15:53 +0300 Subject: [PATCH 129/237] Update font-awesome-rails to 4.7.0.2 --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ae118542..17f96de1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -180,8 +180,8 @@ GEM fastimage (2.0.0) addressable (~> 2) ffi (1.9.18) - font-awesome-rails (4.1.0.0) - railties (>= 3.2, < 5.0) + font-awesome-rails (4.7.0.2) + railties (>= 3.2, < 5.2) formatador (0.2.5) formtastic (3.1.3) actionpack (>= 3.2.13) From d94fdb2a28520e96f03d0a5192a00ba7086d2880 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Tue, 18 Jul 2017 10:16:32 +0300 Subject: [PATCH 130/237] Update dotenv-rails to 2.2.1 --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 17f96de1..3e2deeb4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -162,10 +162,10 @@ GEM docile (1.1.5) domain_name (0.5.20160310) unf (>= 0.0.5, < 1.0.0) - dotenv (2.1.1) - dotenv-rails (2.1.1) - dotenv (= 2.1.1) - railties (>= 4.0, < 5.1) + dotenv (2.2.1) + dotenv-rails (2.2.1) + dotenv (= 2.2.1) + railties (>= 3.2, < 5.2) erubis (2.7.0) execjs (2.6.0) factory_girl (4.5.0) From f74f2d3f52f9fb3a8c68cd50aab07192bad74c1e Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 24 May 2017 18:53:16 +0300 Subject: [PATCH 131/237] Update responders to 2.4.0 --- Gemfile.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3e2deeb4..0b90d844 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -425,8 +425,9 @@ GEM redcarpet (3.2.3) referer-parser (0.2.1) request_store (1.1.0) - responders (2.1.1) - railties (>= 4.2.0, < 5.1) + responders (2.4.0) + actionpack (>= 4.2.0, < 5.3) + railties (>= 4.2.0, < 5.3) rest-client (1.8.0) http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 3.0) From d9649a4446bce677eebc753636bb00bd66069063 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 24 May 2017 19:36:42 +0300 Subject: [PATCH 132/237] Update jquery-rails to 4.3.1 --- Gemfile.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 0b90d844..d8c8c850 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -235,8 +235,9 @@ GEM jquery-datatables-rails (2.2.3) jquery-rails sass-rails - jquery-rails (3.1.4) - railties (>= 3.0, < 5.0) + jquery-rails (4.3.1) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) thor (>= 0.14, < 2.0) jquery-ui-rails (4.2.1) railties (>= 3.2.16) From 7e2bb8043f2612a16ec49e20defdb57a405f2c90 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 24 May 2017 19:49:48 +0300 Subject: [PATCH 133/237] Update coffee-rails to 4.2.2 --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index d8c8c850..216b7dc0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -117,13 +117,13 @@ GEM rest-client cocoon (1.2.6) coderay (1.1.1) - coffee-rails (4.1.1) + coffee-rails (4.2.2) coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.1.x) + railties (>= 4.0.0) coffee-script (2.4.1) coffee-script-source execjs - coffee-script-source (1.10.0) + coffee-script-source (1.12.2) countable-rails (0.0.1) railties (>= 3.1) countries (1.2.5) From 57f450e857f19d36a86ee61c38aa33165d06c4cb Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 24 May 2017 20:26:50 +0300 Subject: [PATCH 134/237] Update delayed_job_active_record to 4.1.2 --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 216b7dc0..8246c724 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -145,10 +145,10 @@ GEM dante (0.2.0) database_cleaner (1.3.0) debug_inspector (0.0.2) - delayed_job (4.1.1) - activesupport (>= 3.0, < 5.0) - delayed_job_active_record (4.1.0) - activerecord (>= 3.0, < 5) + delayed_job (4.1.3) + activesupport (>= 3.0, < 5.2) + delayed_job_active_record (4.1.2) + activerecord (>= 3.0, < 5.2) delayed_job (>= 3.0, < 5) devise (4.2.0) bcrypt (~> 3.0) From 4e1d45382cb27affaacf38920cd6de60fbb7c709 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 24 May 2017 20:35:38 +0300 Subject: [PATCH 135/237] Update awesome_nested_set to 3.1.3 --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 1b0a3c1d..08170e30 100644 --- a/Gemfile +++ b/Gemfile @@ -57,7 +57,7 @@ gem 'unobtrusive_flash', '>=3' gem 'transitions', :require => %w( transitions active_record/transitions ) # for comments -gem 'awesome_nested_set', '~> 3.0.0.rc.5' +gem 'awesome_nested_set', '~> 3.1.3' gem 'acts_as_commentable_with_threading' # as templating language diff --git a/Gemfile.lock b/Gemfile.lock index 8246c724..85e7438f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -72,8 +72,8 @@ GEM autoprefixer-rails (5.1.9) execjs json - awesome_nested_set (3.0.0.rc.5) - activerecord (>= 4.0.0, < 5) + awesome_nested_set (3.1.3) + activerecord (>= 4.0.0, < 5.2) aws_cf_signer (0.1.3) axlsx_rails (0.2.0) axlsx (>= 2.0.1) @@ -569,7 +569,7 @@ DEPENDENCIES acts_as_list ahoy_matey autoprefixer-rails - awesome_nested_set (~> 3.0.0.rc.5) + awesome_nested_set (~> 3.1.3) axlsx! axlsx_rails bootstrap-sass (~> 3.3.4.1) From 27996531248eadeb3437fc34d30a817db5f21963 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 24 May 2017 21:05:24 +0300 Subject: [PATCH 136/237] Update omniauth to 1.6.1 --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 85e7438f..1288d067 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -219,7 +219,7 @@ GEM rubocop (>= 0.47.0) sysexits (~> 1.1) hashdiff (0.3.4) - hashie (2.1.1) + hashie (3.5.5) hike (1.2.3) hoptoad_notifier (2.4.11) activesupport @@ -302,9 +302,9 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (~> 1.2) - omniauth (1.2.1) - hashie (>= 1.2, < 3) - rack (~> 1.0) + omniauth (1.6.1) + hashie (>= 3.4.6, < 3.6.0) + rack (>= 1.6.2, < 3) omniauth-facebook (1.6.0) omniauth-oauth2 (~> 1.1) omniauth-github (1.1.2) From 2824336ead6f6ed5ea938f3410168df63ec15433 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 24 May 2017 21:49:53 +0300 Subject: [PATCH 137/237] Update sprockets to 3.7.1 --- Gemfile.lock | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1288d067..ecc7ec98 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -124,6 +124,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) + concurrent-ruby (1.0.5) countable-rails (0.0.1) railties (>= 3.1) countries (1.2.5) @@ -220,7 +221,6 @@ GEM sysexits (~> 1.1) hashdiff (0.3.4) hashie (3.5.5) - hike (1.2.3) hoptoad_notifier (2.4.11) activesupport builder @@ -497,11 +497,9 @@ GEM spring (1.6.3) spring-commands-rspec (1.0.4) spring (>= 0.9.1) - sprockets (2.11.3) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) + sprockets (3.7.1) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) sprockets-rails (2.3.3) actionpack (>= 3.0) activesupport (>= 3.0) From cb8010bafe3bb914c0ca72ea4f49879a486c1fe9 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 24 May 2017 22:03:39 +0300 Subject: [PATCH 138/237] Update omniauth-oauth2 to 1.4.0 --- Gemfile.lock | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ecc7ec98..8a1c97f7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -296,12 +296,12 @@ GEM notiffany (0.1.1) nenv (~> 0.1) shellany (~> 0.0) - oauth2 (0.9.4) - faraday (>= 0.8, < 0.10) + oauth2 (1.3.1) + faraday (>= 0.8, < 0.12) jwt (~> 1.0) multi_json (~> 1.3) multi_xml (~> 0.5) - rack (~> 1.2) + rack (>= 1.2, < 3) omniauth (1.6.1) hashie (>= 3.4.6, < 3.6.0) rack (>= 1.6.2, < 3) @@ -313,10 +313,8 @@ GEM omniauth-google-oauth2 (0.2.4) omniauth (~> 1.0) omniauth-oauth2 (~> 1.1) - omniauth-oauth2 (1.1.2) - faraday (>= 0.8, < 0.10) - multi_json (~> 1.3) - oauth2 (~> 0.9.3) + omniauth-oauth2 (1.4.0) + oauth2 (~> 1.0) omniauth (~> 1.2) omniauth-openid (1.0.1) omniauth (~> 1.0) From 9b7562fe2e394a47bc4c91c3666fbe09556cba7b Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Sun, 4 Jun 2017 19:50:48 +0300 Subject: [PATCH 139/237] Update autoprefixer-rails to 7.1.1 --- Gemfile.lock | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8a1c97f7..faaa8246 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -69,9 +69,8 @@ GEM uuidtools arel (6.0.4) ast (2.3.0) - autoprefixer-rails (5.1.9) + autoprefixer-rails (7.1.1) execjs - json awesome_nested_set (3.1.3) activerecord (>= 4.0.0, < 5.2) aws_cf_signer (0.1.3) From 033dbe4c40fd9c428b0167e84668c11e127de9e7 Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Fri, 4 Aug 2017 01:01:36 -0500 Subject: [PATCH 140/237] Fix the dropdown to get enough bottom padding. --- app/assets/stylesheets/osem-navbar.css.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/osem-navbar.css.scss b/app/assets/stylesheets/osem-navbar.css.scss index ef05c0a9..bfaac9ac 100644 --- a/app/assets/stylesheets/osem-navbar.css.scss +++ b/app/assets/stylesheets/osem-navbar.css.scss @@ -29,7 +29,7 @@ } } .dropdown-menu { - padding: 17px 17px 0px 17px; + padding: 17px; min-width: 225px; } } From 32c5af2a17f08162e113c8d32298b71b9839a0e9 Mon Sep 17 00:00:00 2001 From: nasia Date: Thu, 20 Jul 2017 14:20:46 +0300 Subject: [PATCH 141/237] Add booths to non admin --- .haml-lint_todo.yml | 6 +- .rubocop_todo.yml | 2 + app/controllers/admin/booths_controller.rb | 22 ++-- app/controllers/booths_controller.rb | 97 +++++++++++++++ app/helpers/format_helper.rb | 13 +++ app/models/ability.rb | 6 + app/models/booth.rb | 10 +- app/views/admin/booths/_form.html.haml | 33 ------ app/views/admin/booths/edit.html.haml | 2 +- app/views/admin/booths/index.html.haml | 11 +- app/views/admin/booths/new.html.haml | 2 +- app/views/admin/booths/show.html.haml | 3 +- app/views/booths/_form.html.haml | 30 +++++ app/views/booths/edit.html.haml | 6 + app/views/booths/index.html.haml | 51 ++++++++ app/views/booths/new.html.haml | 4 + app/views/booths/show.html.haml | 60 ++++++++++ config/routes.rb | 8 +- .../admin/booths_controller_spec.rb | 18 --- spec/controllers/booths_controller_spec.rb | 110 ++++++++++++++++++ spec/factories/booths.rb | 1 + spec/models/booth_spec.rb | 17 +-- 22 files changed, 426 insertions(+), 86 deletions(-) create mode 100644 app/controllers/booths_controller.rb delete mode 100644 app/views/admin/booths/_form.html.haml create mode 100644 app/views/booths/_form.html.haml create mode 100644 app/views/booths/edit.html.haml create mode 100644 app/views/booths/index.html.haml create mode 100644 app/views/booths/new.html.haml create mode 100644 app/views/booths/show.html.haml create mode 100644 spec/controllers/booths_controller_spec.rb diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index b42ccb06..52d5f5ca 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -11,7 +11,6 @@ linters: # Offense count: 945 LineLength: exclude: - - "app/views/admin/booths/_form.html.haml" - "app/views/admin/booths/index.html.haml" - "app/views/admin/booths/show.html.haml" - "app/views/admin/campaigns/_form.html.haml" @@ -109,6 +108,9 @@ linters: - "app/views/admin/versions/_object_desc_and_link.html.haml" - "app/views/admin/versions/index.html.haml" - "app/views/admin/volunteers/index.html.haml" + - "app/views/booths/_form.html.haml" + - "app/views/booths/index.html.haml" + - "app/views/booths/show.html.haml" - "app/views/commercials/edit.html.haml" - "app/views/commercials/new.html.haml" - "app/views/conference_registrations/_form.html.haml" @@ -369,6 +371,7 @@ linters: - "app/views/admin/tracks/show.html.haml" - "app/views/admin/venues/show.html.haml" - "app/views/admin/versions/index.html.haml" + - "app/views/booths/index.html.haml" - "app/views/conference_registrations/_form.html.haml" - "app/views/conference_registrations/_ticket.html.haml" - "app/views/conference_registrations/show.html.haml" @@ -397,6 +400,7 @@ linters: - "app/views/admin/schedules/_day_tab.html.haml" - "app/views/admin/schedules/_event.html.haml" - "app/views/admin/versions/_object_desc_and_link.html.haml" + - "app/views/booths/index.html.haml" - "app/views/schedules/_carousel.html.haml" # Offense count: 29 diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 7a9ab03c..8d752446 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -333,6 +333,8 @@ Metrics/MethodLength: # Configuration parameters: CountComments. Metrics/ModuleLength: Max: 159 + Exclude: + - 'app/helpers/format_helper.rb' # Offense count: 15 Metrics/PerceivedComplexity: diff --git a/app/controllers/admin/booths_controller.rb b/app/controllers/admin/booths_controller.rb index f5096c34..e5b55552 100644 --- a/app/controllers/admin/booths_controller.rb +++ b/app/controllers/admin/booths_controller.rb @@ -7,9 +7,13 @@ module Admin def show; end - def new; end + def new + @url = admin_conference_booths_path(@conference.short_title) + end def create + @url = admin_conference_booths_path(@conference.short_title) + @booth = @conference.booths.new(booth_params) @booth.submitter = current_user @@ -23,9 +27,13 @@ module Admin end end - def edit; end + def edit + @url = admin_conference_booth_path(@conference.short_title, @booth.id) + end def update + @url = admin_conference_booth_path(@conference.short_title, @booth.id) + @booth.update_attributes(booth_params) if @booth.save @@ -38,16 +46,6 @@ module Admin end end - def destroy - if @booth.destroy - redirect_to admin_conference_booths_path, - notice: 'Booth successfully destroyed.' - else - redirect_to admin_conference_booths_path, - error: "Booth couldn't be deleted. #{@booth.errors.full_messages.join('. ')}." - end - end - def accept update_state(:accept, 'Booth accepted!') end diff --git a/app/controllers/booths_controller.rb b/app/controllers/booths_controller.rb new file mode 100644 index 00000000..99fde3bc --- /dev/null +++ b/app/controllers/booths_controller.rb @@ -0,0 +1,97 @@ +class BoothsController < ApplicationController + before_action :authenticate_user! + load_resource :conference, find_by: :short_title + load_and_authorize_resource through: :conference + skip_authorize_resource only: [:withdraw, :confirm, :restart] + + def index + @booths = current_user.booths.where(conference_id: @conference.id).uniq + end + + def show; end + + def new + @url = conference_booths_path(@conference.short_title) + end + + def create + @url = conference_booths_path(@conference.short_title) + + @booth.submitter = current_user + + if @booth.save + redirect_to conference_booths_path, + notice: 'Booth successfully created.' + else + flash[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}." + render :new + end + end + + def edit + @url = conference_booth_path(@conference.short_title, @booth.id) + end + + def update + @url = conference_booth_path(@conference.short_title, @booth.id) + @booth.update_attributes(booth_params) + + if @booth.save + redirect_to conference_booths_path, + notice: 'Booth successfully updated!' + else + flash[:error] = "Booth could not be updated. #{@booth.errors.full_messages.to_sentence}." + end + end + + def destroy; end + + def withdraw + authorize! :update, @booth + @url = conference_booth_path(@conference.short_title, @booth.id) + + @booth.withdraw! + + if @booth.save + redirect_to conference_booths_path, + notice: 'Booth successfully withdrawn' + else + flash[:error] = "Booth could not be withdrawn. #{@booth.errors.full_messages.to_sentence}." + end + end + + def confirm + authorize! :update, @booth + @url = conference_booth_path(@conference.short_title, @booth.id) + + @booth.confirm! + + if @booth.save + redirect_to conference_booths_path, + notice: 'Booth successfully confirmed' + else + flash[:error] = "Booth could not be confirmed. #{@booth.errors.full_messages.to_sentence}." + end + end + + def restart + authorize! :update, @booth + @url = conference_booth_path(@conference.short_title, @booth.id) + + @booth.restart! + + if @booth.save + redirect_to conference_booths_path, + notice: 'Booth successfully re-submitted' + else + flash[:error] = "Booth could not be re-submitted. #{@booth.errors.full_messages.to_sentence}." + end + end + + private + + def booth_params + params.require(:booth).permit(:title, :description, :reasoning, :state, :picture, :conference_id, + :created_at, :updated_at, :submitter_relationship, :website_url, responsible_ids: []) + end +end diff --git a/app/helpers/format_helper.rb b/app/helpers/format_helper.rb index 334c70bf..65578ba6 100644 --- a/app/helpers/format_helper.rb +++ b/app/helpers/format_helper.rb @@ -15,6 +15,19 @@ module FormatHelper end end + def booth_status_icon(booth) + case booth.state + when 'new', 'to_reject', 'to_accept' + 'fa-eye' + when 'accepted' + 'fa-check text-muted' + when 'confirmed' + 'fa-check text-success' + when 'rejected', 'withdrawn', 'canceled' + 'fa-ban' + end + end + def event_progress_color(progress) progress = progress.to_i if progress == 100 diff --git a/app/models/ability.rb b/app/models/ability.rb index afc51a68..0ebabfdc 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -75,6 +75,12 @@ class Ability can [:new, :create], Payment, user_id: user.id can [:index, :show], PhysicalTicket, user: user + can [:new, :create], Booth + + can [:edit, :update, :index, :show], Booth do |booth| + booth.users.include?(user) + end + can [:create, :destroy], Subscription, user_id: user.id can [:new, :create], Event do |event| diff --git a/app/models/booth.rb b/app/models/booth.rb index 5c20550a..853bca9e 100644 --- a/app/models/booth.rb +++ b/app/models/booth.rb @@ -35,12 +35,16 @@ class Booth < ActiveRecord::Base state :to_reject state :rejected state :canceled + state :confirmed event :restart do - transitions to: :new, from: [:withdrawn, :to_accept, :to_reject, :canceled] + transitions to: :new, from: [:withdrawn, :rejected, :canceled] end event :withdraw do - transitions to: :withdrawn, from: [:new, :to_accept, :accepted, :to_reject, :rejected] + transitions to: :withdrawn, from: [:new, :to_accept, :accepted, :to_reject, :rejected, :confirmed] + end + event :confirm do + transitions to: :confirmed, from: [:accepted] end event :to_accept do transitions to: :to_accept, from: [:new, :to_reject] @@ -55,7 +59,7 @@ class Booth < ActiveRecord::Base transitions to: :rejected, from: [:new, :to_reject] end event :cancel do - transitions to: :canceled, from: [:accepted, :rejected, :to_accept, :to_reject] + transitions to: :canceled, from: [:accepted, :rejected, :to_accept, :to_reject, :confirmed] end end diff --git a/app/views/admin/booths/_form.html.haml b/app/views/admin/booths/_form.html.haml deleted file mode 100644 index f70079fa..00000000 --- a/app/views/admin/booths/_form.html.haml +++ /dev/null @@ -1,33 +0,0 @@ -.row - .col-md-12 - .page-header - %title Request a Booth -.row - .col-md-8 - = semantic_form_for(@booth, url: @booth.new_record? ? admin_conference_booths_path(@conference.short_title) : admin_conference_booth_path(@conference.short_title, @booth.id), html: { multipart: true }) do |f| - = f.input :title, as: :string, autofocus: true, required: true - = f.input :description, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, - hint: 'This field becomes public upon request acceptance' - = f.input :reasoning, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, - label: 'How it fits the conference' - = f.input :submitter_relationship, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, - label: 'Submitter\'s relation', - hint: 'e.g. employee, comunity manager, etc' - = f.input :website_url - = responsibles_selector_input f - = image_tag f.object.picture.thumb.url if f.object.picture? - = f.input :picture - - %p.text-right - - if @booth.new_record? - = f.submit 'Create Booth Request', class: 'btn btn-success' - - else - = f.submit 'Update Booth Request', class: 'btn btn-success' - -:javascript - $(document).ready(function() { - $('#booth_responsible_ids').selectize({ - plugins: ['remove_button'], - minItems: 2 - } ) - }); diff --git a/app/views/admin/booths/edit.html.haml b/app/views/admin/booths/edit.html.haml index 9f9a5a61..0cac17e7 100644 --- a/app/views/admin/booths/edit.html.haml +++ b/app/views/admin/booths/edit.html.haml @@ -2,4 +2,4 @@ Editing = @booth.title -= render 'form' += render 'booths/form' diff --git a/app/views/admin/booths/index.html.haml b/app/views/admin/booths/index.html.haml index 15833bd7..27f505ad 100644 --- a/app/views/admin/booths/index.html.haml +++ b/app/views/admin/booths/index.html.haml @@ -41,8 +41,9 @@ = link_to booth.submitter.name, admin_user_path(booth.submitter) if booth.submitter %td .responsibles - - booth.responsibles.each do |responsible| + - booth.responsibles.each_with_index do |responsible, i| = link_to responsible.name, admin_user_path(responsible) + = ", " unless i == booth.responsibles.length - 1 %td .btn-group %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } @@ -51,9 +52,5 @@ %ul.dropdown-menu{ role: 'menu' } = render 'change_state_dropdown', booth: booth %td - .btn-group{ role: "group" } - = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id), - class: 'btn btn-primary' - = link_to 'Delete', admin_conference_booth_path(@conference.short_title, booth.id), - method: :delete, class: 'btn btn-danger', - data: {confirm: "Do you really want to delete this booth request?"} + = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id), + class: 'btn btn-primary' diff --git a/app/views/admin/booths/new.html.haml b/app/views/admin/booths/new.html.haml index db1c4736..99ec9b20 100644 --- a/app/views/admin/booths/new.html.haml +++ b/app/views/admin/booths/new.html.haml @@ -1,3 +1,3 @@ %h1 New booth -= render 'form' += render 'booths/form' diff --git a/app/views/admin/booths/show.html.haml b/app/views/admin/booths/show.html.haml index 8c692bc4..6ed823e5 100644 --- a/app/views/admin/booths/show.html.haml +++ b/app/views/admin/booths/show.html.haml @@ -39,12 +39,13 @@ %td.col-md-2 %b Responsibles %td - - @booth.responsibles.each do |responsibles| + - @booth.responsibles.each_with_index do |responsibles, i| .responsibles = link_to responsibles.name, admin_user_path(responsibles) ( = responsibles.email ) + = " , " unless i == @booth.responsibles.length - 1 %tr %td.col-md-2 %b Submitted on diff --git a/app/views/booths/_form.html.haml b/app/views/booths/_form.html.haml new file mode 100644 index 00000000..55a51432 --- /dev/null +++ b/app/views/booths/_form.html.haml @@ -0,0 +1,30 @@ +.container + .row + .col-md-8 + = semantic_form_for(@booth, url: @url, html: { multipart: true }) do |f| + = f.input :title, as: :string, autofocus: true, required: true + = f.input :description, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, + hint: 'This field becomes public upon request acceptance' + = f.input :reasoning, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, + label: 'How it fits the conference' + = f.input :submitter_relationship, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, + label: 'Submitter\'s relation', + hint: 'e.g. employee, comunity manager, etc' + = f.input :website_url + = responsibles_selector_input f + = image_tag f.object.picture.thumb.url if f.object.picture? + = f.input :picture + + %p.text-right + - if @booth.new_record? + = f.submit 'Create Booth Request', class: 'btn btn-success' + - else + = f.submit 'Update Booth Request', class: 'btn btn-success' + + :javascript + $(document).ready(function() { + $('#booth_responsible_ids').selectize({ + plugins: ['remove_button'], + minItems: 2 + } ) + }); diff --git a/app/views/booths/edit.html.haml b/app/views/booths/edit.html.haml new file mode 100644 index 00000000..9f60196d --- /dev/null +++ b/app/views/booths/edit.html.haml @@ -0,0 +1,6 @@ +.container + %h1 + Editing + = @booth.title + + = render 'form' diff --git a/app/views/booths/index.html.haml b/app/views/booths/index.html.haml new file mode 100644 index 00000000..d6c392dd --- /dev/null +++ b/app/views/booths/index.html.haml @@ -0,0 +1,51 @@ +.container + .row + .col-md-12.page-header + %h1 + Your booth requests for + = @conference.title + .row + .col-md-12 + .margin-booth-table + %table.table.table-striped.table-hover + %thead + %th + %b State + %th + %b Logo + %th + %b Title + %th + %b Actions + - @booths.each do |booth| + %tr + %td{ style: "padding:20px 8px 20px 8px;" } + - if (booth.state == 'to_accept' || booth.state == 'to_reject') + - show_state = 'new' + - else + - show_state = booth.state + %span{ title: show_state, class: "fa #{booth_status_icon(booth)}" } + %td + - if booth.logo_link + = image_tag(booth.picture.thumb.url, width: '20%') + %td + = link_to booth.title, conference_booth_path(@conference.short_title, booth) + %td + -if can? :edit, booth + = link_to 'Edit', edit_conference_booth_path(@conference.short_title, booth.id), + class: 'btn btn-default' + - if booth.transition_possible? :withdraw + = link_to 'Withdraw', + withdraw_conference_booth_path(@conference.short_title, booth), + method: :patch, class: 'btn btn-mini btn-warning', id: "withdraw_booth_#{booth.id}", + data: { confirm: 'Are you sure you really want to withdraw this request?' } + - if booth.transition_possible? :confirm + = link_to 'Confirm', + confirm_conference_booth_path(@conference.short_title, booth), + method: :patch, class: 'btn btn-mini btn-success', id: "confirm_booth_#{booth.id}" + - if booth.transition_possible? :restart + = link_to 'Re-submit', + restart_conference_booth_path(@conference.short_title, booth), + method: :patch, class: 'btn btn-mini btn-success', id: "restart_booth_#{booth.id}" + .pull-right + = link_to 'Add Booth', new_conference_booth_path(@conference.short_title), class: 'button btn btn-primary' diff --git a/app/views/booths/new.html.haml b/app/views/booths/new.html.haml new file mode 100644 index 00000000..169efd17 --- /dev/null +++ b/app/views/booths/new.html.haml @@ -0,0 +1,4 @@ +.container + %h1 Request a booth + + = render 'form' diff --git a/app/views/booths/show.html.haml b/app/views/booths/show.html.haml new file mode 100644 index 00000000..6b12229d --- /dev/null +++ b/app/views/booths/show.html.haml @@ -0,0 +1,60 @@ +.container + .row + .col-md-12 + %h3 + - if @booth.logo_link + = image_tag(@booth.picture.thumb.url, size: '20%', alt: '') + = @booth.title + .btn-group.pull-right + = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, @booth), class: 'btn btn-mini btn-primary' + + .row + .col-md-12 + %table.table + %tr + %td.col-md-2 + %b Description + %td + = markdown(@booth.description) + %tr + %td.col-md-2 + %b Reasoning + %td + = markdown(@booth.reasoning) + %tr + %td.col-md-2 + %b Website + %td + - if @booth.website_url.present? + = link_to @booth.website_url, @booth.website_url + %tr + %td.col-md-2 + %b Submitter + %td + = link_to @booth.submitter.name, user_path(@booth.submitter) + %tr + %td.col-md-2 + %b Submitter's relationship + %td + = @booth.submitter_relationship + %tr + %td.col-md-2 + %b Responsibles + %td + - @booth.responsibles.each_with_index do |responsibles, i| + .responsibles + = link_to responsibles.name, user_path(responsibles) + ( + = responsibles.email + ) + = ", " unless i == @booth.responsibles.length - 1 + %tr + %td.col-md-2 + %b Submitted on + %td + = @booth.created_at + %tr + %td.col-md-2 + %b Last updated on + %td + = @booth.updated_at diff --git a/config/routes.rb b/config/routes.rb index 5a17d314..be507d35 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -41,7 +41,6 @@ Osem::Application.routes.draw do member do patch :accept patch :restart - patch :withdrawn patch :to_accept patch :reject patch :reset @@ -131,6 +130,13 @@ Osem::Application.routes.draw do end resources :organizations, only: [:index] resources :conferences, only: [:index, :show] do + resources :booths do + member do + patch :withdraw + patch :confirm + patch :restart + end + end resource :program, only: [] do resources :proposals, except: :destroy do get 'commercials/render_commercial' => 'commercials#render_commercial' diff --git a/spec/controllers/admin/booths_controller_spec.rb b/spec/controllers/admin/booths_controller_spec.rb index 569862d1..37004531 100644 --- a/spec/controllers/admin/booths_controller_spec.rb +++ b/spec/controllers/admin/booths_controller_spec.rb @@ -126,23 +126,5 @@ describe Admin::BoothsController do end end end - - describe 'DELETE #destroy' do - context 'deletes successfully' do - before { delete :destroy, id: booth.id, conference_id: conference.short_title } - - it 'booth deleted' do - expect(Booth.count).to eq(0) - end - - it 'redirects to admin booth index path' do - expect(response).to redirect_to(admin_conference_booths_path) - end - - it 'show success message' do - expect(flash[:notice]).to match('Booth successfully destroyed.') - end - end - end end end diff --git a/spec/controllers/booths_controller_spec.rb b/spec/controllers/booths_controller_spec.rb new file mode 100644 index 00000000..243bc6e2 --- /dev/null +++ b/spec/controllers/booths_controller_spec.rb @@ -0,0 +1,110 @@ +require 'spec_helper' + +describe BoothsController do + + let(:user) { create(:user) } + let(:conference) { create(:conference) } + let(:booth) { create(:booth, title: 'Title', conference: conference) } + + context 'user is signed in with submitter role' do + before :each do + sign_in booth.submitter + end + + describe 'GET index' do + before { get :index, conference_id: conference.short_title } + + it 'assigns attributes for booths' do + expect(assigns(:booths)).to eq([booth]) + end + + it 'renders index template' do + expect(response).to render_template('index') + end + end + + describe 'GET #new' do + before { get :new, conference_id: conference.short_title } + + it 'assigns attributes for booths' do + expect(assigns(:booth)).to be_a_new(Booth) + end + + it 'renders new template' do + expect(response).to render_template('new') + end + end + + describe 'POST #create' do + context 'successfully created' do + before { post :create, booth: attributes_for(:booth), conference_id: conference.short_title } + + it 'creates a new booth' do + expect(Booth.count).to_not eq(0) + end + + it 'redirects to booth index' do + expect(response).to redirect_to(conference_booths_path) + end + + it 'has responsibles' do + expect(booth.responsibles.count).to_not eq(0) + end + + it 'shows success message' do + expect(flash[:notice]).to match('Booth successfully created.') + end + end + + context 'create action fails' do + before { post :create, booth: attributes_for(:booth, title: ''), conference_id: conference.short_title } + + it 'does not create any record' do + expected = expect do + post :create, booth: attributes_for(:booth, title: ''), conference_id: conference.short_title + end + expected.to_not change(Booth, :count) + end + + it 'redirects to new' do + expect(response).to render_template('new') + end + + it 'shows flash message' do + expect(flash[:error]).to eq("Creating booth failed. Title can't be blank.") + end + end + end + + describe 'GET #edit' do + before { get :edit, id: booth.id, conference_id: conference.short_title } + + it 'renders edit template' do + expect(response).to render_template('edit') + end + + it 'assigns booth variable' do + expect(assigns(:booth)).to eq booth + end + end + + describe 'PATCH #update' do + context 'updates suchessfully' do + before { patch :update, id: booth.id, booth: attributes_for(:booth, title: 'different'), conference_id: conference.short_title } + + it 'redirects to booth index path' do + expect(response).to redirect_to conference_booths_path + end + + it 'shows success message' do + expect(flash[:notice]).to match 'Booth successfully updated!' + end + + it 'updates booth' do + booth.reload + expect(booth.title).to eq('different') + end + end + end + end +end diff --git a/spec/factories/booths.rb b/spec/factories/booths.rb index b1cd1956..1ac3ff87 100644 --- a/spec/factories/booths.rb +++ b/spec/factories/booths.rb @@ -8,6 +8,7 @@ FactoryGirl.define do conference + submitter { create(:user) } responsible_ids { [create(:user).id] } end end diff --git a/spec/models/booth_spec.rb b/spec/models/booth_spec.rb index 5e86a393..287653ac 100644 --- a/spec/models/booth_spec.rb +++ b/spec/models/booth_spec.rb @@ -33,16 +33,17 @@ describe 'Booth' do end end - states = [:new, :withdrawn, :to_accept, :accepted, :to_reject, :rejected, :canceled] + states = [:new, :withdrawn, :to_accept, :accepted, :to_reject, :rejected, :canceled, :confirmed] transitions = [:restart, :withdraw, :accept, :reject, :to_accept, :to_reject, :cancel] - states_transitions = { new: { restart: false, withdraw: true, accept: true, to_accept: true, to_reject: true, reject: true, cancel: false }, - withdrawn: { restart: true, withdraw: false, accept: false, to_accept: false, to_reject: false, reject: false, cancel: false }, - to_accept: { restart: true, withdraw: true, accept: true, to_accept: false, to_reject: true, reject: false, cancel: true }, - to_reject: { restart: true, withdraw: true, accept: false, to_accept: true, to_reject: false, reject: true, cancel: true }, - accepted: { restart: false, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true }, - rejected: { restart: false, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true }, - canceled: { restart: true, withdraw: false, accept: false, to_accept: false, to_reject: false, reject: false, cancel: false } } + states_transitions = { new: { restart: false, withdraw: true, accept: true, to_accept: true, to_reject: true, reject: true, cancel: false, confirm: false }, + withdrawn: { restart: true, withdraw: false, accept: false, to_accept: false, to_reject: false, reject: false, cancel: false, confirm: false }, + to_accept: { restart: false, withdraw: true, accept: true, to_accept: false, to_reject: true, reject: false, cancel: true, confirm: false }, + to_reject: { restart: false, withdraw: true, accept: false, to_accept: true, to_reject: false, reject: true, cancel: true, confirm: false }, + accepted: { restart: false, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true, confirm: true }, + rejected: { restart: true, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true, confirm: false }, + canceled: { restart: true, withdraw: false, accept: false, to_accept: false, to_reject: false, reject: false, cancel: false, confirm: false }, + confirmed: { restart: false, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true, confirm: false } } states.each do |state| transitions.each do |transition| From 540c982771ea96c4f17e563179139e976519c3ea Mon Sep 17 00:00:00 2001 From: shlok007 Date: Thu, 13 Jul 2017 04:02:13 +0530 Subject: [PATCH 142/237] mention organization in dashboard, splashpage and admin/conference#edit --- app/views/admin/conferences/edit.html.haml | 1 + app/views/admin/conferences/show.html.haml | 2 +- app/views/conferences/show.html.haml | 3 +++ spec/features/conference_spec.rb | 9 +++++++++ spec/features/splashpage_spec.rb | 11 +++++++++++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/views/admin/conferences/edit.html.haml b/app/views/admin/conferences/edit.html.haml index 2d5df126..49d65235 100644 --- a/app/views/admin/conferences/edit.html.haml +++ b/app/views/admin/conferences/edit.html.haml @@ -9,6 +9,7 @@ = semantic_form_for(@conference, url: admin_conference_path(@conference.short_title), html: {multipart: true}) do |f| = f.input :title, hint: "The full title of the conference, e.g. 'openSUSE Conference 2014'" = f.input :short_title, hint: "A short title, e.g. 'oSC14', to be used in URLs" + = f.input :organization, hint: 'The organization in which this conference belongs', input_html: { disabled: true } = f.input :description, hint: markdown_hint('A description of the conference.'), input_html: { rows: 5, data: { provide: 'markdown-editable' } } = f.input :color, hint: 'The color will be used eg for the dashboard.', input_html: {size: 6, type: 'color'} = f.label 'Conference Logo' diff --git a/app/views/admin/conferences/show.html.haml b/app/views/admin/conferences/show.html.haml index cddae4c2..f270867b 100644 --- a/app/views/admin/conferences/show.html.haml +++ b/app/views/admin/conferences/show.html.haml @@ -1,6 +1,6 @@ %h1 %span.fa.fa-tachometer - Dashboard for #{@conference.title} + Dashboard for #{@conference.title} ( by #{@conference.organization.name} ) %hr .row .col-sm-4.col-xs-4 diff --git a/app/views/conferences/show.html.haml b/app/views/conferences/show.html.haml index fb488e22..b133c26a 100644 --- a/app/views/conferences/show.html.haml +++ b/app/views/conferences/show.html.haml @@ -22,6 +22,9 @@ .col-md-8 %h1 = @conference.title + %h3 + %i + = "( by #{@conference.organization.name} )" %p.lead - if @conference.venue = "#{@conference.venue.city} / #{@conference.venue.country_name}" diff --git a/spec/features/conference_spec.rb b/spec/features/conference_spec.rb index d17ce5fc..5b9f9c54 100644 --- a/spec/features/conference_spec.rb +++ b/spec/features/conference_spec.rb @@ -71,6 +71,15 @@ feature Conference do end describe 'admin' do + let!(:conference) { create(:conference) } + + scenario 'has organization name in edit form', feature: true, js: true do + sign_in user + visit edit_admin_conference_path(conference.short_title) + org_id = find('#conference_organization_id').value + expect(Organization.find(org_id)).to eq conference.organization + end + it_behaves_like 'add and update conference' end end diff --git a/spec/features/splashpage_spec.rb b/spec/features/splashpage_spec.rb index e913d023..ee9b63d5 100644 --- a/spec/features/splashpage_spec.rb +++ b/spec/features/splashpage_spec.rb @@ -61,4 +61,15 @@ feature Splashpage do expect(current_path).to eq(root_path) end end + + context 'public splashpage already created' do + let!(:splashpage) { create(:splashpage, conference: conference, public: true)} + + scenario 'should have organization name', feature: true, js: true do + sign_in participant + visit conference_path(conference.short_title) + + expect(page).to have_text(conference.organization.name) + end + end end From cdc08052b140fc1bca6bb8847f40a4e61a1e169f Mon Sep 17 00:00:00 2001 From: shlok007 Date: Mon, 24 Jul 2017 13:46:09 +0530 Subject: [PATCH 143/237] display organization name in menu bar --- app/views/admin/conferences/edit.html.haml | 1 - app/views/conferences/show.html.haml | 3 --- app/views/layouts/_navigation.html.haml | 5 ++++- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/views/admin/conferences/edit.html.haml b/app/views/admin/conferences/edit.html.haml index 49d65235..2d5df126 100644 --- a/app/views/admin/conferences/edit.html.haml +++ b/app/views/admin/conferences/edit.html.haml @@ -9,7 +9,6 @@ = semantic_form_for(@conference, url: admin_conference_path(@conference.short_title), html: {multipart: true}) do |f| = f.input :title, hint: "The full title of the conference, e.g. 'openSUSE Conference 2014'" = f.input :short_title, hint: "A short title, e.g. 'oSC14', to be used in URLs" - = f.input :organization, hint: 'The organization in which this conference belongs', input_html: { disabled: true } = f.input :description, hint: markdown_hint('A description of the conference.'), input_html: { rows: 5, data: { provide: 'markdown-editable' } } = f.input :color, hint: 'The color will be used eg for the dashboard.', input_html: {size: 6, type: 'color'} = f.label 'Conference Logo' diff --git a/app/views/conferences/show.html.haml b/app/views/conferences/show.html.haml index b133c26a..fb488e22 100644 --- a/app/views/conferences/show.html.haml +++ b/app/views/conferences/show.html.haml @@ -22,9 +22,6 @@ .col-md-8 %h1 = @conference.title - %h3 - %i - = "( by #{@conference.organization.name} )" %p.lead - if @conference.venue = "#{@conference.venue.city} / #{@conference.venue.country_name}" diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index 6683ea23..92be2e89 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -7,7 +7,10 @@ %span.icon-bar %span.icon-bar %span.icon-bar - = link_to (ENV['OSEM_NAME'] || 'OSEM'), root_path, class: 'navbar-brand', title: 'Open Source Event Manager' + - if @conference.nil? || @conference.new_record? + = link_to (ENV['OSEM_NAME'] || 'OSEM'), root_path, class: 'navbar-brand', title: 'Open Source Event Manager' + - else + = link_to (ENV['OSEM_NAME'] || "#{@conference.organization.name} Organization"), organizations_path, class: 'navbar-brand', title: 'Open Source Event Manager' .collapse.navbar-collapse - if content_for :splash_nav %ul.nav.navbar-nav#splash-nav From 17eacaec0dcf154f8d4a11af6b83d0d3bcfbb68e Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 25 Jul 2017 08:16:44 +0530 Subject: [PATCH 144/237] add tests for organization name in conference views remove tests for organization name in conference#edit --- app/views/admin/conferences/show.html.haml | 2 +- app/views/layouts/_navigation.html.haml | 4 ++-- app/views/layouts/application.html.haml | 2 +- spec/features/conference_spec.rb | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/admin/conferences/show.html.haml b/app/views/admin/conferences/show.html.haml index f270867b..cddae4c2 100644 --- a/app/views/admin/conferences/show.html.haml +++ b/app/views/admin/conferences/show.html.haml @@ -1,6 +1,6 @@ %h1 %span.fa.fa-tachometer - Dashboard for #{@conference.title} ( by #{@conference.organization.name} ) + Dashboard for #{@conference.title} %hr .row .col-sm-4.col-xs-4 diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index 92be2e89..dbbfdbc0 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -7,10 +7,10 @@ %span.icon-bar %span.icon-bar %span.icon-bar - - if @conference.nil? || @conference.new_record? + - if conference.nil? || conference.new_record? = link_to (ENV['OSEM_NAME'] || 'OSEM'), root_path, class: 'navbar-brand', title: 'Open Source Event Manager' - else - = link_to (ENV['OSEM_NAME'] || "#{@conference.organization.name} Organization"), organizations_path, class: 'navbar-brand', title: 'Open Source Event Manager' + = link_to (ENV['OSEM_NAME'] || "#{conference.organization.name} Organization"), organizations_path, class: 'navbar-brand', title: 'Open Source Event Manager' .collapse.navbar-collapse - if content_for :splash_nav %ul.nav.navbar-nav#splash-nav diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 09be2523..c1a6ce78 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -21,7 +21,7 @@ = yield(:head) %body - = render 'layouts/navigation' + = render 'layouts/navigation', conference: @conference -# Admin area - if controller.class.name.split("::").first=="Admin" = render 'layouts/admin' diff --git a/spec/features/conference_spec.rb b/spec/features/conference_spec.rb index 5b9f9c54..5ac9f29b 100644 --- a/spec/features/conference_spec.rb +++ b/spec/features/conference_spec.rb @@ -73,11 +73,11 @@ feature Conference do describe 'admin' do let!(:conference) { create(:conference) } - scenario 'has organization name in edit form', feature: true, js: true do + scenario 'has organization name in menu bar for conference views', feature: true, js: true do sign_in user - visit edit_admin_conference_path(conference.short_title) - org_id = find('#conference_organization_id').value - expect(Organization.find(org_id)).to eq conference.organization + visit admin_conference_path(conference.short_title) + + expect(find('.navbar-brand').text).to eq "#{conference.organization.name} Organization" end it_behaves_like 'add and update conference' From 28b55a9d72e8c3b4de5e1271ed4082d31e97fe0a Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 2 Aug 2017 15:00:08 +0530 Subject: [PATCH 145/237] remove OSEM_NAME from navigation --- app/views/layouts/_navigation.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index dbbfdbc0..193e6b76 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -10,7 +10,7 @@ - if conference.nil? || conference.new_record? = link_to (ENV['OSEM_NAME'] || 'OSEM'), root_path, class: 'navbar-brand', title: 'Open Source Event Manager' - else - = link_to (ENV['OSEM_NAME'] || "#{conference.organization.name} Organization"), organizations_path, class: 'navbar-brand', title: 'Open Source Event Manager' + = link_to "#{conference.organization.name} Organization", organizations_path, class: 'navbar-brand', title: 'Open Source Event Manager' .collapse.navbar-collapse - if content_for :splash_nav %ul.nav.navbar-nav#splash-nav From 83abc9f71f1f857ceab691dfea6b2664baaea847 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 9 Aug 2017 23:34:58 +0530 Subject: [PATCH 146/237] remove Organization suffix from navbar-brand in navigation --- app/views/layouts/_navigation.html.haml | 2 +- spec/features/conference_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index 193e6b76..9750be92 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -10,7 +10,7 @@ - if conference.nil? || conference.new_record? = link_to (ENV['OSEM_NAME'] || 'OSEM'), root_path, class: 'navbar-brand', title: 'Open Source Event Manager' - else - = link_to "#{conference.organization.name} Organization", organizations_path, class: 'navbar-brand', title: 'Open Source Event Manager' + = link_to conference.organization.name, organizations_path, class: 'navbar-brand', title: 'Open Source Event Manager' .collapse.navbar-collapse - if content_for :splash_nav %ul.nav.navbar-nav#splash-nav diff --git a/spec/features/conference_spec.rb b/spec/features/conference_spec.rb index 5ac9f29b..f3205e07 100644 --- a/spec/features/conference_spec.rb +++ b/spec/features/conference_spec.rb @@ -77,7 +77,7 @@ feature Conference do sign_in user visit admin_conference_path(conference.short_title) - expect(find('.navbar-brand').text).to eq "#{conference.organization.name} Organization" + expect(find('.navbar-brand').text).to eq(conference.organization.name) end it_behaves_like 'add and update conference' From f31651ad9c0ce80a3fe41013d01773c9c7cb0307 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Mon, 7 Aug 2017 15:10:06 +0530 Subject: [PATCH 147/237] Added registration-ticket Added registration type tickets that will used in the check-in process --- app/controllers/admin/tickets_controller.rb | 2 +- app/views/admin/tickets/_form.html.haml | 1 + app/views/admin/tickets/index.html.haml | 3 +++ .../20170807092805_add_registration_ticket_to_tickets.rb | 5 +++++ db/schema.rb | 3 ++- 5 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20170807092805_add_registration_ticket_to_tickets.rb diff --git a/app/controllers/admin/tickets_controller.rb b/app/controllers/admin/tickets_controller.rb index c7161409..cf6e0f80 100644 --- a/app/controllers/admin/tickets_controller.rb +++ b/app/controllers/admin/tickets_controller.rb @@ -50,7 +50,7 @@ module Admin private def ticket_params - params.require(:ticket).permit(:conference, :title, :url, :description, :conference_id, :price_cents, :price_currency, :price) + params.require(:ticket).permit(:conference, :title, :url, :description, :conference_id, :price_cents, :price_currency, :price, :registration_ticket) end end end diff --git a/app/views/admin/tickets/_form.html.haml b/app/views/admin/tickets/_form.html.haml index 94a54692..11aff78d 100644 --- a/app/views/admin/tickets/_form.html.haml +++ b/app/views/admin/tickets/_form.html.haml @@ -13,5 +13,6 @@ = f.input :description, input_html: { rows: 5, data: { provide: "markdown-editable" } } = f.input :price = f.input :price_currency, as: :select, class: 'form-control', collection: ['USD', 'EUR', 'GBP', 'INR', 'CNY'], include_blank: false + = f.input :registration_ticket, hint: 'A registration ticket is with which user register for the conference.' %p.text-right = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/tickets/index.html.haml b/app/views/admin/tickets/index.html.haml index bb2804bf..b8cdb505 100644 --- a/app/views/admin/tickets/index.html.haml +++ b/app/views/admin/tickets/index.html.haml @@ -14,6 +14,7 @@ %th Price %th Sold %th Turnover + %th Registration Ticket %th Actions %tbody - @conference.tickets.each do |ticket| @@ -27,6 +28,8 @@ = ticket.tickets_sold %td = humanized_money_with_symbol ticket.tickets_turnover + %td + = ticket.registration_ticket? ? 'Yes' : 'No' %td .btn-group = link_to 'Edit', edit_admin_conference_ticket_path(@conference.short_title, ticket.id), diff --git a/db/migrate/20170807092805_add_registration_ticket_to_tickets.rb b/db/migrate/20170807092805_add_registration_ticket_to_tickets.rb new file mode 100644 index 00000000..0ee2410d --- /dev/null +++ b/db/migrate/20170807092805_add_registration_ticket_to_tickets.rb @@ -0,0 +1,5 @@ +class AddRegistrationTicketToTickets < ActiveRecord::Migration + def change + add_column :tickets, :registration_ticket, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index d49dfa03..ce680725 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170721001700) do +ActiveRecord::Schema.define(version: 20170807092805) do create_table "ahoy_events", force: :cascade do |t| t.integer "visit_id" @@ -507,6 +507,7 @@ ActiveRecord::Schema.define(version: 20170721001700) do t.text "description" t.integer "price_cents", default: 0, null: false t.string "price_currency", default: "USD", null: false + t.boolean "registration_ticket", default: false end create_table "tracks", force: :cascade do |t| From bd62df14c3999b7968586d886141bc60557d99a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=20Mar=C3=ADa=20Mart=C3=ADnez=20G=C3=B3mez?= Date: Thu, 20 Jul 2017 14:37:22 +0200 Subject: [PATCH 148/237] Fix vagrant broken after updating to Ruby 2.4 Ruby got updated in https://github.com/openSUSE/osem/pull/1588, But there was a repo missed, so Ruby 2.4 can be installed in our Vagrant machine. Closes https://github.com/openSUSE/osem/issues/1601 Mob-programmed by @mdeniz, @DavidKang and @Ana06. --- bootstrap.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bootstrap.sh b/bootstrap.sh index f0ac49fb..92a8d746 100644 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -2,6 +2,8 @@ pushd /vagrant echo -e "\ninstalling required software packages...\n" +zypper -q ar -f http://download.opensuse.org/repositories/devel:/languages:/ruby/openSUSE_Leap_42.2/devel:languages:ruby.repo +zypper -q --gpg-auto-import-keys --non-interactive ref zypper -q -n install update-alternatives ruby2.4-devel make gcc gcc-c++ \ libxml2-devel libxslt-devel nodejs screen mariadb \ libmysqld-devel sqlite3-devel ImageMagick From 88e31ad902f729412a616b18f50bf2e1f38cac25 Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Wed, 2 Aug 2017 11:24:37 -0500 Subject: [PATCH 149/237] Expose enable_starttls_auto & openssl_verify_mode. And align `ENV` calls to keep up with codes above. My fault for using tabs. which caused a real misalignment. --- config/environments/production.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/environments/production.rb b/config/environments/production.rb index d2b43a46..cb3a5d67 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -77,8 +77,9 @@ Osem::Application.configure do user_name: ENV['OSEM_SMTP_USERNAME'], password: ENV['OSEM_SMTP_PASSWORD'], authentication: ENV['OSEM_SMTP_AUTHENTICATION'].try(:to_sym), - domain: ENV['OSEM_SMTP_DOMAIN'], - enable_starttls_auto: true + domain: ENV['OSEM_SMTP_DOMAIN'], + enable_starttls_auto: ENV['OSEM_SMTP_ENABLE_STARTTLS_AUTO'], + openssl_verify_mode: ENV['OSEM_SMTP_OPENSSL_VERIFY_MODE'] } # Set the secret_key_base from the env, if not set by any other means From 33aee342b43d14cf3ade75a0f45ae6018982566b Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Wed, 2 Aug 2017 21:19:13 -0500 Subject: [PATCH 150/237] Add new envs to dotenv.example. --- dotenv.example | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dotenv.example b/dotenv.example index 0c852658..77c28e4c 100644 --- a/dotenv.example +++ b/dotenv.example @@ -58,6 +58,8 @@ OSEM_SMTP_USERNAME="" OSEM_SMTP_PASSWORD="" OSEM_SMTP_AUTHENTICATION="" OSEM_SMTP_DOMAIN="" +OSEM_SMTP_ENABLE_STARTTLS_AUTO="" +OSEM_SMTP_OPENSSL_VERIFY_MODE="" # Enable the usage of the devise ichain plugin OSEM_ICHAIN_ENABLED=false From d616c66745352e9c64e3f248e9271b5555073607 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 12 Jul 2017 14:31:22 +0300 Subject: [PATCH 151/237] Define the track's finite state machine --- .rubocop_todo.yml | 1 + app/models/track.rb | 66 ++++++++++++++++++- spec/features/track_organizer_ability_spec.rb | 4 +- spec/models/admin_ability_spec.rb | 9 +-- 4 files changed, 72 insertions(+), 8 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 8d752446..e7e50f4a 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -565,6 +565,7 @@ Style/PercentLiteralDelimiters: - 'app/models/subscription.rb' - 'app/uploaders/picture_uploader.rb' - 'spec/models/program_spec.rb' + - 'app/models/track.rb' # Offense count: 2 # Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. diff --git a/app/models/track.rb b/app/models/track.rb index 2b37d1bb..6228ff02 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -1,4 +1,5 @@ class Track < ActiveRecord::Base + include ActiveRecord::Transitions include RevisionCount resourcify :roles, dependent: :delete_all @@ -18,12 +19,49 @@ class Track < ActiveRecord::Base uniqueness: { scope: :program } - validates :state, presence: true, if: :self_organized? + validates :state, + presence: true, + inclusion: { in: %w(new to_accept accepted confirmed to_reject rejected canceled withdrawn) }, + if: :self_organized? validates :cfp_active, inclusion: { in: [true, false] }, if: :self_organized? before_validation :capitalize_color - after_create :create_organizer_role, if: :self_organized? + state_machine initial: :pending do + state :new + state :to_accept + state :accepted + state :confirmed + state :to_reject + state :rejected + state :canceled + state :withdrawn + + event :restart do + transitions to: :new, from: [:rejected, :withdrawn, :canceled] + end + event :readiness_to_accept do + transitions to: :to_accept, from: [:new] + end + event :accept do + transitions to: :accepted, from: [:new, :to_accept], on_transition: :create_organizer_role + end + event :confirm do + transitions to: :confirmed, from: [:accepted], on_transition: :assign_role_to_submitter + end + event :readiness_to_reject do + transitions to: :to_reject, from: [:new] + end + event :reject do + transitions to: :rejected, from: [:new, :to_reject] + end + event :cancel do + transitions to: :canceled, from: [:to_accept, :to_reject, :accepted, :confirmed], on_transition: :revoke_role_and_cleanup + end + event :withdraw do + transitions to: :withdrawn, from: [:new, :to_accept, :to_reject, :accepted, :confirmed], on_transition: :revoke_role_and_cleanup + end + end def conference program.conference @@ -43,6 +81,30 @@ class Track < ActiveRecord::Base short_name end + def transition_possible?(transition) + self.class.state_machine.events_for(current_state).include?(transition) + end + + # Gives the role of the track_organizer to the submitter + def assign_role_to_submitter + submitter.add_role 'track_organizer', self + end + + # Revokes the track organizer role and removes the track from events that have it set + def revoke_role_and_cleanup + role = Role.find_by(name: 'track_organizer', resource: self) + + if role + role.users.each do |user| + user.remove_role 'track_organizer', self + end + end + + events.each do |event| + event.track = nil + end + end + private def generate_guid diff --git a/spec/features/track_organizer_ability_spec.rb b/spec/features/track_organizer_ability_spec.rb index f79eba05..49e46915 100644 --- a/spec/features/track_organizer_ability_spec.rb +++ b/spec/features/track_organizer_ability_spec.rb @@ -5,10 +5,10 @@ feature 'Has correct abilities' do let(:organization) { create(:organization) } let(:conference) { create(:full_conference, organization: organization) } let(:self_organized_track) { create(:track, :self_organized, program: conference.program) } - let(:role_track_organizer) { Role.find_by(name: 'track_organizer', resource: self_organized_track) } + let(:role_track_organizer) { Role.where(name: 'track_organizer', resource: self_organized_track).first_or_create } let(:user_track_organizer) { create(:user, role_ids: [role_track_organizer.id]) } - context 'when user is info desk' do + context 'when user is track organizer' do before do sign_in user_track_organizer end diff --git a/spec/models/admin_ability_spec.rb b/spec/models/admin_ability_spec.rb index 5398b7d2..16456a19 100644 --- a/spec/models/admin_ability_spec.rb +++ b/spec/models/admin_ability_spec.rb @@ -79,7 +79,7 @@ describe 'User with admin role' do context 'accesses track organizers' do before :each do other_self_organized_track = create(:track, :self_organized) - @other_track_organizer_role = Role.find_by(name: 'track_organizer', resource: other_self_organized_track) + @other_track_organizer_role = Role.where(name: 'track_organizer', resource: other_self_organized_track).first_or_create end it{ should_not be_able_to(:toggle_user, @other_track_organizer_role) } @@ -105,7 +105,7 @@ describe 'User with admin role' do context 'accesses track organizers' do before :each do - @track_organizer_role = Role.find_by(name: 'track_organizer', resource: my_self_organized_track) + @track_organizer_role = Role.where(name: 'track_organizer', resource: my_self_organized_track).first_or_create end if role_name == 'track_organizer' @@ -223,7 +223,7 @@ describe 'User with admin role' do context 'can manage track organizers' do before :each do - @track_organizer_role = Role.find_by(name: 'track_organizer', resource: my_self_organized_track) + @track_organizer_role = Role.where(name: 'track_organizer', resource: my_self_organized_track).first_or_create end it{ should be_able_to(:toggle_user, @track_organizer_role) } @@ -441,7 +441,8 @@ describe 'User with admin role' do end context 'when user has the role track_organizer' do - let(:role) { Role.find_by(name: 'track_organizer', resource: my_self_organized_track) } + + let(:role) { Role.where(name: 'track_organizer', resource: my_self_organized_track).first_or_create } let(:user) { create(:user, role_ids: [role.id]) } let(:new_track) { build(:track, program: my_conference.program) } From fd93b04f169685f446dd9e3a4e2395a80a53f0a6 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 12 Jul 2017 15:56:07 +0300 Subject: [PATCH 152/237] Add room and dates to tracks They are required only for accepted and confirmed self-organized tracks --- .rubocop_todo.yml | 4 ++ app/controllers/admin/tracks_controller.rb | 2 +- app/models/room.rb | 1 + app/models/track.rb | 56 +++++++++++++++++++ app/views/admin/tracks/_form.html.haml | 8 ++- app/views/admin/tracks/index.html.haml | 18 ++++++ ...0712120556_add_room_and_dates_to_tracks.rb | 7 +++ db/schema.rb | 4 ++ spec/models/room_spec.rb | 1 + 9 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20170712120556_add_room_and_dates_to_tracks.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index e7e50f4a..487a9fdb 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -317,6 +317,8 @@ Metrics/BlockLength: # Offense count: 23 Metrics/CyclomaticComplexity: Max: 12 + Exclude: + - 'app/models/track.rb' # Offense count: 2353 # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. @@ -339,6 +341,8 @@ Metrics/ModuleLength: # Offense count: 15 Metrics/PerceivedComplexity: Max: 16 + Exclude: + - 'app/models/track.rb' # Offense count: 20 Style/AccessorMethodName: diff --git a/app/controllers/admin/tracks_controller.rb b/app/controllers/admin/tracks_controller.rb index c229b9b8..0eed1b2d 100644 --- a/app/controllers/admin/tracks_controller.rb +++ b/app/controllers/admin/tracks_controller.rb @@ -62,7 +62,7 @@ module Admin private def track_params - params.require(:track).permit(:name, :description, :color, :short_name, :cfp_active) + params.require(:track).permit(:name, :description, :color, :short_name, :cfp_active, :start_date, :end_date, :room_id) end end end diff --git a/app/models/room.rb b/app/models/room.rb index f8150f78..8a50551d 100644 --- a/app/models/room.rb +++ b/app/models/room.rb @@ -2,6 +2,7 @@ class Room < ActiveRecord::Base include RevisionCount belongs_to :venue has_many :event_schedules, dependent: :destroy + has_many :tracks has_paper_trail ignore: [:guid], meta: { conference_id: :conference_id } diff --git a/app/models/track.rb b/app/models/track.rb index 6228ff02..f29babde 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -6,6 +6,7 @@ class Track < ActiveRecord::Base belongs_to :program belongs_to :submitter, class_name: 'User' + belongs_to :room has_many :events, dependent: :nullify has_paper_trail only: [:name, :description, :color], meta: { conference_id: :conference_id } @@ -24,6 +25,10 @@ class Track < ActiveRecord::Base inclusion: { in: %w(new to_accept accepted confirmed to_reject rejected canceled withdrawn) }, if: :self_organized? validates :cfp_active, inclusion: { in: [true, false] }, if: :self_organized? + validates :start_date, presence: true, if: :accepted_or_confirmed? + validates :end_date, presence: true, if: :accepted_or_confirmed? + validates :room, presence: true, if: :accepted_or_confirmed? + validate :valid_dates, if: :accepted_or_confirmed? before_validation :capitalize_color @@ -105,6 +110,33 @@ class Track < ActiveRecord::Base end end + ## + # Checks if the track is accepted + # ====Returns + # * +true+ -> If the track's state is 'accepted' + # * +false+ -> If the track's state isn't 'accepted' + def accepted? + state == 'accepted' + end + + ## + # Checks if the track is confirmed + # ====Returns + # * +true+ -> If the track's state is 'confirmed' + # * +false+ -> If the track's state isn't 'confirmed' + def confirmed? + state == 'confirmed' + end + + ## + # Checks if the track is accepted or confirmed + # ====Returns + # * +true+ -> If the track's state is 'accepted' or 'confirmed' + # * +false+ -> If the track's state is neither 'accepted' nor 'confirmed' + def accepted_or_confirmed? + accepted? || confirmed? + end + private def generate_guid @@ -128,4 +160,28 @@ class Track < ActiveRecord::Base def create_organizer_role Role.where(name: 'track_organizer', resource: self).first_or_create(description: 'For the organizers of the Track') end + + def valid_dates + return unless start_date && end_date + + if program && program.conference && program.conference.start_date && (start_date < program.conference.start_date) + errors.add(:start_date, "can't be before the conference start date (#{program.conference.end_date})") + end + + if program && program.conference && program.conference.start_date && (end_date < program.conference.start_date) + errors.add(:end_date, "can't be before the conference start date (#{program.conference.end_date})") + end + + if program && program.conference && program.conference.end_date && (start_date > program.conference.end_date) + errors.add(:start_date, "can't be after the conference end date (#{program.conference.end_date})") + end + + if program && program.conference && program.conference.end_date && (end_date > program.conference.end_date) + errors.add(:end_date, "can't be after the conference end date (#{program.conference.end_date})") + end + + if start_date > end_date + errors.add(:start_date, 'can\'t be after the end_date') + end + end end diff --git a/app/views/admin/tracks/_form.html.haml b/app/views/admin/tracks/_form.html.haml index fe7f014a..cb2e8b01 100644 --- a/app/views/admin/tracks/_form.html.haml +++ b/app/views/admin/tracks/_form.html.haml @@ -8,10 +8,16 @@ Track .row .col-md-12 - = semantic_form_for(@track, url: (@track.new_record? ? admin_conference_program_tracks_path : admin_conference_program_track_path(@conference.short_title, @track))) do |f| + = semantic_form_for(@track, url: (@track.new_record? ? admin_conference_program_tracks_path(@conference.short_title) : admin_conference_program_track_path(@conference.short_title, @track))) do |f| = f.input :name = f.input :short_name, hint: "A short and unique handle for the track, using only letters, numbers, underscores, and dashes. This will be used to identify the track in URLs etc. Example: 'my_awesome_track'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' } = f.input :color, input_html: {size: 6, type: 'color'}, required: true + = f.input :start_date, as: :string, input_html: { id: 'registration-period-start-datepicker', start_date: @conference.start_date, end_date: @conference.end_date, readonly: 'readonly', required: @track.self_organized_and_accepted_or_confirmed? } + = f.input :end_date, as: :string, input_html: { id: 'registration-period-end-datepicker', readonly: 'readonly', required: @track.self_organized_and_accepted_or_confirmed? } + - if @conference.venue + = f.input :room, as: :select, collection: (@conference.venue.rooms).map {|room| ["#{room.name}", room.id]}, include_blank: true, label: 'Room', input_html: { class: 'select-help-toggle', required: @track.self_organized_and_accepted_or_confirmed? } + - else + Please add a venue with rooms, if you want to select a room for the track. = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, hint: markdown_hint - if @track.self_organized? = f.input :cfp_active, label: 'Allow event submitters to select this track for their proposal' diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 1cda360a..82167bb8 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -15,6 +15,9 @@ %th Color %th State %th Included in the Cfp + %th Room + %th Start Date + %th End Date %th Actions %tbody - @tracks.each do |track| @@ -52,6 +55,21 @@ off_text: 'No' } - else %i.fa.fa-check + %td + - if track.room + = link_to track.room.name, admin_conference_venue_room_path(@conference.short_title, track.room.id) + - else + N/A + %td + - if track.start_date + = track.start_date.strftime('%A, %B %-d. %Y') + - else + N/A + %td + - if track.end_date + = track.end_date.strftime('%A, %B %-d. %Y') + - else + N/A %td .btn-group{role: "group"} = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), diff --git a/db/migrate/20170712120556_add_room_and_dates_to_tracks.rb b/db/migrate/20170712120556_add_room_and_dates_to_tracks.rb new file mode 100644 index 00000000..fb8a064b --- /dev/null +++ b/db/migrate/20170712120556_add_room_and_dates_to_tracks.rb @@ -0,0 +1,7 @@ +class AddRoomAndDatesToTracks < ActiveRecord::Migration + def change + add_reference :tracks, :room, index: true, foreign_key: true + add_column :tracks, :start_date, :date + add_column :tracks, :end_date, :date + end +end diff --git a/db/schema.rb b/db/schema.rb index ce680725..d3e14687 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -522,8 +522,12 @@ ActiveRecord::Schema.define(version: 20170807092805) do t.string "state" t.boolean "cfp_active" t.integer "submitter_id" + t.integer "room_id" + t.date "start_date" + t.date "end_date" end + add_index "tracks", ["room_id"], name: "index_tracks_on_room_id" add_index "tracks", ["submitter_id"], name: "index_tracks_on_submitter_id" create_table "users", force: :cascade do |t| diff --git a/spec/models/room_spec.rb b/spec/models/room_spec.rb index 469fb117..f135f91d 100644 --- a/spec/models/room_spec.rb +++ b/spec/models/room_spec.rb @@ -12,6 +12,7 @@ describe Room do describe 'association' do it { should belong_to(:venue) } it { should have_many(:event_schedules).dependent(:destroy) } + it { should have_many(:tracks) } end describe 'callback' do From 0f154d07c9abcb1bb5a954b79d67092d89e92b08 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Sat, 15 Jul 2017 19:55:45 +0300 Subject: [PATCH 153/237] Mark track state as not null and add default value The regular tracks are marked as 'confirmed' --- app/controllers/admin/tracks_controller.rb | 1 + app/controllers/tracks_controller.rb | 1 - app/models/track.rb | 14 +++++++------- app/views/admin/tracks/index.html.haml | 2 +- ...e_track_state_not_null_and_add_default_value.rb | 14 ++++++++++++++ db/schema.rb | 8 ++++---- spec/controllers/admin/tracks_controller_spec.rb | 4 ++++ spec/factories/tracks.rb | 1 + 8 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 db/migrate/20170715131706_make_track_state_not_null_and_add_default_value.rb diff --git a/app/controllers/admin/tracks_controller.rb b/app/controllers/admin/tracks_controller.rb index 0eed1b2d..2cb6ec2b 100644 --- a/app/controllers/admin/tracks_controller.rb +++ b/app/controllers/admin/tracks_controller.rb @@ -19,6 +19,7 @@ module Admin def create @track = @program.tracks.new(track_params) + @track.state = 'confirmed' if @track.save redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title), notice: 'Track successfully created.' diff --git a/app/controllers/tracks_controller.rb b/app/controllers/tracks_controller.rb index 529767cd..59deae3c 100644 --- a/app/controllers/tracks_controller.rb +++ b/app/controllers/tracks_controller.rb @@ -18,7 +18,6 @@ class TracksController < ApplicationController def create @track = @program.tracks.new(track_params) @track.submitter = current_user - @track.state = 'new' @track.cfp_active = false if @track.save redirect_to conference_program_tracks_path(conference_id: @conference.short_title), diff --git a/app/models/track.rb b/app/models/track.rb index f29babde..a53471bc 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -25,10 +25,10 @@ class Track < ActiveRecord::Base inclusion: { in: %w(new to_accept accepted confirmed to_reject rejected canceled withdrawn) }, if: :self_organized? validates :cfp_active, inclusion: { in: [true, false] }, if: :self_organized? - validates :start_date, presence: true, if: :accepted_or_confirmed? - validates :end_date, presence: true, if: :accepted_or_confirmed? - validates :room, presence: true, if: :accepted_or_confirmed? - validate :valid_dates, if: :accepted_or_confirmed? + validates :start_date, presence: true, if: :self_organized_and_accepted_or_confirmed? + validates :end_date, presence: true, if: :self_organized_and_accepted_or_confirmed? + validates :room, presence: true, if: :self_organized_and_accepted_or_confirmed? + validate :valid_dates, if: :self_organized_and_accepted_or_confirmed? before_validation :capitalize_color @@ -129,12 +129,12 @@ class Track < ActiveRecord::Base end ## - # Checks if the track is accepted or confirmed + # Checks if a self-organized track is accepted or confirmed # ====Returns # * +true+ -> If the track's state is 'accepted' or 'confirmed' # * +false+ -> If the track's state is neither 'accepted' nor 'confirmed' - def accepted_or_confirmed? - accepted? || confirmed? + def self_organized_and_accepted_or_confirmed? + self_organized? && (accepted? || confirmed?) end private diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 82167bb8..4da97a18 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -42,7 +42,7 @@ - if track.self_organized? = track.state - else - N/A + = track.state.humanize %td - if track.self_organized? = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, diff --git a/db/migrate/20170715131706_make_track_state_not_null_and_add_default_value.rb b/db/migrate/20170715131706_make_track_state_not_null_and_add_default_value.rb new file mode 100644 index 00000000..3d2520cf --- /dev/null +++ b/db/migrate/20170715131706_make_track_state_not_null_and_add_default_value.rb @@ -0,0 +1,14 @@ +class MakeTrackStateNotNullAndAddDefaultValue < ActiveRecord::Migration + class TmpTrack < ActiveRecord::Base + self.table_name = 'tracks' + end + + def change + TmpTrack.where(state: nil).each do |track| + track.state = 'confirmed' + track.save! + end + + change_column :tracks, :state, :string, null: false, default: 'new' + end +end diff --git a/db/schema.rb b/db/schema.rb index d3e14687..aa2f160d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -511,15 +511,15 @@ ActiveRecord::Schema.define(version: 20170807092805) do end create_table "tracks", force: :cascade do |t| - t.string "guid", null: false - t.string "name", null: false + t.string "guid", null: false + t.string "name", null: false t.text "description" t.string "color" t.datetime "created_at" t.datetime "updated_at" t.integer "program_id" - t.string "short_name", null: false - t.string "state" + t.string "short_name", null: false + t.string "state", default: "new", null: false t.boolean "cfp_active" t.integer "submitter_id" t.integer "room_id" diff --git a/spec/controllers/admin/tracks_controller_spec.rb b/spec/controllers/admin/tracks_controller_spec.rb index 2177af2f..ed76fe68 100644 --- a/spec/controllers/admin/tracks_controller_spec.rb +++ b/spec/controllers/admin/tracks_controller_spec.rb @@ -80,6 +80,10 @@ describe Admin::TracksController do it 'creates new track' do expect(Track.find(assigns(:track).id)).to be_a Track end + + it 'the new tracks has the correct attributes' do + expect(assigns(:track).state).to eq 'confirmed' + end end context 'save fails' do diff --git a/spec/factories/tracks.rb b/spec/factories/tracks.rb index 091d8d07..d30a686e 100644 --- a/spec/factories/tracks.rb +++ b/spec/factories/tracks.rb @@ -4,6 +4,7 @@ FactoryGirl.define do description { Faker::Lorem.sentence } color { Faker::Color.hex_color } short_name { SecureRandom.urlsafe_base64(5) } + state 'confirmed' program trait :self_organized do From 2f9eb0421940bffb44837d343e35ef0d0f3fd59d Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 12 Jul 2017 16:35:09 +0300 Subject: [PATCH 154/237] Enable track requests --- .haml-lint_todo.yml | 4 +++ app/helpers/application_helper.rb | 2 +- app/models/ability.rb | 8 +++++ app/models/cfp.rb | 3 +- app/views/admin/cfps/_tracks_cfp.html.haml | 12 ++++++++ .../conferences/_call_for_tracks.html.haml | 30 +++++++++++++++++++ .../conferences/_conference_details.html.haml | 4 +++ app/views/conferences/show.html.haml | 4 +++ app/views/tracks/index.html.haml | 2 +- app/views/tracks/show.html.haml | 2 +- spec/features/cfp_ability_spec.rb | 26 ++++++++++++++-- .../organization_admin_ability_spec.rb | 26 ++++++++++++++-- spec/features/organizer_ability_spec.rb | 26 ++++++++++++++-- spec/models/program_spec.rb | 26 +++++++++------- 14 files changed, 155 insertions(+), 20 deletions(-) create mode 100644 app/views/admin/cfps/_tracks_cfp.html.haml create mode 100644 app/views/conferences/_call_for_tracks.html.haml diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 52d5f5ca..11397297 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -180,6 +180,7 @@ linters: - "app/views/tracks/_form.html.haml" - "app/views/tracks/index.html.haml" - "app/views/tracks/show.html.haml" + - "app/views/conferences/_call_for_tracks.html.haml" # Offense count: 223 InstanceVariables: @@ -242,6 +243,8 @@ linters: - "app/views/schedules/_schedule_tabs.html.haml" - "app/views/admin/cfps/_events_cfp.html.haml" - "app/views/tracks/_form.html.haml" + - "app/views/admin/cfps/_tracks_cfp.html.haml" + - "app/views/conferences/_call_for_tracks.html.haml" # Offense count: 32 IdNames: @@ -261,6 +264,7 @@ linters: - "app/views/admin/users/show.html.haml" - "app/views/users/edit.html.haml" - "app/views/admin/cfps/_events_cfp.html.haml" + - "app/views/admin/cfps/_tracks_cfp.html.haml" # Offense count: 4 UnnecessaryInterpolation: diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 0abf6088..fdef7b4a 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -56,7 +56,7 @@ module ApplicationHelper end def tracks(conference) - all = conference.program.tracks.map {|t| t.name} + all = conference.program.tracks.map { |t| t.name if !t.self_organized? || t.confirmed? && t.cfp_active }.compact first = all[0...-1] last = all[-1] ts = '' diff --git a/app/models/ability.rb b/app/models/ability.rb index 0ebabfdc..e5dbd7e4 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -95,6 +95,14 @@ class Ability can :manage, Commercial, commercialable_type: 'Event', commercialable_id: user.events.pluck(:id) can [:destroy], Openid + + can [:new, :create], Track do |track| + track.new_record? && track.program.cfps.for_tracks.try(:open?) + end + + can [:index, :show, :edit, :update], Track do |track| + user == track.submitter + end end # Abilities for users with roles wandering around in non-admin views. diff --git a/app/models/cfp.rb b/app/models/cfp.rb index 97f276c9..44d8281b 100644 --- a/app/models/cfp.rb +++ b/app/models/cfp.rb @@ -1,9 +1,10 @@ # cannot delete program if there are events submitted class Cfp < ActiveRecord::Base - TYPES = %w(events booths).freeze + TYPES = %w(events booths tracks).freeze scope :for_events, (-> { find_by(cfp_type: 'events') }) + scope :for_tracks, (-> { find_by(cfp_type: 'tracks') }) has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id } belongs_to :program diff --git a/app/views/admin/cfps/_tracks_cfp.html.haml b/app/views/admin/cfps/_tracks_cfp.html.haml new file mode 100644 index 00000000..e381df96 --- /dev/null +++ b/app/views/admin/cfps/_tracks_cfp.html.haml @@ -0,0 +1,12 @@ +%dt + Start Date: +%dd#start_date + = @cfp.start_date.strftime('%A, %B %-d. %Y') +%dt + End Date: +%dd#end_date + = @cfp.end_date.strftime('%A, %B %-d. %Y') +%dt + Days Left: +%dd + = pluralize(@cfp.remaining_days, 'day') diff --git a/app/views/conferences/_call_for_tracks.html.haml b/app/views/conferences/_call_for_tracks.html.haml new file mode 100644 index 00000000..1abeb956 --- /dev/null +++ b/app/views/conferences/_call_for_tracks.html.haml @@ -0,0 +1,30 @@ += content_for :splash_nav do + %li + %a.smoothscroll{ href: '#callfortracks' } Call For Tracks + +.container + .row + .col-md-12.text-center + %h2 + Call for Tracks + %p.lead + We are ready to accept requests for tracks! + .row + .col-md-6.col-md-offset-3.col-sm-10.col-sm-offset-1 + %p + The submission period for track requests has begun + %em.notranslate + = @conference.program.cfps.for_tracks.start_date.strftime('%A, %B %-d. %Y') + and closes + %em.notranslate + = @conference.program.cfps.for_tracks.end_date.strftime('%A, %B %-d. %Y.') + - if @conference.program.cfps.for_tracks.try(:open?) + That means you have only + %b.notranslate= pluralize(@conference.program.cfps.for_tracks.remaining_days, 'day') + left! + - else + The submission period for track requests is closed. + .row + .col-md-12.text-center + %p.cta-button + = link_to "Submit your request for track", conference_program_tracks_path(@conference.short_title), class: 'btn btn-success btn-lg text-center' diff --git a/app/views/conferences/_conference_details.html.haml b/app/views/conferences/_conference_details.html.haml index d5bafad4..e8ca2449 100644 --- a/app/views/conferences/_conference_details.html.haml +++ b/app/views/conferences/_conference_details.html.haml @@ -30,6 +30,10 @@ = link_to "Register", new_conference_conference_registration_path(conference.short_title), class: "btn btn-default", disabled: cannot?(:new, Registration.new(conference_id: conference.id)) - if cannot?(:new, Registration.new(conference_id: conference.id)) && conference.registration_limit_exceeded? Sorry, no places left + - if !current_user.nil? && current_user.tracks.where(program: conference.program).length > 0 + = link_to "My Track Requests", conference_program_tracks_path(conference.short_title), class: 'btn btn-default' + - elsif can? :new, conference.program.tracks.new + = link_to "Submit Track Request", new_conference_program_track_path(conference.short_title), class: 'btn btn-default' - if !current_user.nil? && current_user.proposal_count(conference) > 0 = link_to "My Proposals", conference_program_proposals_path(conference.short_title), class: 'btn btn-default' - elsif can? :new, conference.program.events.new diff --git a/app/views/conferences/show.html.haml b/app/views/conferences/show.html.haml index fb488e22..edc72726 100644 --- a/app/views/conferences/show.html.haml +++ b/app/views/conferences/show.html.haml @@ -45,6 +45,10 @@ %section#program = render 'schedule_splashpage' + - if @conference.program.cfps.for_tracks.try(:open?) && @conference.splashpage.include_cfp + %section#callfortracks + = render 'call_for_tracks' + - if @conference.program.cfp_open? and @conference.splashpage.include_cfp %section#callforpapers = render 'call_for_paper' diff --git a/app/views/tracks/index.html.haml b/app/views/tracks/index.html.haml index d4670bf4..7e16304f 100644 --- a/app/views/tracks/index.html.haml +++ b/app/views/tracks/index.html.haml @@ -32,7 +32,7 @@ %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} = track.color %td - = track.state + = track.state.humanize %td = link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track), method: :get, class: 'btn btn-primary' diff --git a/app/views/tracks/show.html.haml b/app/views/tracks/show.html.haml index c08818eb..37c180ae 100644 --- a/app/views/tracks/show.html.haml +++ b/app/views/tracks/show.html.haml @@ -16,7 +16,7 @@ %dt State: %dd - = @track.state + = @track.state.humanize %dt Description %dd diff --git a/spec/features/cfp_ability_spec.rb b/spec/features/cfp_ability_spec.rb index d40a54a4..cd9fa3bd 100644 --- a/spec/features/cfp_ability_spec.rb +++ b/spec/features/cfp_ability_spec.rb @@ -64,29 +64,51 @@ feature 'Has correct abilities' do visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) - # Both event and booth exists + # Event and booth cfps exist cfb = create(:cfp, cfp_type: 'booths', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) - expect(current_path).to eq root_path + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + # Event, booth, track cfps exist + cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq root_path + + # Booth and track cfps exist conference.program.cfp.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) # Only booth exists + cft.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) visit edit_admin_conference_program_cfp_path(conference.short_title, cfb) expect(current_path). to eq(edit_admin_conference_program_cfp_path(conference.short_title, cfb)) + # No cfp exists cfb.destroy visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) + # Only Tracks cfp exists + cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) + + visit edit_admin_conference_program_cfp_path(conference.short_title, cft) + expect(current_path).to eq edit_admin_conference_program_cfp_path(conference.short_title, cft) + + # Event and track cfps exist + create(:cfp, cfp_type: 'events', program: conference.program) + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) + + cft.destroy! create(:event, program: conference.program) visit edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first) expect(current_path).to eq(edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first)) diff --git a/spec/features/organization_admin_ability_spec.rb b/spec/features/organization_admin_ability_spec.rb index 274d345f..12fd038b 100644 --- a/spec/features/organization_admin_ability_spec.rb +++ b/spec/features/organization_admin_ability_spec.rb @@ -106,29 +106,51 @@ feature 'Has correct abilities' do visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) - # Both event and booth exists + # Event and booth cfps exist cfb = create(:cfp, cfp_type: 'booths', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) - expect(current_path).to eq root_path + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + # Event, booth, track cfps exist + cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq root_path + + # Booth and track cfps exist conference.program.cfp.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) # Only booth exists + cft.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) visit edit_admin_conference_program_cfp_path(conference.short_title, cfb) expect(current_path). to eq(edit_admin_conference_program_cfp_path(conference.short_title, cfb)) + # No cfp exists cfb.destroy visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) + # Only Tracks cfp exists + cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) + + visit edit_admin_conference_program_cfp_path(conference.short_title, cft) + expect(current_path).to eq edit_admin_conference_program_cfp_path(conference.short_title, cft) + + # Event and track cfps exist + create(:cfp, cfp_type: 'events', program: conference.program) + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) + + cft.destroy! visit admin_conference_program_events_path(conference.short_title) expect(current_path).to eq(admin_conference_program_events_path(conference.short_title)) diff --git a/spec/features/organizer_ability_spec.rb b/spec/features/organizer_ability_spec.rb index 3ed6ee39..ef2b3744 100644 --- a/spec/features/organizer_ability_spec.rb +++ b/spec/features/organizer_ability_spec.rb @@ -112,29 +112,51 @@ feature 'Has correct abilities' do visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) - # Both event and booth exists + # Event and booth cfps exist cfb = create(:cfp, cfp_type: 'booths', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) - expect(current_path).to eq root_path + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) visit edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp) expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) + # Event, booth, track cfps exist + cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq root_path + + # Booth and track cfps exist conference.program.cfp.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) # Only booth exists + cft.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) visit edit_admin_conference_program_cfp_path(conference.short_title, cfb) expect(current_path). to eq(edit_admin_conference_program_cfp_path(conference.short_title, cfb)) + # No cfp exists cfb.destroy visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) + # Only Tracks cfp exists + cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) + + visit edit_admin_conference_program_cfp_path(conference.short_title, cft) + expect(current_path).to eq edit_admin_conference_program_cfp_path(conference.short_title, cft) + + # Event and track cfps exist + create(:cfp, cfp_type: 'events', program: conference.program) + visit new_admin_conference_program_cfp_path(conference.short_title) + expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) + + cft.destroy! visit admin_conference_program_events_path(conference.short_title) expect(current_path).to eq(admin_conference_program_events_path(conference.short_title)) diff --git a/spec/models/program_spec.rb b/spec/models/program_spec.rb index d81e32bc..1c8eabd9 100644 --- a/spec/models/program_spec.rb +++ b/spec/models/program_spec.rb @@ -253,28 +253,34 @@ describe Program do end describe '#remaining_cfp_types' do - it 'returns an array with the types for which a cfp doesn\'t exist, when only the Event type does' do - expect(program.remaining_cfp_types).to eq(Cfp::TYPES) + it 'returns an array without the \'events\' type, when the cfp for events exists' do create(:cfp, cfp_type: 'events', program: program) - expect(program.remaining_cfp_types).to eq(['booths']) + expect(program.remaining_cfp_types).to be_a Array + expect(program.remaining_cfp_types.include?('events')).to eq false end - it 'returns an array with the types for which a cfp doesn\'t exist, when only the Booth type does' do - expect(program.remaining_cfp_types).to eq(Cfp::TYPES) + it 'returns an array without the \'booths\' type, when the cfp for booths exists' do create(:cfp, cfp_type: 'booths', program: program) - expect(program.remaining_cfp_types).to eq(['events']) + expect(program.remaining_cfp_types).to be_a Array + expect(program.remaining_cfp_types.include?('booths')).to eq false end - it 'returns an empty array when all the cfp types exist' do - expect(program.remaining_cfp_types).to eq(Cfp::TYPES) + it 'returns an array without the \'tracks\' type, when the cfp for tracks exists' do + create(:cfp, cfp_type: 'tracks', program: program) + expect(program.remaining_cfp_types).to be_a Array + expect(program.remaining_cfp_types.include?('tracks')).to eq false + end + + it 'returns an empty array when cfps for all the types exist' do create(:cfp, cfp_type: 'events', program: program) create(:cfp, cfp_type: 'booths', program: program) + create(:cfp, cfp_type: 'tracks', program: program) expect(program.remaining_cfp_types).to eq([]) end - it 'returns all the possible cfp types when there is no existed cfp type' do + it 'returns all the possible cfp types when there is no cfp' do expect(program.remaining_cfp_types).to eq(Cfp::TYPES) - expect(program.remaining_cfp_types). to eq(%w[events booths]) + expect(program.remaining_cfp_types). to eq(%w[events booths tracks]) end end end From d9faffc96a04dacdac8472f80c9e3f106e69a2e2 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Fri, 14 Jul 2017 15:57:34 +0300 Subject: [PATCH 155/237] Implement track request acceptance Allow track submitter to request specific dates Redirect to Tracks#edit if a track doesn't have a room or start/end date before accepting it Don't allow the submitter or the track organizers to edit the request after it has been accepted or confirmed Restrict track selection in proposals and move track selection from Proposals form to events helper Mark cfp_active of the tracks table as not null and fill in true if nil --- .haml-lint_todo.yml | 2 + app/controllers/admin/tracks_controller.rb | 46 +++ app/controllers/tracks_controller.rb | 28 +- app/helpers/application_helper.rb | 2 +- app/helpers/events_helper.rb | 8 + app/models/ability.rb | 6 +- app/models/admin_ability.rb | 4 + app/models/event.rb | 8 + app/models/track.rb | 52 ++- .../tracks/_change_state_dropdown.html.haml | 34 ++ app/views/admin/tracks/_form.html.haml | 3 +- app/views/admin/tracks/index.html.haml | 32 +- app/views/proposals/_proposal_form.html.haml | 5 +- app/views/tracks/_form.html.haml | 4 +- app/views/tracks/index.html.haml | 29 +- app/views/tracks/show.html.haml | 17 +- config/routes.rb | 15 +- ...20134353_make_track_cfp_active_not_null.rb | 14 + db/schema.rb | 2 +- .../admin/tracks_controller_spec.rb | 203 ++++++++++- spec/controllers/tracks_controller_spec.rb | 66 +++- spec/factories/tracks.rb | 4 + spec/models/ability_spec.rb | 30 ++ spec/models/admin_ability_spec.rb | 4 +- spec/models/conference_spec.rb | 4 +- spec/models/event_spec.rb | 34 ++ spec/models/track_spec.rb | 315 +++++++++++++++++- 27 files changed, 909 insertions(+), 62 deletions(-) create mode 100644 app/views/admin/tracks/_change_state_dropdown.html.haml create mode 100644 db/migrate/20170720134353_make_track_cfp_active_not_null.rb diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 11397297..89d18c3f 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -181,6 +181,7 @@ linters: - "app/views/tracks/index.html.haml" - "app/views/tracks/show.html.haml" - "app/views/conferences/_call_for_tracks.html.haml" + - "app/views/admin/tracks/_change_state_dropdown.html.haml" # Offense count: 223 InstanceVariables: @@ -245,6 +246,7 @@ linters: - "app/views/tracks/_form.html.haml" - "app/views/admin/cfps/_tracks_cfp.html.haml" - "app/views/conferences/_call_for_tracks.html.haml" + - "app/views/admin/tracks/_change_state_dropdown.html.haml" # Offense count: 32 IdNames: diff --git a/app/controllers/admin/tracks_controller.rb b/app/controllers/admin/tracks_controller.rb index 2cb6ec2b..3d51a677 100644 --- a/app/controllers/admin/tracks_controller.rb +++ b/app/controllers/admin/tracks_controller.rb @@ -20,6 +20,7 @@ module Admin def create @track = @program.tracks.new(track_params) @track.state = 'confirmed' + @track.cfp_active = true if @track.save redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title), notice: 'Track successfully created.' @@ -60,10 +61,55 @@ module Admin end end + def restart + update_state(:restart, "Review for #{@track.name} started!") + end + + def to_accept + update_state(:to_accept, "Track #{@track.name} marked as a possible acceptance!") + end + + def accept + if @track.room && @track.start_date && @track.end_date + update_state(:accept, "Track #{@track.name} accepted!") + else + flash[:alert] = 'Please make sure that the track has a room and start/end dates before accepting it' + redirect_to edit_admin_conference_program_track_path(@conference.short_title, @track) + end + end + + def confirm + update_state(:confirm, "Track #{@track.name} confirmed!") + end + + def to_reject + update_state(:to_reject, "Track #{@track.name} marked as a possible rejection!") + end + + def reject + update_state(:reject, "Track #{@track.name} rejected!") + end + + def cancel + update_state(:cancel, "Track #{@track.name} canceled!") + end + private def track_params params.require(:track).permit(:name, :description, :color, :short_name, :cfp_active, :start_date, :end_date, :room_id) end + + def update_state(transition, notice) + errors = @track.update_state(transition) + + if errors.blank? + flash[:notice] = notice + else + flash[:error] = errors + end + + redirect_back_or_to(admin_conference_program_tracks_path(conference_id: @conference.short_title)) + end end end diff --git a/app/controllers/tracks_controller.rb b/app/controllers/tracks_controller.rb index 59deae3c..9305950e 100644 --- a/app/controllers/tracks_controller.rb +++ b/app/controllers/tracks_controller.rb @@ -4,7 +4,7 @@ class TracksController < ApplicationController load_and_authorize_resource through: :program, find_by: :short_name def index - @tracks = current_user.tracks.where(program: @program) + @tracks = @tracks.where(submitter: current_user) end def show; end @@ -38,9 +38,33 @@ class TracksController < ApplicationController end end + def restart + update_state(:restart, "Track #{@track.name} re-submitted.") + end + + def confirm + update_state(:confirm, "Track #{@track.name} confirmed.") + end + + def withdraw + update_state(:withdraw, "Track #{@track.name} withdrawn.") + end + private def track_params - params.require(:track).permit(:name, :description, :color, :short_name) + params.require(:track).permit(:name, :description, :color, :short_name, :start_date, :end_date) + end + + def update_state(transition, notice) + errors = @track.update_state(transition) + + if errors.blank? + flash[:notice] = notice + else + flash[:error] = errors + end + + redirect_back_or_to(conference_program_tracks_path(conference_id: @conference.short_title)) end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index fdef7b4a..040927c1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -56,7 +56,7 @@ module ApplicationHelper end def tracks(conference) - all = conference.program.tracks.map { |t| t.name if !t.self_organized? || t.confirmed? && t.cfp_active }.compact + all = conference.program.tracks.where(state: 'confirmed', cfp_active: true).pluck(:name) first = all[0...-1] last = all[-1] ts = '' diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 012bd930..dbc609ac 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -39,4 +39,12 @@ module EventsHelper content_tag :span, 'REPLACEMENT', class: (['label', 'label-info'] + label_classes) end end + + def track_selector_input(form) + if @program.tracks.any? + form.input :track_id, as: :select, + collection: @program.tracks.where(state: 'confirmed', cfp_active: true).pluck(:name, :id), + include_blank: true + end + end end diff --git a/app/models/ability.rb b/app/models/ability.rb index e5dbd7e4..63ec68dc 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -100,8 +100,10 @@ class Ability track.new_record? && track.program.cfps.for_tracks.try(:open?) end - can [:index, :show, :edit, :update], Track do |track| - user == track.submitter + can [:index, :show, :restart, :confirm, :withdraw], Track, submitter_id: user.id + + can [:edit, :update], Track do |track| + user == track.submitter && !(track.accepted? || track.confirmed?) end end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 716aecb0..b0c9d4c9 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -275,6 +275,10 @@ class AdminAbility can :manage, Track, id: track_ids_for_track_organizer + cannot [:edit, :update], Track do |track| + track.self_organized_and_accepted_or_confirmed? + end + # Show Roles in the admin sidebar and allow authorization of the index action can [:index, :show], Role do |role| role.resource_type == 'Conference' || role.resource_type == 'Track' diff --git a/app/models/event.rb b/app/models/event.rb index 8436aac9..682eb6c8 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -45,6 +45,7 @@ class Event < ActiveRecord::Base validates :max_attendees, numericality: { only_integer: true, greater_than_or_equal_to: 1, allow_nil: true } validate :max_attendees_no_more_than_room_size + validate :acceptable_track scope :confirmed, -> { where(state: 'confirmed') } scope :canceled, -> { where(state: 'canceled') } @@ -303,4 +304,11 @@ class Event < ActiveRecord::Base def conference_id program.conference_id end + + ## + # Allow only confirmed tracks that belong to the same program and are included in the cfp + def acceptable_track + return unless track && track.program && program + errors.add(:track, 'is invalid') unless track.confirmed? && track.cfp_active && track.program == program + end end diff --git a/app/models/track.rb b/app/models/track.rb index a53471bc..3743cd79 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -22,13 +22,13 @@ class Track < ActiveRecord::Base } validates :state, presence: true, - inclusion: { in: %w(new to_accept accepted confirmed to_reject rejected canceled withdrawn) }, - if: :self_organized? - validates :cfp_active, inclusion: { in: [true, false] }, if: :self_organized? + inclusion: { in: %w(new to_accept accepted confirmed to_reject rejected canceled withdrawn) } + validates :cfp_active, inclusion: { in: [true, false] } validates :start_date, presence: true, if: :self_organized_and_accepted_or_confirmed? validates :end_date, presence: true, if: :self_organized_and_accepted_or_confirmed? validates :room, presence: true, if: :self_organized_and_accepted_or_confirmed? - validate :valid_dates, if: :self_organized_and_accepted_or_confirmed? + validate :valid_dates + validate :valid_room, if: :self_organized_and_accepted_or_confirmed? before_validation :capitalize_color @@ -45,7 +45,7 @@ class Track < ActiveRecord::Base event :restart do transitions to: :new, from: [:rejected, :withdrawn, :canceled] end - event :readiness_to_accept do + event :to_accept do transitions to: :to_accept, from: [:new] end event :accept do @@ -54,7 +54,7 @@ class Track < ActiveRecord::Base event :confirm do transitions to: :confirmed, from: [:accepted], on_transition: :assign_role_to_submitter end - event :readiness_to_reject do + event :to_reject do transitions to: :to_reject, from: [:new] end event :reject do @@ -107,6 +107,7 @@ class Track < ActiveRecord::Base events.each do |event| event.track = nil + event.save! end end @@ -137,6 +138,19 @@ class Track < ActiveRecord::Base self_organized? && (accepted? || confirmed?) end + def update_state(transition) + error = '' + + begin + send(transition) + rescue Transitions::InvalidTransition => e + error += "State update failed. #{e.message} " + end + + error += errors.full_messages.join(', ') unless save + error + end + private def generate_guid @@ -162,26 +176,32 @@ class Track < ActiveRecord::Base end def valid_dates - return unless start_date && end_date - - if program && program.conference && program.conference.start_date && (start_date < program.conference.start_date) - errors.add(:start_date, "can't be before the conference start date (#{program.conference.end_date})") + if start_date && program && program.conference && program.conference.start_date && (start_date < program.conference.start_date) + errors.add(:start_date, "can't be before the conference start date (#{program.conference.start_date})") end - if program && program.conference && program.conference.start_date && (end_date < program.conference.start_date) - errors.add(:end_date, "can't be before the conference start date (#{program.conference.end_date})") + if end_date && program && program.conference && program.conference.start_date && (end_date < program.conference.start_date) + errors.add(:end_date, "can't be before the conference start date (#{program.conference.start_date})") end - if program && program.conference && program.conference.end_date && (start_date > program.conference.end_date) + if start_date && program && program.conference && program.conference.end_date && (start_date > program.conference.end_date) errors.add(:start_date, "can't be after the conference end date (#{program.conference.end_date})") end - if program && program.conference && program.conference.end_date && (end_date > program.conference.end_date) + if end_date && program && program.conference && program.conference.end_date && (end_date > program.conference.end_date) errors.add(:end_date, "can't be after the conference end date (#{program.conference.end_date})") end - if start_date > end_date - errors.add(:start_date, 'can\'t be after the end_date') + if start_date && end_date && (start_date > end_date) + errors.add(:start_date, 'can\'t be after the end date') + end + end + + ## + # Verify that the room is a room of the conference + def valid_room + if room && room.venue && room.venue.conference && program && program.conference && (program.conference != room.venue.conference) + errors.add(:room, "must be a room of #{program.conference.venue.name}") end end end diff --git a/app/views/admin/tracks/_change_state_dropdown.html.haml b/app/views/admin/tracks/_change_state_dropdown.html.haml new file mode 100644 index 00000000..0bbbcd7f --- /dev/null +++ b/app/views/admin/tracks/_change_state_dropdown.html.haml @@ -0,0 +1,34 @@ +- if track.transition_possible? :restart + %li= link_to 'Start review', + restart_admin_conference_program_track_path(@conference.short_title, track), + method: :patch, id: "restart_track_#{track.id}" + +- if track.transition_possible? :to_accept + %li= link_to 'Mark as possible acceptance', + to_accept_admin_conference_program_track_path(@conference.short_title, track), + method: :patch, id: "to_accept_track_#{track.id}" + +- if track.transition_possible? :accept + %li= link_to 'Accept track request', + accept_admin_conference_program_track_path(@conference.short_title, track), + method: :patch, id: "accept_track_#{track.id}" + +- if track.transition_possible? :confirm + %li= link_to 'Confirm track', + confirm_admin_conference_program_track_path(@conference.short_title, track), + method: :patch, id: "confirm_track_#{track.id}" + +- if track.transition_possible? :to_reject + %li= link_to 'Mark as possible rejection', + to_reject_admin_conference_program_track_path(@conference.short_title, track), + method: :patch, id: "to_reject_track_#{track.id}" + +- if track.transition_possible? :reject + %li= link_to 'Reject track request', + reject_admin_conference_program_track_path(@conference.short_title, track), + method: :patch, confirm: 'Are you sure?', id: "reject_track_#{track.id}" + +- if track.transition_possible? :cancel + %li= link_to 'Cancel track request', + cancel_admin_conference_program_track_path(@conference.short_title, track), + method: :patch, id: "cancel_track_#{track.id}" diff --git a/app/views/admin/tracks/_form.html.haml b/app/views/admin/tracks/_form.html.haml index cb2e8b01..eb12561b 100644 --- a/app/views/admin/tracks/_form.html.haml +++ b/app/views/admin/tracks/_form.html.haml @@ -19,6 +19,5 @@ - else Please add a venue with rooms, if you want to select a room for the track. = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, hint: markdown_hint - - if @track.self_organized? - = f.input :cfp_active, label: 'Allow event submitters to select this track for their proposal' + = f.input :cfp_active, label: 'Allow event submitters to select this track for their proposal' = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 4da97a18..0cfe0ff2 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -40,21 +40,24 @@ = track.color %td - if track.self_organized? - = track.state + .btn-group + %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } + = track.state.humanize + %span.caret + %ul.dropdown-menu{ role: 'menu' } + = render 'change_state_dropdown', track: track - else = track.state.humanize %td - - if track.self_organized? - = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, - class: 'switch-checkbox', method: :patch, - url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.short_name)+"?included=", - data: { size: 'small', - on_color: 'success', - off_color: 'warning', - on_text: 'Yes', - off_text: 'No' } - - else - %i.fa.fa-check + = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, + class: 'switch-checkbox', method: :patch, + url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.short_name)+"?included=", + data: { size: 'small', + on_color: 'success', + off_color: 'warning', + on_text: 'Yes', + off_text: 'No' } + %td - if track.room = link_to track.room.name, admin_conference_venue_room_path(@conference.short_title, track.room.id) @@ -72,8 +75,9 @@ N/A %td .btn-group{role: "group"} - = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), - method: :get, class: 'btn btn-primary' + - if can? :edit, track + = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), + method: :get, class: 'btn btn-primary' - if can? :destroy, track = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), method: :delete, class: 'btn btn-danger', diff --git a/app/views/proposals/_proposal_form.html.haml b/app/views/proposals/_proposal_form.html.haml index f31651a1..4b66240c 100644 --- a/app/views/proposals/_proposal_form.html.haml +++ b/app/views/proposals/_proposal_form.html.haml @@ -6,10 +6,7 @@ = speaker_selector_input f - - if @program.tracks.any? - = f.input :track_id, as: :select, - collection: @program.tracks.map {|track| ["#{track.name}", track.id] }, - include_blank: true + = track_selector_input f = f.input :event_type_id, as: :select, collection: @conference.program.event_types.map {|type| ["#{type.title} - #{show_time(type.length)}", type.id, diff --git a/app/views/tracks/_form.html.haml b/app/views/tracks/_form.html.haml index 0e48a851..2a55df5a 100644 --- a/app/views/tracks/_form.html.haml +++ b/app/views/tracks/_form.html.haml @@ -9,9 +9,11 @@ Track .row .col-md-12 - = semantic_form_for(@track, url: (@track.new_record? ? conference_program_tracks_path : conference_program_track_path(@conference.short_title, @track))) do |f| + = semantic_form_for(@track, url: (@track.new_record? ? conference_program_tracks_path(@conference.short_title) : conference_program_track_path(@conference.short_title, @track))) do |f| = f.input :name = f.input :short_name, hint: "A short and unique handle for the track, using only letters, numbers, underscores, and dashes. This will be used to identify the track in URLs etc. Example: 'my_awesome_track'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' } = f.input :color, input_html: {size: 6, type: 'color'}, required: true + = f.input :start_date, as: :string, input_html: { id: 'registration-period-start-datepicker', start_date: @conference.start_date, end_date: @conference.end_date, readonly: 'readonly' } + = f.input :end_date, as: :string, input_html: { id: 'registration-period-end-datepicker', readonly: 'readonly' } = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, required: true, hint: markdown_hint = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/tracks/index.html.haml b/app/views/tracks/index.html.haml index 7e16304f..fd1235d4 100644 --- a/app/views/tracks/index.html.haml +++ b/app/views/tracks/index.html.haml @@ -16,6 +16,8 @@ %th Description %th Color %th State + %th Start Date + %th End Date %th Actions %tbody - @tracks.each do |track| @@ -34,10 +36,31 @@ %td = track.state.humanize %td - = link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track), - method: :get, class: 'btn btn-primary' + - if track.start_date + = track.start_date.strftime('%A, %B %-d. %Y') + - else + N/A + %td + - if track.end_date + = track.end_date.strftime('%A, %B %-d. %Y') + - else + N/A + %td + - if track.transition_possible? :confirm + = link_to 'Confirm', confirm_conference_program_track_path(@conference.short_title, track), + method: :patch, class: 'btn btn-mini btn-success', id: "confirm_track_#{track.id}" + - if track.transition_possible? :withdraw + = link_to 'Withdraw', withdraw_conference_program_track_path(@conference.short_title, track), + method: :patch, data: { confirm: 'Are you sure you want to withdraw this track request?' }, + class: 'btn btn-mini btn-warning', id: "withdraw_track_request_#{track.id}" + - if track.transition_possible? :restart + = link_to 'Re-Submit', restart_conference_program_track_path(@conference.short_title, track), + method: :patch, class: 'btn btn-mini btn-success', id: "resubmit_track_request_#{track.id}" + - if can? :edit, track + = link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track), + method: :get, class: 'btn btn-primary' .row .col-md-12 - - if can? :create, @track + - if can? :new, @program.tracks.new = link_to "New Track request", new_conference_program_track_path(@conference.short_title), class: 'btn btn-success pull-right' diff --git a/app/views/tracks/show.html.haml b/app/views/tracks/show.html.haml index 37c180ae..c5bc27e5 100644 --- a/app/views/tracks/show.html.haml +++ b/app/views/tracks/show.html.haml @@ -17,10 +17,25 @@ State: %dd = @track.state.humanize + %dt + Start date: + %dd + - if @track.start_date + = @track.start_date.strftime('%A, %B %-d. %Y') + - else + N/A + %dt + End date: + %dd + - if @track.end_date + = @track.end_date.strftime('%A, %B %-d. %Y') + - else + N/A %dt Description %dd = @track.description .row .col-md-12.text-right - = link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-primary' + - if can? :edit, @track + = link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-primary' diff --git a/config/routes.rb b/config/routes.rb index be507d35..d4d6d0ee 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -69,6 +69,13 @@ Osem::Application.routes.draw do resources :tracks do member do patch :toggle_cfp_inclusion + patch :restart + patch :to_accept + patch :accept + patch :confirm + patch :to_reject + patch :reject + patch :cancel end end resources :event_types @@ -149,7 +156,13 @@ Osem::Application.routes.draw do patch '/restart' => 'proposals#restart' end end - resources :tracks, except: :destroy + resources :tracks, except: :destroy do + member do + patch :restart + patch :confirm + patch :withdraw + end + end end # TODO: change conference_registrations to singular resource diff --git a/db/migrate/20170720134353_make_track_cfp_active_not_null.rb b/db/migrate/20170720134353_make_track_cfp_active_not_null.rb new file mode 100644 index 00000000..0f75d046 --- /dev/null +++ b/db/migrate/20170720134353_make_track_cfp_active_not_null.rb @@ -0,0 +1,14 @@ +class MakeTrackCfpActiveNotNull < ActiveRecord::Migration + class TmpTrack < ActiveRecord::Base + self.table_name = 'tracks' + end + + def change + TmpTrack.where(cfp_active: nil).each do |track| + track.cfp_active = true + track.save! + end + + change_column_null :tracks, :cfp_active, false + end +end diff --git a/db/schema.rb b/db/schema.rb index aa2f160d..f8cc3ddc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -520,7 +520,7 @@ ActiveRecord::Schema.define(version: 20170807092805) do t.integer "program_id" t.string "short_name", null: false t.string "state", default: "new", null: false - t.boolean "cfp_active" + t.boolean "cfp_active", null: false t.integer "submitter_id" t.integer "room_id" t.date "start_date" diff --git a/spec/controllers/admin/tracks_controller_spec.rb b/spec/controllers/admin/tracks_controller_spec.rb index ed76fe68..70ca48a1 100644 --- a/spec/controllers/admin/tracks_controller_spec.rb +++ b/spec/controllers/admin/tracks_controller_spec.rb @@ -5,7 +5,7 @@ describe Admin::TracksController do let(:conference) { create(:conference) } let!(:track) { create(:track, program: conference.program, color: '#800080') } - let!(:self_organized_track) { create(:track, :self_organized, program: conference.program) } + let!(:self_organized_track) { create(:track, :self_organized, program: conference.program, name: 'My awesome track') } before :each do sign_in(admin) @@ -83,6 +83,7 @@ describe Admin::TracksController do it 'the new tracks has the correct attributes' do expect(assigns(:track).state).to eq 'confirmed' + expect(assigns(:track).cfp_active).to eq true end end @@ -257,4 +258,204 @@ describe Admin::TracksController do end end end + + describe 'PATCH #restart' do + before :each do + self_organized_track.state = 'canceled' + self_organized_track.save! + patch :restart, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows message in flash notice' do + expect(flash[:notice]).to eq 'Review for My awesome track started!' + end + + it 'changes the track\'s state to new' do + expect(self_organized_track.state).to eq 'new' + end + end + + describe 'PATCH #to_accept' do + before :each do + patch :to_accept, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows message in flash notice' do + expect(flash[:notice]).to eq 'Track My awesome track marked as a possible acceptance!' + end + + it 'changes the track\'s state to to_accept' do + expect(self_organized_track.state).to eq 'to_accept' + end + end + + describe 'PATCH #accept' do + shared_examples 'fails to accept' do |start_date, end_date, room| + before :each do + self_organized_track.start_date = start_date ? Date.today : nil + self_organized_track.end_date = end_date ? Date.today : nil + if room + conference.venue = create(:venue) + self_organized_track.room = create(:room, venue: conference.venue) + else + self_organized_track.room = nil + end + self_organized_track.save! + + patch :accept, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'redirects to Tracks#edit' do + expect(response).to redirect_to edit_admin_conference_program_track_path(conference.short_title, self_organized_track) + end + + it 'shows message in flash alert' do + expect(flash[:alert]).to eq 'Please make sure that the track has a room and start/end dates before accepting it' + end + end + + context 'has start_date, end_date and room' do + before :each do + self_organized_track.start_date = Date.today + self_organized_track.end_date = Date.today + conference.venue = create(:venue) + self_organized_track.room = create(:room, venue: conference.venue) + self_organized_track.save! + + patch :accept, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows message in flash notice' do + expect(flash[:notice]).to eq 'Track My awesome track accepted!' + end + + it 'changes the track\'s state to accepted' do + expect(self_organized_track.state).to eq 'accepted' + end + end + + context 'has start_date and end_date' do + it_behaves_like 'fails to accept', true, true, false + end + + context 'has start_date and room' do + it_behaves_like 'fails to accept', true, false, true + end + + context 'has start_date' do + it_behaves_like 'fails to accept', true, false, false + end + + context 'has end_date and room' do + it_behaves_like 'fails to accept', false, true, true + end + + context 'has end_date' do + it_behaves_like 'fails to accept', false, true, false + end + + context 'has room' do + it_behaves_like 'fails to accept', false, false, true + end + + context 'has non of start_date, end_date, room' do + it_behaves_like 'fails to accept', false, false, false + end + end + + describe 'PATCH #confirm' do + before :each do + self_organized_track.state = 'accepted' + self_organized_track.save! + patch :confirm, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows message in flash notice' do + expect(flash[:notice]).to eq 'Track My awesome track confirmed!' + end + + it 'changes the track\'s state to confirmed' do + expect(self_organized_track.state).to eq 'confirmed' + end + end + + describe 'PATCH #to_reject' do + before :each do + patch :to_reject, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows message in flash notice' do + expect(flash[:notice]).to eq 'Track My awesome track marked as a possible rejection!' + end + + it 'changes the track\'s state to to_reject' do + expect(self_organized_track.state).to eq 'to_reject' + end + end + + describe 'PATCH #reject' do + before :each do + patch :reject, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows message in flash notice' do + expect(flash[:notice]).to eq 'Track My awesome track rejected!' + end + + it 'changes the track\'s state to rejected' do + expect(self_organized_track.state).to eq 'rejected' + end + end + + describe 'PATCH #cancel' do + before :each do + self_organized_track.state = 'confirmed' + self_organized_track.save! + patch :cancel, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows message in flash notice' do + expect(flash[:notice]).to eq 'Track My awesome track canceled!' + end + + it 'changes the track\'s state to canceled' do + expect(self_organized_track.state).to eq 'canceled' + end + end end diff --git a/spec/controllers/tracks_controller_spec.rb b/spec/controllers/tracks_controller_spec.rb index 373435c2..0e3a0553 100644 --- a/spec/controllers/tracks_controller_spec.rb +++ b/spec/controllers/tracks_controller_spec.rb @@ -1,12 +1,11 @@ require 'spec_helper' describe TracksController do - # A regular user should be used when the track requests have been enabled let(:user) { create(:admin) } let(:conference) { create(:conference) } let!(:regular_track) { create(:track, program: conference.program) } - let!(:self_organized_track) { create(:track, :self_organized, program: conference.program, submitter: user, color: '#800080') } + let!(:self_organized_track) { create(:track, :self_organized, program: conference.program, submitter: user, name: 'My awesome track', color: '#800080') } before :each do sign_in(user) @@ -176,4 +175,67 @@ describe TracksController do end end end + + describe 'PATCH #restart' do + before :each do + self_organized_track.state = 'withdrawn' + self_organized_track.save! + patch :restart, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows message in flash notice' do + expect(flash[:notice]).to eq 'Track My awesome track re-submitted.' + end + + it 'changes the track\'s state to new' do + expect(self_organized_track.state).to eq 'new' + end + end + + describe 'PATCH #confirm' do + before :each do + self_organized_track.state = 'accepted' + self_organized_track.save! + patch :confirm, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows message in flash notice' do + expect(flash[:notice]).to eq 'Track My awesome track confirmed.' + end + + it 'changes the track\'s state to confirmed' do + expect(self_organized_track.state).to eq 'confirmed' + end + end + + describe 'PATCH #withdraw' do + before :each do + self_organized_track.state = 'confirmed' + self_organized_track.save! + patch :withdraw, conference_id: conference.short_title, id: self_organized_track.short_name + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows message in flash notice' do + expect(flash[:notice]).to eq 'Track My awesome track withdrawn.' + end + + it 'changes the track\'s state to withdrawn' do + expect(self_organized_track.state).to eq 'withdrawn' + end + end end diff --git a/spec/factories/tracks.rb b/spec/factories/tracks.rb index d30a686e..d61c9a1b 100644 --- a/spec/factories/tracks.rb +++ b/spec/factories/tracks.rb @@ -5,12 +5,16 @@ FactoryGirl.define do color { Faker::Color.hex_color } short_name { SecureRandom.urlsafe_base64(5) } state 'confirmed' + cfp_active true program trait :self_organized do association :submitter, factory: :user state 'new' cfp_active false + start_date { Date.today } + end_date { Date.today } + room end end end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 2144cec6..ff3f14cb 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -26,6 +26,7 @@ describe 'User' do let(:program_with_cfp) { create(:program, :with_cfp) } let(:program_without_cfp) { create(:program) } + let(:program_with_call_for_tracks) { create(:cfp, cfp_type: 'tracks').program } let(:conference_with_open_registration) { create(:conference) } let!(:open_registration_period) { create(:registration_period, conference: conference_with_open_registration, start_date: Date.current - 6.days) } let(:conference_with_closed_registration) { create(:conference) } @@ -82,6 +83,10 @@ describe 'User' do let(:user_event_with_cfp) { create(:event, users: [user], program: program_with_cfp) } let(:user_commercial) { create(:commercial, commercialable: user_event_with_cfp) } + let(:user_self_organized_track) { create(:track, :self_organized, submitter: user) } + let(:accepted_user_self_organized_track) { create(:track, :self_organized, submitter: user, state: 'accepted') } + let(:confirmed_user_self_organized_track) { create(:track, :self_organized, submitter: user, state: 'confirmed') } + let(:other_self_organized_track) { create(:track, :self_organized) } it{ should be_able_to(:manage, user) } @@ -114,6 +119,31 @@ describe 'User' do it{ should be_able_to(:create, user_event_with_cfp.commercials.new) } it{ should be_able_to(:manage, user_commercial) } it{ should_not be_able_to(:manage, commercial_event_unconfirmed) } + + it{ should be_able_to(:new, Track.new(program: program_with_call_for_tracks)) } + it{ should be_able_to(:create, Track.new(program: program_with_call_for_tracks)) } + it{ should_not be_able_to(:new, Track.new(program: program_without_cfp)) } + it{ should_not be_able_to(:create, Track.new(program: program_without_cfp)) } + + it{ should be_able_to(:index, user_self_organized_track) } + it{ should be_able_to(:show, user_self_organized_track) } + it{ should be_able_to(:restart, user_self_organized_track) } + it{ should be_able_to(:confirm, user_self_organized_track) } + it{ should be_able_to(:withdraw, user_self_organized_track) } + it{ should_not be_able_to(:index, other_self_organized_track) } + it{ should_not be_able_to(:show, other_self_organized_track) } + it{ should_not be_able_to(:restart, other_self_organized_track) } + it{ should_not be_able_to(:confirm, other_self_organized_track) } + it{ should_not be_able_to(:withdraw, other_self_organized_track) } + + it{ should be_able_to(:edit, user_self_organized_track) } + it{ should be_able_to(:update, user_self_organized_track) } + it{ should_not be_able_to(:edit, accepted_user_self_organized_track) } + it{ should_not be_able_to(:update, accepted_user_self_organized_track) } + it{ should_not be_able_to(:edit, confirmed_user_self_organized_track) } + it{ should_not be_able_to(:update, confirmed_user_self_organized_track) } + it{ should_not be_able_to(:edit, other_self_organized_track) } + it{ should_not be_able_to(:update, other_self_organized_track) } end end end diff --git a/spec/models/admin_ability_spec.rb b/spec/models/admin_ability_spec.rb index 16456a19..126d32de 100644 --- a/spec/models/admin_ability_spec.rb +++ b/spec/models/admin_ability_spec.rb @@ -44,7 +44,7 @@ describe 'User with admin role' do let!(:my_event_schedule) { create(:event_schedule, schedule: my_schedule) } let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) } - let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program) } + let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program, state: 'confirmed') } context 'user #is_admin?' do let(:venue) { my_conference.venue } @@ -505,6 +505,8 @@ describe 'User with admin role' do it{ should be_able_to(:show, my_conference.program) } it{ should be_able_to(:update, new_track) } it{ should be_able_to(:manage, my_self_organized_track) } + it{ should_not be_able_to(:edit, my_self_organized_track) } + it{ should_not be_able_to(:update, my_self_organized_track) } it_behaves_like 'user with any role' it_behaves_like 'user with non-organizer role', 'track_organizer' diff --git a/spec/models/conference_spec.rb b/spec/models/conference_spec.rb index 91c06140..26070134 100755 --- a/spec/models/conference_spec.rb +++ b/spec/models/conference_spec.rb @@ -606,8 +606,8 @@ describe Conference do describe 'tracks_distribution' do before do subject.email_settings = create(:email_settings) - @track_one = create(:track, name: 'Track One', color: '#000000') - @track_two = create(:track, name: 'Track Two', color: '#ffffff') + @track_one = create(:track, name: 'Track One', color: '#000000', program: subject.program) + @track_two = create(:track, name: 'Track Two', color: '#ffffff', program: subject.program) end describe '#tracks_distribution' do diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index b723d151..3ada61ca 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -96,6 +96,40 @@ describe Event do end end end + + describe '#acceptable_track' do + context 'is valid' do + it 'when the track belong to the same program, is confirmed and is included in the cfp' do + track = create(:track, state: 'confirmed', cfp_active: true, program: conference.program) + event = build(:event, program: conference.program, track: track) + expect(event.valid?).to eq true + end + end + + context 'is invalid' do + it 'when the track doesn\'t have the same program' do + track = create(:track, state: 'confirmed', cfp_active: true) + event = build(:event, program: conference.program, track: track) + expect(event.valid?).to eq false + expect(event.errors[:track]).to eq ['is invalid'] + end + + it 'when the track is unconfirmed' do + track = create(:track, cfp_active: true, program: conference.program) + allow(track).to receive(:confirmed?).and_return(false) + event = build(:event, program: conference.program, track: track) + expect(event.valid?).to eq false + expect(event.errors[:track]).to eq ['is invalid'] + end + + it 'when the track isn\'t included in the cfp' do + track = create(:track, state: 'confirmed', cfp_active: false, program: conference.program) + event = build(:event, program: conference.program, track: track) + expect(event.valid?).to eq false + expect(event.errors[:track]).to eq ['is invalid'] + end + end + end end describe '#comments_count' do diff --git a/spec/models/track_spec.rb b/spec/models/track_spec.rb index 840641cb..4853f31d 100644 --- a/spec/models/track_spec.rb +++ b/spec/models/track_spec.rb @@ -8,6 +8,7 @@ describe Track do describe 'association' do it { is_expected.to belong_to(:program) } it { is_expected.to belong_to(:submitter).class_name('User') } + it { is_expected.to belong_to(:room) } it { is_expected.to have_many(:events) } end @@ -23,23 +24,99 @@ describe Track do it { is_expected.to allow_value('My_track_name').for(:short_name) } it { is_expected.to_not allow_value('My track name').for(:short_name) } it { is_expected.to validate_uniqueness_of(:short_name).scoped_to(:program_id) } + it { is_expected.to validate_presence_of(:state) } + it { is_expected.to validate_inclusion_of(:state).in_array(%w[new to_accept accepted confirmed to_reject rejected canceled withdrawn]) } + it { is_expected.to validate_inclusion_of(:cfp_active).in_array([true, false]) } - context 'when self-organized' do + context 'when self_organized_and_accepted_or_confirmed? returns true' do before :each do - allow(subject).to receive(:self_organized?).and_return(true) + allow(subject).to receive(:self_organized_and_accepted_or_confirmed?).and_return(true) end - it { is_expected.to validate_presence_of(:state) } - it { is_expected.to validate_inclusion_of(:cfp_active).in_array([true, false]) } + it { is_expected.to validate_presence_of(:start_date) } + it { is_expected.to validate_presence_of(:end_date) } + it { is_expected.to validate_presence_of(:room) } end - context 'when regular' do + context 'when self_organized_and_accepted_or_confirmed? returns false' do before :each do - allow(subject).to receive(:self_organized?).and_return(false) + allow(subject).to receive(:self_organized_and_accepted_or_confirmed?).and_return(false) end - it { is_expected.to_not validate_presence_of(:state) } - it { is_expected.to_not validate_inclusion_of(:cfp_active) } + it { is_expected.to_not validate_presence_of(:start_date) } + it { is_expected.to_not validate_presence_of(:end_date) } + it { is_expected.to_not validate_presence_of(:room) } + end + + describe '#valid_dates' do + before :each do + @conference = create(:conference, start_date: 1.day.ago, end_date: 2.days.from_now) + end + + context 'is valid' do + it 'when the track\'s start date is before it\'s end date and between the conference start/end dates' do + track = build(:track, start_date: Date.today, end_date: Date.tomorrow, program: @conference.program) + expect(track.valid?).to eq true + end + end + + context 'is invalid' do + it 'when the track\'s start date is before the conference\'s start date' do + track = build(:track, start_date: 2.days.ago, end_date: Date.tomorrow, program: @conference.program) + expect(track.valid?).to eq false + expect(track.errors[:start_date]).to eq ["can't be before the conference start date (#{1.day.ago.to_date})"] + end + + it 'when the track\'s end date is before the conference\'s start date' do + track = build(:track, start_date: 3.days.ago, end_date: 2.days.ago, program: @conference.program) + expect(track.valid?).to eq false + expect(track.errors[:end_date]).to eq ["can't be before the conference start date (#{1.day.ago.to_date})"] + end + + it 'when the track\'s start date is after the conference\'s end date' do + track = build(:track, start_date: 3.days.from_now, end_date: 4.days.from_now, program: @conference.program) + expect(track.valid?).to eq false + expect(track.errors[:start_date]).to eq ["can't be after the conference end date (#{2.days.from_now.to_date})"] + end + + it 'when the track\'s end date is after the conference\'s end date' do + track = build(:track, start_date: Date.today, end_date: 3.days.from_now, program: @conference.program) + expect(track.valid?).to eq false + expect(track.errors[:end_date]).to eq ["can't be after the conference end date (#{2.days.from_now.to_date})"] + end + + it 'when the track\'s start date is after it\'s end date' do + track = build(:track, start_date: 1.day.from_now, end_date: 1.day.ago) + expect(track.valid?).to eq false + expect(track.errors[:start_date]).to eq ['can\'t be after the end date'] + end + end + end + + describe '#valid_room' do + before :each do + @conference = create(:conference) + @conference.venue = create(:venue, name: 'The venue') + end + + context 'is valid' do + it 'when the track\'s room belongs to the venue of the conference' do + room = create(:room, venue: @conference.venue) + track = build(:track, :self_organized, state: 'accepted', program: @conference.program, room: room) + expect(track.valid?).to eq true + end + end + + context 'is invalid' do + it 'when the track\'s room doesn\'t belong to the venue of the track\'s conference' do + other_conference = create(:conference) + other_conference.venue = create(:venue) + room = create(:room, venue: other_conference.venue) + track = build(:track, :self_organized, state: 'accepted', program: @conference.program, room: room) + expect(track.valid?).to eq false + expect(track.errors[:room]).to eq ['must be a room of The venue'] + end + end end end @@ -54,4 +131,226 @@ describe Track do expect(track.self_organized?).to eq false end end + + describe '#transition_possible?' do + shared_examples 'transition_possible?' do |state, transition, expected| + it "returns #{expected} for #{transition} event, when the track's state is #{state}}" do + my_self_organized_track = create(:track, :self_organized, state: state) + expect(my_self_organized_track.transition_possible?(transition.to_sym)).to eq expected + end + end + + states = [:new, :to_accept, :accepted, :confirmed, :to_reject, :rejected, :canceled, :withdrawn] + transitions = [:restart, :to_accept, :accept, :confirm, :to_reject, :reject, :cancel, :withdraw] + + states_transitions = { new: { restart: false, to_accept: true, accept: true, confirm: false, to_reject: true, reject: true, cancel: false, withdraw: true }, + to_accept: { restart: false, to_accept: false, accept: true, confirm: false, to_reject: false, reject: false, cancel: true, withdraw: true }, + accepted: { restart: false, to_accept: false, accept: false, confirm: true, to_reject: false, reject: false, cancel: true, withdraw: true }, + confirmed: { restart: false, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: true, withdraw: true }, + to_reject: { restart: false, to_accept: false, accept: false, confirm: false, to_reject: false, reject: true, cancel: true, withdraw: true }, + rejected: { restart: true, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: false, withdraw: false }, + canceled: { restart: true, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: false, withdraw: false }, + withdrawn: { restart: true, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: false, withdraw: false } } + + states.each do |state| + transitions.each do |transition| + it_behaves_like 'transition_possible?', state, transition, states_transitions[state.to_sym][transition.to_sym] + end + end + end + + describe '#assign_role_to_submitter' do + before :each do + Role.where(name: 'track_organizer', resource: self_organized_track).first_or_create + @submitter = self_organized_track.submitter + end + + it 'gives the role of the track organizer to the submitter of the track' do + expect(@submitter.has_role?(:track_organizer, self_organized_track)).to eq false + self_organized_track.assign_role_to_submitter + expect(@submitter.has_role?(:track_organizer, self_organized_track)).to eq true + end + + it 'is executed when the track is confirmed' do + self_organized_track.state = 'accepted' + self_organized_track.save! + expect(@submitter.has_role?(:track_organizer, self_organized_track)).to eq false + self_organized_track.confirm + expect(@submitter.has_role?(:track_organizer, self_organized_track)).to eq true + end + end + + describe '#revoke_role_and_cleanup' do + before :each do + Role.where(name: 'track_organizer', resource: self_organized_track).first_or_create + @a_track_organizer = create(:user) + self_organized_track.state = 'confirmed' + self_organized_track.cfp_active = true + self_organized_track.save! + @a_track_organizer.add_role 'track_organizer', self_organized_track + @an_event_of_the_track = create(:event, program: self_organized_track.program, track: self_organized_track) + end + + it 'revokes the role of the track organizer' do + expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq true + self_organized_track.revoke_role_and_cleanup + expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false + end + + it 'removes the track from the events that have it set' do + expect(@an_event_of_the_track.track).to eq self_organized_track + self_organized_track.revoke_role_and_cleanup + @an_event_of_the_track.reload + expect(@an_event_of_the_track.track).to eq nil + end + + it 'is executed when the track is canceled' do + self_organized_track.state = 'confirmed' + self_organized_track.save! + self_organized_track.cancel + expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false + @an_event_of_the_track.reload + expect(@an_event_of_the_track.track).to eq nil + end + + it 'is executed when the track is withdrawn' do + self_organized_track.withdraw + expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false + @an_event_of_the_track.reload + expect(@an_event_of_the_track.track).to eq nil + end + end + + describe '#accepted?' do + context 'returns true' do + it 'when the state is "accepted"' do + self_organized_track.state = 'accepted' + self_organized_track.save! + expect(self_organized_track.accepted?).to eq true + end + end + + context 'returns false' do + %w[new to_accept confirmed to_reject rejected canceled withdrawn].each do |state| + it "when the state is \"#{state}\"" do + self_organized_track.state = state + self_organized_track.save! + expect(self_organized_track.accepted?).to eq false + end + end + end + end + + describe '#confirmed?' do + context 'returns true' do + it 'when the state is "confirmed"' do + self_organized_track.state = 'confirmed' + self_organized_track.save! + expect(self_organized_track.confirmed?).to eq true + end + end + + context 'returns false' do + %w[new to_accept accepted to_reject rejected canceled withdrawn].each do |state| + it "when the state is \"#{state}\"" do + self_organized_track.state = state + self_organized_track.save! + expect(self_organized_track.confirmed?).to eq false + end + end + end + end + + # accepted? and confirmed? are mutually exclusive (they can't be both true) + describe '#self_organized_and_accepted_or_confirmed?' do + context 'returns true' do + context 'when self_organized? returns true' do + before :each do + allow(track).to receive(:self_organized?).and_return(true) + end + + context 'accepted? returns true and confirmed? returns false' do + before :each do + allow(track).to receive(:accepted?).and_return(true) + allow(track).to receive(:confirmed?).and_return(false) + end + + it { expect(track.self_organized_and_accepted_or_confirmed?).to eq true } + end + + context 'accepted? returns false and confirmed? returns true' do + before :each do + allow(track).to receive(:accepted?).and_return(false) + allow(track).to receive(:confirmed?).and_return(true) + end + + it { expect(track.self_organized_and_accepted_or_confirmed?).to eq true } + end + end + end + + context 'returns false' do + context 'when self_organized? returns true' do + before :each do + allow(track).to receive(:self_organized?).and_return(true) + end + + context 'accepted? returns false and confirmed? returns false' do + before :each do + allow(track).to receive(:accepted?).and_return(false) + allow(track).to receive(:confirmed?).and_return(false) + end + + it { expect(track.self_organized_and_accepted_or_confirmed?).to eq false } + end + end + + context 'when self_organized? returns false' do + before :each do + allow(track).to receive(:self_organized?).and_return(false) + end + + context 'accepted? returns false and confirmed? returns false' do + before :each do + allow(track).to receive(:accepted?).and_return(false) + allow(track).to receive(:confirmed?).and_return(false) + end + + it { expect(track.self_organized_and_accepted_or_confirmed?).to eq false } + end + + context 'accepted? returns true and confirmed? returns false' do + before :each do + allow(track).to receive(:accepted?).and_return(true) + allow(track).to receive(:confirmed?).and_return(false) + end + + it { expect(track.self_organized_and_accepted_or_confirmed?).to eq false } + end + + context 'accepted? returns false and confirmed? returns true' do + before :each do + allow(track).to receive(:accepted?).and_return(false) + allow(track).to receive(:confirmed?).and_return(true) + end + + it { expect(track.self_organized_and_accepted_or_confirmed?).to eq false } + end + end + end + end + + describe '#create_organizer_role' do + it 'creates the role of the track organizer' do + expect(Role.find_by(name: 'track_organizer', resource: self_organized_track)).to eq nil + self_organized_track.send(:create_organizer_role) + expect(Role.find_by(name: 'track_organizer', resource: self_organized_track).description).to eq 'For the organizers of the Track' + end + + it 'is executed when the track is accepted' do + expect(Role.find_by(name: 'track_organizer', resource: self_organized_track)).to eq nil + self_organized_track.accept + expect(Role.find_by(name: 'track_organizer', resource: self_organized_track).description).to eq 'For the organizers of the Track' + end + end end From f9903eba16e4ff807d484874939971a7d0cddf59 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Sun, 16 Jul 2017 20:29:03 +0300 Subject: [PATCH 156/237] Change Cfp scopes to class methods When no record matches the requested criteria a scope will return all the records In this case, if no record can be found we want the result to be nil Also, make some readability fixes in specs --- app/models/cfp.rb | 21 ++++++++++-- spec/features/cfp_ability_spec.rb | 12 +++---- .../organization_admin_ability_spec.rb | 12 +++---- spec/features/organizer_ability_spec.rb | 12 +++---- spec/models/cfp_spec.rb | 32 +++++++++++++------ 5 files changed, 59 insertions(+), 30 deletions(-) diff --git a/app/models/cfp.rb b/app/models/cfp.rb index 44d8281b..8248cd1a 100644 --- a/app/models/cfp.rb +++ b/app/models/cfp.rb @@ -3,9 +3,6 @@ class Cfp < ActiveRecord::Base TYPES = %w(events booths tracks).freeze - scope :for_events, (-> { find_by(cfp_type: 'events') }) - scope :for_tracks, (-> { find_by(cfp_type: 'tracks') }) - has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id } belongs_to :program @@ -79,6 +76,24 @@ class Cfp < ActiveRecord::Base (start_date..end_date).cover?(Date.current) end + ## + # Finds the cfp for events if it exists + # + # ====Returns + # * +Cfp+ -> The cfp with type 'events' + def self.for_events + find_by(cfp_type: 'events') + end + + ## + # Finds the cfp for tracks if it exists + # + # ====Returns + # * +Cfp+ -> The cfp with type 'tracks' + def self.for_tracks + find_by(cfp_type: 'tracks') + end + private def before_end_of_conference diff --git a/spec/features/cfp_ability_spec.rb b/spec/features/cfp_ability_spec.rb index cd9fa3bd..1607401c 100644 --- a/spec/features/cfp_ability_spec.rb +++ b/spec/features/cfp_ability_spec.rb @@ -73,7 +73,7 @@ feature 'Has correct abilities' do expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) # Event, booth, track cfps exist - cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + call_for_tracks = create(:cfp, cfp_type: 'tracks', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq root_path @@ -83,7 +83,7 @@ feature 'Has correct abilities' do expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) # Only booth exists - cft.destroy! + call_for_tracks.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) @@ -96,19 +96,19 @@ feature 'Has correct abilities' do expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) # Only Tracks cfp exists - cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + call_for_tracks = create(:cfp, cfp_type: 'tracks', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) - visit edit_admin_conference_program_cfp_path(conference.short_title, cft) - expect(current_path).to eq edit_admin_conference_program_cfp_path(conference.short_title, cft) + visit edit_admin_conference_program_cfp_path(conference.short_title, call_for_tracks) + expect(current_path).to eq edit_admin_conference_program_cfp_path(conference.short_title, call_for_tracks) # Event and track cfps exist create(:cfp, cfp_type: 'events', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) - cft.destroy! + call_for_tracks.destroy! create(:event, program: conference.program) visit edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first) expect(current_path).to eq(edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first)) diff --git a/spec/features/organization_admin_ability_spec.rb b/spec/features/organization_admin_ability_spec.rb index 12fd038b..8bccd2cf 100644 --- a/spec/features/organization_admin_ability_spec.rb +++ b/spec/features/organization_admin_ability_spec.rb @@ -115,7 +115,7 @@ feature 'Has correct abilities' do expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) # Event, booth, track cfps exist - cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + call_for_tracks = create(:cfp, cfp_type: 'tracks', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq root_path @@ -125,7 +125,7 @@ feature 'Has correct abilities' do expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) # Only booth exists - cft.destroy! + call_for_tracks.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) @@ -138,19 +138,19 @@ feature 'Has correct abilities' do expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) # Only Tracks cfp exists - cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + call_for_tracks = create(:cfp, cfp_type: 'tracks', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) - visit edit_admin_conference_program_cfp_path(conference.short_title, cft) - expect(current_path).to eq edit_admin_conference_program_cfp_path(conference.short_title, cft) + visit edit_admin_conference_program_cfp_path(conference.short_title, call_for_tracks) + expect(current_path).to eq edit_admin_conference_program_cfp_path(conference.short_title, call_for_tracks) # Event and track cfps exist create(:cfp, cfp_type: 'events', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) - cft.destroy! + call_for_tracks.destroy! visit admin_conference_program_events_path(conference.short_title) expect(current_path).to eq(admin_conference_program_events_path(conference.short_title)) diff --git a/spec/features/organizer_ability_spec.rb b/spec/features/organizer_ability_spec.rb index ef2b3744..5345b58c 100644 --- a/spec/features/organizer_ability_spec.rb +++ b/spec/features/organizer_ability_spec.rb @@ -121,7 +121,7 @@ feature 'Has correct abilities' do expect(current_path).to eq(edit_admin_conference_program_cfp_path(conference.short_title, conference.program.cfp)) # Event, booth, track cfps exist - cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + call_for_tracks = create(:cfp, cfp_type: 'tracks', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq root_path @@ -131,7 +131,7 @@ feature 'Has correct abilities' do expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) # Only booth exists - cft.destroy! + call_for_tracks.destroy! visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) @@ -144,19 +144,19 @@ feature 'Has correct abilities' do expect(current_path).to eq(new_admin_conference_program_cfp_path(conference.short_title)) # Only Tracks cfp exists - cft = create(:cfp, cfp_type: 'tracks', program: conference.program) + call_for_tracks = create(:cfp, cfp_type: 'tracks', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) - visit edit_admin_conference_program_cfp_path(conference.short_title, cft) - expect(current_path).to eq edit_admin_conference_program_cfp_path(conference.short_title, cft) + visit edit_admin_conference_program_cfp_path(conference.short_title, call_for_tracks) + expect(current_path).to eq edit_admin_conference_program_cfp_path(conference.short_title, call_for_tracks) # Event and track cfps exist create(:cfp, cfp_type: 'events', program: conference.program) visit new_admin_conference_program_cfp_path(conference.short_title) expect(current_path).to eq new_admin_conference_program_cfp_path(conference.short_title) - cft.destroy! + call_for_tracks.destroy! visit admin_conference_program_events_path(conference.short_title) expect(current_path).to eq(admin_conference_program_events_path(conference.short_title)) diff --git a/spec/models/cfp_spec.rb b/spec/models/cfp_spec.rb index 606f5f9f..95607491 100644 --- a/spec/models/cfp_spec.rb +++ b/spec/models/cfp_spec.rb @@ -5,21 +5,35 @@ describe Cfp do let!(:conference) { create(:conference, end_date: Date.today) } let!(:cfp) { create(:cfp, start_date: Date.today - 2, end_date: Date.today - 1, program_id: conference.program.id) } - describe 'scope' do - describe '#for_events' do - it 'returns the cfp for events' do - expect(conference.program.cfps.for_events).to be_a Cfp - expect(conference.program.cfps.for_events.cfp_type).to eq('events') - end - end - end - describe 'validations' do it { is_expected.to validate_presence_of(:cfp_type) } it { is_expected.to validate_inclusion_of(:cfp_type).in_array(Cfp::TYPES) } it { is_expected.to validate_uniqueness_of(:cfp_type).scoped_to(:program_id).case_insensitive } end + describe '.for_events' do + it 'returns the cfp for events when it exists' do + expect(conference.program.cfps.for_events).to be_a Cfp + expect(conference.program.cfps.for_events.cfp_type).to eq('events') + end + + it 'returns nil when the cfp for events doesn\'t exist' do + conference.program.cfp.destroy + expect(conference.program.cfps.for_events).to eq nil + end + end + + describe '.for_tracks' do + it 'returns the cfp for tracks when it exists' do + call_for_tracks = create(:cfp, cfp_type: 'tracks', program: conference.program, end_date: Date.today) + expect(conference.program.cfps.for_tracks).to eq call_for_tracks + end + + it 'returns nil when the cfp for tracks doesn\'t exist' do + expect(conference.program.cfps.for_tracks).to eq nil + end + end + describe '#before_end_of_conference' do describe 'fails to save cfp' do it 'when cfp end_date is after conference end_date' do From 3d250ecf753c25a9968c642a248777f88876058a Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 19 Jul 2017 18:28:57 +0300 Subject: [PATCH 157/237] UI/UX changes related to tracks Add confirmed and cfp_active scopes to Track Render markdown in track's description Make the views more similar to the proposal/events views Change the sequence of columns in admin/Tracks#index Remove the short_name column from the index views Add button "My Tracks" in the user menu Fix track count in proposals Add details of track in admin/Tracks#show Use tabs to show track details and events --- .haml-lint_todo.yml | 1 + app/controllers/admin/events_controller.rb | 6 +- app/helpers/application_helper.rb | 2 +- app/models/track.rb | 3 + app/views/admin/tracks/index.html.haml | 74 ++++------ app/views/admin/tracks/show.html.haml | 135 ++++++++++++++---- .../_schedule_splashpage.html.haml | 11 +- app/views/layouts/_user_menu.html.haml | 4 + .../proposals/_encouragement_text.html.haml | 2 +- app/views/tracks/_form.html.haml | 2 +- app/views/tracks/index.html.haml | 89 +++++++----- app/views/tracks/show.html.haml | 30 ++-- spec/features/tracks_spec.rb | 2 +- spec/models/track_spec.rb | 40 ++++++ 14 files changed, 269 insertions(+), 132 deletions(-) diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 89d18c3f..b7a18be0 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -182,6 +182,7 @@ linters: - "app/views/tracks/show.html.haml" - "app/views/conferences/_call_for_tracks.html.haml" - "app/views/admin/tracks/_change_state_dropdown.html.haml" + - "app/views/proposals/_encouragement_text.html.haml" # Offense count: 223 InstanceVariables: diff --git a/app/controllers/admin/events_controller.rb b/app/controllers/admin/events_controller.rb index 125d1ef1..1aa2e4bd 100644 --- a/app/controllers/admin/events_controller.rb +++ b/app/controllers/admin/events_controller.rb @@ -17,7 +17,7 @@ module Admin def index @events = @program.events - @tracks = @program.tracks + @tracks = @program.tracks.confirmed.cfp_active @difficulty_levels = @program.difficulty_levels @event_types = @program.event_types @tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed) @@ -43,7 +43,7 @@ module Admin end def show - @tracks = @program.tracks + @tracks = @program.tracks.confirmed.cfp_active @event_types = @program.event_types @comments = @event.root_comments @comment_count = @event.comment_threads.count @@ -58,7 +58,7 @@ module Admin def edit @event_types = @program.event_types - @tracks = Track.all + @tracks = @program.tracks.confirmed.cfp_active @comments = @event.root_comments @comment_count = @event.comment_threads.count @user = @event.submitter diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 040927c1..0c460f26 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -56,7 +56,7 @@ module ApplicationHelper end def tracks(conference) - all = conference.program.tracks.where(state: 'confirmed', cfp_active: true).pluck(:name) + all = conference.program.tracks.confirmed.cfp_active.pluck(:name) first = all[0...-1] last = all[-1] ts = '' diff --git a/app/models/track.rb b/app/models/track.rb index 3743cd79..5fb37549 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -32,6 +32,9 @@ class Track < ActiveRecord::Base before_validation :capitalize_color + scope :confirmed, -> { where(state: 'confirmed') } + scope :cfp_active, -> { where(cfp_active: true) } + state_machine initial: :pending do state :new state :to_accept diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 0cfe0ff2..5c47fe11 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -6,39 +6,46 @@ Categorize events in your conference .row .col-md-12 - %table.table.table-hover#tracks + %table.table.table-hover.table-striped.table-bordered.datatable#tracks %thead %th Name - %th Short name %th Description - %th Submitter - %th Color - %th State - %th Included in the Cfp %th Room %th Start Date %th End Date + %th Submitter + %th Included in Cfp + %th State %th Actions %tbody - @tracks.each do |track| %tr - %td - = link_to(admin_conference_program_track_path(@conference.short_title, track)) do - = track.name - %td - = track.short_name + %td{style: "padding: 15px 0px 0px 10px;"} + = link_to admin_conference_program_track_path(@conference.short_title, track), class: 'btn' do + %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} + = track.name %td %p - = truncate(track.description) + = markdown(truncate(track.description)) %td - - if track.self_organized? - = link_to track.submitter.name, admin_user_path(track.submitter) - - else - N/A + = track.room.try(:name) %td - %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} - = track.color + = track.start_date.strftime('%A, %B %-d. %Y') if track.start_date %td + = track.end_date.strftime('%A, %B %-d. %Y') if track.end_date + %td + = link_to track.submitter.name, admin_user_path(track.submitter) if track.self_organized? + %td.text-center + = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, + class: 'switch-checkbox', method: :patch, + url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.short_name)+"?included=", + data: { size: 'small', + on_color: 'success', + off_color: 'warning', + on_text: 'Yes', + off_text: 'No' } + + %td.text-center - if track.self_organized? .btn-group %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } @@ -48,39 +55,12 @@ = render 'change_state_dropdown', track: track - else = track.state.humanize - %td - = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, - class: 'switch-checkbox', method: :patch, - url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.short_name)+"?included=", - data: { size: 'small', - on_color: 'success', - off_color: 'warning', - on_text: 'Yes', - off_text: 'No' } - - %td - - if track.room - = link_to track.room.name, admin_conference_venue_room_path(@conference.short_title, track.room.id) - - else - N/A - %td - - if track.start_date - = track.start_date.strftime('%A, %B %-d. %Y') - - else - N/A - %td - - if track.end_date - = track.end_date.strftime('%A, %B %-d. %Y') - - else - N/A %td .btn-group{role: "group"} - if can? :edit, track - = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), - method: :get, class: 'btn btn-primary' + = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-primary' - if can? :destroy, track - = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), - method: :delete, class: 'btn btn-danger', + = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } .row .col-md-12.text-right diff --git a/app/views/admin/tracks/show.html.haml b/app/views/admin/tracks/show.html.haml index 3acb8471..5e45d3a5 100644 --- a/app/views/admin/tracks/show.html.haml +++ b/app/views/admin/tracks/show.html.haml @@ -4,27 +4,114 @@ %h1 = @track.name Track - %p.text-muted - Events in this track -.row - .col-md-12 - %table.table.table-hover.datatable - %thead - %th Title - %th Type - %th Submitter - %th State - %th Time - %tbody - - @track.events.each_with_index do |event| - %tr - %td - =link_to event.title, admin_conference_program_event_path(@conference.short_title, event) - %td - = event.event_type.title - %td - =link_to event.submitter.name, admin_user_path(event.submitter) - %td - = event.state - %td - = event.time + +.tabbable + %ul.nav.nav-tabs + %li.active + = link_to 'Details', '#details', 'data-toggle' => 'tab' + %li + = link_to 'Events', '#events', 'data-toggle' => 'tab' + + .tab-content + .tab-pane.active#details + .row + .col-md-12 + .btn-group.pull-right + - if can? :edit, @track + = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, @track), + method: :get, class: 'btn btn-primary' + - if can? :destroy, @track + = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, @track), + method: :delete, class: 'btn btn-danger', + data: { confirm: "Do you really want to delete #{@track.name}? Attention: This track will be removed from all Events that have it set" } + .row + .col-md-12 + %table.table + %tr + %td.col-md-2 + %b Color + %td + %span.label{ style: "background-color: #{@track.color}; color: #{ contrast_color(@track.color) }" } + = @track.color + %tr + %td + %b Room + %td + = @track.room.try(:name) + %tr + %td + %b Start date + %td + = @track.start_date.strftime('%A, %B %-d. %Y') if @track.start_date + %tr + %td + %b End date + %td + = @track.end_date.strftime('%A, %B %-d. %Y') if @track.end_date + - if @track.self_organized? + %tr + %td + %b Submitter + %td + = link_to @track.submitter.name, admin_user_path(@track.submitter) + - if @track.confirmed? + %tr + %td + %b Organizers + %td + - Role.find_by(name: 'track_organizer', resource: @track).users.each do |organizer| + %div + = link_to organizer.name, admin_user_path(organizer) + %tr + %td + %b Included in the Cfp? + %td + = check_box_tag "#{@conference.short_title}_#{@track.short_name}", @track.id, @track.cfp_active, + class: 'switch-checkbox', method: :patch, + url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: @track.short_name)+"?included=", + data: { size: 'small', + on_color: 'success', + off_color: 'warning', + on_text: 'Yes', + off_text: 'No' } + %tr + %td + %b State + %td + - if @track.self_organized? + .btn-group + %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } + = @track.state.humanize + %span.caret + %ul.dropdown-menu{ role: 'menu' } + = render 'change_state_dropdown', track: @track + - else + = @track.state.humanize + %tr + %td + %b Description + %td + = markdown(@track.description) + + .tab-pane#events + .col-md-12 + %table.table.table-hover.datatable + %thead + %th Title + %th Type + %th Submitter + %th State + %th Time + %tbody + - @track.events.each_with_index do |event| + %tr + %td + =link_to event.title, admin_conference_program_event_path(@conference.short_title, event) + %td + = event.event_type.title + %td + =link_to event.submitter.name, admin_user_path(event.submitter) + %td + = event.state + %td + = event.time diff --git a/app/views/conferences/_schedule_splashpage.html.haml b/app/views/conferences/_schedule_splashpage.html.haml index 67bd52e4..defd3e4d 100644 --- a/app/views/conferences/_schedule_splashpage.html.haml +++ b/app/views/conferences/_schedule_splashpage.html.haml @@ -10,13 +10,22 @@ - if @conference.splashpage and @conference.program.tracks.any? and @conference.splashpage.include_tracks See rock-star speakers cover the topics of - if @conference.splashpage and @conference.splashpage.include_tracks - - @conference.program.tracks.each_slice(3) do |slice| + - @conference.program.tracks.confirmed.cfp_active.each_slice(3) do |slice| .row.row-centered - slice.each do |track| .col-md-4.col-sm-4.col-centered.col-top.track %h4.text-center = track.name = markdown(track.description) + - if track.start_date + %br + From: #{track.start_date.strftime('%A, %B %-d. %Y')} + - if track.end_date + %br + To: #{track.end_date.strftime('%A, %B %-d. %Y')} + - if track.room + %br + In: #{track.room.name} - if @conference.program and @conference.program.schedule_public .row diff --git a/app/views/layouts/_user_menu.html.haml b/app/views/layouts/_user_menu.html.haml index 38a96b08..fe1e9a35 100644 --- a/app/views/layouts/_user_menu.html.haml +++ b/app/views/layouts/_user_menu.html.haml @@ -12,6 +12,10 @@ = link_to(conference_program_proposals_path(@conference.short_title)) do %span.fa.fa-comment My Submissions + %li + = link_to(conference_program_tracks_path(@conference.short_title)) do + %span.fa.fa-road + My Tracks %li - if ENV['OSEM_ICHAIN_ENABLED'] == 'true' = link_to(destroy_user_ichain_session_path, method: 'delete') do diff --git a/app/views/proposals/_encouragement_text.html.haml b/app/views/proposals/_encouragement_text.html.haml index a0f513cd..c6d574d6 100644 --- a/app/views/proposals/_encouragement_text.html.haml +++ b/app/views/proposals/_encouragement_text.html.haml @@ -4,7 +4,7 @@ = "#{event_types(@conference)}." - if @program.tracks.any? Proposals should fit in one of the - = "#{pluralize(@program.tracks.count, 'track')}:" + = "#{pluralize(@program.tracks.confirmed.cfp_active.count, 'track')}:" = "#{tracks(@conference)}." - if @program.cfp_open? The submission period has begun diff --git a/app/views/tracks/_form.html.haml b/app/views/tracks/_form.html.haml index 2a55df5a..31e9deaf 100644 --- a/app/views/tracks/_form.html.haml +++ b/app/views/tracks/_form.html.haml @@ -15,5 +15,5 @@ = f.input :color, input_html: {size: 6, type: 'color'}, required: true = f.input :start_date, as: :string, input_html: { id: 'registration-period-start-datepicker', start_date: @conference.start_date, end_date: @conference.end_date, readonly: 'readonly' } = f.input :end_date, as: :string, input_html: { id: 'registration-period-end-datepicker', readonly: 'readonly' } - = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, required: true, hint: markdown_hint + = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, required: true, hint: "This will be public #{markdown_hint}".html_safe = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/tracks/index.html.haml b/app/views/tracks/index.html.haml index fd1235d4..31a9fe97 100644 --- a/app/views/tracks/index.html.haml +++ b/app/views/tracks/index.html.haml @@ -6,46 +6,60 @@ %span.notranslate = @conference.title + .row + .col-md-12 + %p.text-right + = link_to '#status-help', class: 'btn btn-default', "data-toggle"=>"collapse" do + Help? + .collapse#status-help + %p + %strong + What happens next with my track request? + %p + If you submit a track request, the conference organizers will review it and either accept or reject it. + %br + If your track request is accepted, the conference organizers expect you to confirm that you will be able to hold it. + Then you will gain the Track organizer role. + %br + If your track request is rejected, you can either live with that or adapt it and resubmit it for review again. + %br + If something changes and you can't organize the track any more, you should withdraw it. + - if @tracks.any? .row .col-md-12 - %table.table.table-hover#tracks - %thead - %th Name - %th Short name - %th Description - %th Color - %th State - %th Start Date - %th End Date - %th Actions - %tbody - - @tracks.each do |track| - %tr - %td - = link_to(conference_program_track_path(@conference.short_title, track)) do - = track.name - %td - = track.short_name - %td - %p - = truncate(track.description) - %td + %table.table.table-striped#tracks + - @tracks.each do |track| + %tr + %td{style: "padding:15px 0px 0px 8px;"} + - if %w(new to_accept to_reject).include? track.state + %span{ title: 'In review', class: 'fa fa-eye' } + - elsif track.state == 'accepted' + %span{ title: 'Accepted', class: 'fa fa-check text-muted' } + - elsif track.state == 'confirmed' + %spam{ title: 'Confirmed', class: 'fa fa-check text-success' } + - elsif %w(rejected withdrawn canceled).include? track.state + %span{ title: track.state.humanize, class: 'fa fa-ban'} + %td{style: "padding: 15px 0px 0px 0px;"} + = link_to conference_program_track_path(@conference.short_title, track), class: 'btn' do %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} - = track.color - %td - = track.state.humanize - %td - - if track.start_date - = track.start_date.strftime('%A, %B %-d. %Y') - - else - N/A - %td - - if track.end_date - = track.end_date.strftime('%A, %B %-d. %Y') - - else - N/A - %td + = track.name + %td + = markdown(truncate(track.description)) + %td + - if track.start_date + From: + = track.start_date.strftime('%A, %B %-d. %Y') + %td + - if track.end_date + To: + = track.end_date.strftime('%A, %B %-d. %Y') + %td + - if track.room + In: + = track.room.name + %td + .pull-right - if track.transition_possible? :confirm = link_to 'Confirm', confirm_conference_program_track_path(@conference.short_title, track), method: :patch, class: 'btn btn-mini btn-success', id: "confirm_track_#{track.id}" @@ -57,8 +71,7 @@ = link_to 'Re-Submit', restart_conference_program_track_path(@conference.short_title, track), method: :patch, class: 'btn btn-mini btn-success', id: "resubmit_track_request_#{track.id}" - if can? :edit, track - = link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track), - method: :get, class: 'btn btn-primary' + = link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track), class: 'btn btn-default' .row .col-md-12 diff --git a/app/views/tracks/show.html.haml b/app/views/tracks/show.html.haml index c5bc27e5..db437878 100644 --- a/app/views/tracks/show.html.haml +++ b/app/views/tracks/show.html.haml @@ -2,9 +2,12 @@ .row .col-md-12 .page-header - %h1 + %h2 = @track.name Track + .btn-group.pull-right + - if can? :edit, @track + = link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-primary' .row .col-md-8 %dl.dl-horizontal @@ -16,26 +19,23 @@ %dt State: %dd - = @track.state.humanize + - if %w(new to_accept to_reject).include? @track.state + New + - else + = @track.state.humanize %dt Start date: %dd - - if @track.start_date - = @track.start_date.strftime('%A, %B %-d. %Y') - - else - N/A + = @track.start_date.strftime('%A, %B %-d. %Y') if @track.start_date %dt End date: %dd - - if @track.end_date - = @track.end_date.strftime('%A, %B %-d. %Y') - - else - N/A + = @track.end_date.strftime('%A, %B %-d. %Y') if @track.end_date + %dt + Room: + %dd + = @track.room.try(:name) %dt Description %dd - = @track.description - .row - .col-md-12.text-right - - if can? :edit, @track - = link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-primary' + = markdown(@track.description) diff --git a/spec/features/tracks_spec.rb b/spec/features/tracks_spec.rb index 3538a6d7..91e90ee9 100644 --- a/spec/features/tracks_spec.rb +++ b/spec/features/tracks_spec.rb @@ -39,7 +39,7 @@ feature Track do within('table#tracks') do expect(page.has_content?(track.name)).to be false expect(page.has_content?(track.description)).to be false - expect(page.assert_selector('tr', count: 1)).to be true + expect(page.has_content?('No data available in table')).to eq true end end diff --git a/spec/models/track_spec.rb b/spec/models/track_spec.rb index 4853f31d..158c6140 100644 --- a/spec/models/track_spec.rb +++ b/spec/models/track_spec.rb @@ -120,6 +120,46 @@ describe Track do end end + describe 'scope' do + describe '#confirmed' do + before :each do + @program = create(:program) + end + + context 'includes' do + it 'when track is confirmed' do + confirmed_track = create(:track, state: 'confirmed', program: @program) + expect(@program.tracks.confirmed.include?(confirmed_track)).to eq true + end + end + + context 'excludes' do + %w[new to_accept accepted to_reject rejected canceled withdrawn].each do |state| + it "when track is #{state.humanize}" do + unconfirmed_track = create(:track, state: state, program: @program) + expect(@program.tracks.confirmed.include?(unconfirmed_track)).to eq false + end + end + end + end + + describe '#cfp_active' do + before :each do + @program = create(:program) + @cfp_active_track = create(:track, cfp_active: true, program: @program) + @non_cfp_active_track = create(:track, cfp_active: false, program: @program) + end + + it 'include tracks with the cfp_active flag enabled' do + expect(@program.tracks.cfp_active.include?(@cfp_active_track)).to eq true + end + + it 'excludes tracks with the cfp_active flag disabled' do + expect(@program.tracks.cfp_active.include?(@non_cfp_active_track)).to eq false + end + end + end + describe '#self_organized?' do it 'returns true when it has a submitter' do expect(self_organized_track.submitter).to be_a User From 2ff4c6d6b25078ac76085f47091104da3dedd5af Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 26 Jul 2017 14:54:10 +0300 Subject: [PATCH 158/237] Add relevance field for track requests The requester can now provide more info about the track and himself --- app/controllers/tracks_controller.rb | 2 +- app/models/track.rb | 1 + app/views/admin/tracks/show.html.haml | 6 ++++++ app/views/tracks/_form.html.haml | 1 + app/views/tracks/show.html.haml | 4 ++++ .../20170726065629_add_relevance_to_tracks.rb | 5 +++++ db/schema.rb | 1 + spec/controllers/tracks_controller_spec.rb | 8 ++++---- spec/factories/tracks.rb | 1 + spec/models/track_spec.rb | 16 ++++++++++++++++ 10 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20170726065629_add_relevance_to_tracks.rb diff --git a/app/controllers/tracks_controller.rb b/app/controllers/tracks_controller.rb index 9305950e..6b584d22 100644 --- a/app/controllers/tracks_controller.rb +++ b/app/controllers/tracks_controller.rb @@ -53,7 +53,7 @@ class TracksController < ApplicationController private def track_params - params.require(:track).permit(:name, :description, :color, :short_name, :start_date, :end_date) + params.require(:track).permit(:name, :description, :color, :short_name, :start_date, :end_date, :relevance) end def update_state(transition, notice) diff --git a/app/models/track.rb b/app/models/track.rb index 5fb37549..2b09b654 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -27,6 +27,7 @@ class Track < ActiveRecord::Base validates :start_date, presence: true, if: :self_organized_and_accepted_or_confirmed? validates :end_date, presence: true, if: :self_organized_and_accepted_or_confirmed? validates :room, presence: true, if: :self_organized_and_accepted_or_confirmed? + validates :relevance, presence: true, if: :self_organized? validate :valid_dates validate :valid_room, if: :self_organized_and_accepted_or_confirmed? diff --git a/app/views/admin/tracks/show.html.haml b/app/views/admin/tracks/show.html.haml index 5e45d3a5..a8c13d9d 100644 --- a/app/views/admin/tracks/show.html.haml +++ b/app/views/admin/tracks/show.html.haml @@ -92,6 +92,12 @@ %b Description %td = markdown(@track.description) + - if @track.self_organized? + %tr + %td + %b Relevance + %td + = markdown(@track.relevance) .tab-pane#events .col-md-12 diff --git a/app/views/tracks/_form.html.haml b/app/views/tracks/_form.html.haml index 31e9deaf..ab693dc5 100644 --- a/app/views/tracks/_form.html.haml +++ b/app/views/tracks/_form.html.haml @@ -16,4 +16,5 @@ = f.input :start_date, as: :string, input_html: { id: 'registration-period-start-datepicker', start_date: @conference.start_date, end_date: @conference.end_date, readonly: 'readonly' } = f.input :end_date, as: :string, input_html: { id: 'registration-period-end-datepicker', readonly: 'readonly' } = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, required: true, hint: "This will be public #{markdown_hint}".html_safe + = f.input :relevance, input_html: {rows: 5, data: { provide: 'markdown-editable' } }, required: true, hint: "Please explain here how this track relates to the conference, how you are related to it's content and why we should accept it. #{markdown_hint}".html_safe = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/tracks/show.html.haml b/app/views/tracks/show.html.haml index db437878..6014f23e 100644 --- a/app/views/tracks/show.html.haml +++ b/app/views/tracks/show.html.haml @@ -39,3 +39,7 @@ Description %dd = markdown(@track.description) + %dt + Relevance + %dd + = markdown(@track.relevance) diff --git a/db/migrate/20170726065629_add_relevance_to_tracks.rb b/db/migrate/20170726065629_add_relevance_to_tracks.rb new file mode 100644 index 00000000..215200c1 --- /dev/null +++ b/db/migrate/20170726065629_add_relevance_to_tracks.rb @@ -0,0 +1,5 @@ +class AddRelevanceToTracks < ActiveRecord::Migration + def change + add_column :tracks, :relevance, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index f8cc3ddc..9e6123a3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -525,6 +525,7 @@ ActiveRecord::Schema.define(version: 20170807092805) do t.integer "room_id" t.date "start_date" t.date "end_date" + t.text "relevance" end add_index "tracks", ["room_id"], name: "index_tracks_on_room_id" diff --git a/spec/controllers/tracks_controller_spec.rb b/spec/controllers/tracks_controller_spec.rb index 0e3a0553..a555dba8 100644 --- a/spec/controllers/tracks_controller_spec.rb +++ b/spec/controllers/tracks_controller_spec.rb @@ -60,7 +60,7 @@ describe TracksController do describe 'POST #create' do context 'saves successfuly' do before :each do - post :create, track: attributes_for(:track, short_name: 'my_track'), conference_id: conference.short_title + post :create, track: attributes_for(:track, :self_organized, short_name: 'my_track'), conference_id: conference.short_title end it 'redirects to tracks index path' do @@ -86,7 +86,7 @@ describe TracksController do context 'save fails' do before :each do allow_any_instance_of(Track).to receive(:save).and_return(false) - post :create, track: attributes_for(:track, short_name: 'my_track'), conference_id: conference.short_title + post :create, track: attributes_for(:track, :self_organized, short_name: 'my_track'), conference_id: conference.short_title end it 'assigns a new track with the correct conference' do @@ -126,7 +126,7 @@ describe TracksController do describe 'PATCH #update' do context 'updates successfully' do before :each do - patch :update, track: attributes_for(:track, color: '#FF0000'), + patch :update, track: attributes_for(:track, :self_organized, color: '#FF0000'), conference_id: conference.short_title, id: self_organized_track.short_name end @@ -152,7 +152,7 @@ describe TracksController do context 'update fails' do before :each do allow_any_instance_of(Track).to receive(:save).and_return(false) - patch :update, track: attributes_for(:track, color: '#FF0000'), + patch :update, track: attributes_for(:track, :self_organized, color: '#FF0000'), conference_id: conference.short_title, id: self_organized_track.short_name end diff --git a/spec/factories/tracks.rb b/spec/factories/tracks.rb index d61c9a1b..3c0042f2 100644 --- a/spec/factories/tracks.rb +++ b/spec/factories/tracks.rb @@ -15,6 +15,7 @@ FactoryGirl.define do start_date { Date.today } end_date { Date.today } room + relevance { Faker::Hipster.paragraph(2) } end end end diff --git a/spec/models/track_spec.rb b/spec/models/track_spec.rb index 158c6140..ed058176 100644 --- a/spec/models/track_spec.rb +++ b/spec/models/track_spec.rb @@ -48,6 +48,22 @@ describe Track do it { is_expected.to_not validate_presence_of(:room) } end + context 'when self_organized? returns true' do + before :each do + allow(subject).to receive(:self_organized?).and_return(true) + end + + it { is_expected.to validate_presence_of(:relevance) } + end + + context 'when self_organized? returns false' do + before :each do + allow(subject).to receive(:self_organized?).and_return(false) + end + + it { is_expected.to_not validate_presence_of(:relevance) } + end + describe '#valid_dates' do before :each do @conference = create(:conference, start_date: 1.day.ago, end_date: 2.days.from_now) From 5f1ed7ce85122305cec73b4fd73db6ea1afc1ba4 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Fri, 28 Jul 2017 02:05:08 +0300 Subject: [PATCH 159/237] Handle Tracks as resource_type in User#get_roles --- app/models/user.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/user.rb b/app/models/user.rb index f3f03ab7..793db609 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -165,7 +165,11 @@ class User < ActiveRecord::Base def get_roles result = {} roles.each do |role| - resource = Conference.find(role.resource_id).short_title + resource = if role.resource_type == 'Conference' + Conference.find(role.resource_id).short_title + elsif role.resource_type == 'Track' + Track.find(role.resource_id).name + end if result[role.name].nil? result[role.name] = [resource] else From b717018b310dea45d2e02a1f69ae9f17912b538a Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Tue, 8 Aug 2017 12:41:37 +0300 Subject: [PATCH 160/237] Track related fixes Make the message in admin/Tracks form more visible by making it bold and adding links to venue and rooms Make papertrail track changes for all the track's attributes Add validation to require presence of description for self-organized tracks Add ID column to admin/Tracks#index Make the cfp inclusion column sortable Show success/error flash messages after toggling cfp inclusion --- app/assets/javascripts/osem-datatables.js | 24 +++--- app/controllers/admin/tracks_controller.rb | 11 ++- app/models/track.rb | 3 +- app/views/admin/tracks/_form.html.haml | 9 +- app/views/admin/tracks/index.html.haml | 6 +- app/views/admin/tracks/show.html.haml | 1 + .../admin/tracks/toggle_cfp_inclusion.js.erb | 8 ++ .../admin/tracks_controller_spec.rb | 82 ++++++++++++++++--- spec/models/track_spec.rb | 2 + 9 files changed, 114 insertions(+), 32 deletions(-) create mode 100644 app/views/admin/tracks/toggle_cfp_inclusion.js.erb diff --git a/app/assets/javascripts/osem-datatables.js b/app/assets/javascripts/osem-datatables.js index f950159e..a6f85c5d 100644 --- a/app/assets/javascripts/osem-datatables.js +++ b/app/assets/javascripts/osem-datatables.js @@ -1,18 +1,14 @@ $(function () { - $(document).ready(function() { - $('.datatable').DataTable({ - // ajax: ..., - stateSave: true, - autoWidth: false, - pagingType: 'full_numbers', - "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]] - }); + $('.datatable').DataTable({ + // ajax: ..., + stateSave: true, + autoWidth: false, + pagingType: 'full_numbers', + "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]], + }); - $('#versionstable').DataTable({ - pagingType: 'full_numbers', - order: [[ 0, 'desc' ]] - }); + $('#versionstable').DataTable({ + pagingType: 'full_numbers', + order: [[ 0, 'desc' ]] }); }); - - diff --git a/app/controllers/admin/tracks_controller.rb b/app/controllers/admin/tracks_controller.rb index 3d51a677..0f3940da 100644 --- a/app/controllers/admin/tracks_controller.rb +++ b/app/controllers/admin/tracks_controller.rb @@ -4,6 +4,9 @@ module Admin load_and_authorize_resource :program, through: :conference, singleton: true load_and_authorize_resource through: :program, find_by: :short_name + # Show flash message with ajax calls + after_action :prepare_unobtrusive_flash, only: :toggle_cfp_inclusion + def index; end def show @@ -55,9 +58,13 @@ module Admin def toggle_cfp_inclusion @track.cfp_active = !@track.cfp_active if @track.save - head :ok + flash[:notice] = "Successfully changed cfp inclusion of #{@track.name} to #{@track.cfp_active}" else - head :unprocessable_entity + flash[:error] = "Failed to toggle cfp inclusion of #{@track.name} to #{@track.cfp_active}" + end + + respond_to do |format| + format.js end end diff --git a/app/models/track.rb b/app/models/track.rb index 2b09b654..c624cab8 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -9,7 +9,7 @@ class Track < ActiveRecord::Base belongs_to :room has_many :events, dependent: :nullify - has_paper_trail only: [:name, :description, :color], meta: { conference_id: :conference_id } + has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id } before_create :generate_guid validates :name, presence: true @@ -28,6 +28,7 @@ class Track < ActiveRecord::Base validates :end_date, presence: true, if: :self_organized_and_accepted_or_confirmed? validates :room, presence: true, if: :self_organized_and_accepted_or_confirmed? validates :relevance, presence: true, if: :self_organized? + validates :description, presence: true, if: :self_organized? validate :valid_dates validate :valid_room, if: :self_organized_and_accepted_or_confirmed? diff --git a/app/views/admin/tracks/_form.html.haml b/app/views/admin/tracks/_form.html.haml index eb12561b..9109e4f5 100644 --- a/app/views/admin/tracks/_form.html.haml +++ b/app/views/admin/tracks/_form.html.haml @@ -14,10 +14,15 @@ = f.input :color, input_html: {size: 6, type: 'color'}, required: true = f.input :start_date, as: :string, input_html: { id: 'registration-period-start-datepicker', start_date: @conference.start_date, end_date: @conference.end_date, readonly: 'readonly', required: @track.self_organized_and_accepted_or_confirmed? } = f.input :end_date, as: :string, input_html: { id: 'registration-period-end-datepicker', readonly: 'readonly', required: @track.self_organized_and_accepted_or_confirmed? } - - if @conference.venue + - if @conference.venue.try(:rooms) = f.input :room, as: :select, collection: (@conference.venue.rooms).map {|room| ["#{room.name}", room.id]}, include_blank: true, label: 'Room', input_html: { class: 'select-help-toggle', required: @track.self_organized_and_accepted_or_confirmed? } - else - Please add a venue with rooms, if you want to select a room for the track. + %b + Please add a + = link_to 'venue', admin_conference_venue_path(@conference.short_title) + with + = link_to 'rooms', admin_conference_venue_rooms_path(@conference.short_title) + , if you want to select a room for the track. = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, hint: markdown_hint = f.input :cfp_active, label: 'Allow event submitters to select this track for their proposal' = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 5c47fe11..77a7cf02 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -1,3 +1,4 @@ +.unobtrusive-flash-container .row .col-md-12 .page-header @@ -8,6 +9,7 @@ .col-md-12 %table.table.table-hover.table-striped.table-bordered.datatable#tracks %thead + %th ID %th Name %th Description %th Room @@ -20,6 +22,8 @@ %tbody - @tracks.each do |track| %tr + %td + = track.id %td{style: "padding: 15px 0px 0px 10px;"} = link_to admin_conference_program_track_path(@conference.short_title, track), class: 'btn' do %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} @@ -35,7 +39,7 @@ = track.end_date.strftime('%A, %B %-d. %Y') if track.end_date %td = link_to track.submitter.name, admin_user_path(track.submitter) if track.self_organized? - %td.text-center + %td.text-center{ 'id' => "cfp_switch_#{track.id}", 'data-order' => track.cfp_active.to_s } = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, class: 'switch-checkbox', method: :patch, url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.short_name)+"?included=", diff --git a/app/views/admin/tracks/show.html.haml b/app/views/admin/tracks/show.html.haml index a8c13d9d..78f8830e 100644 --- a/app/views/admin/tracks/show.html.haml +++ b/app/views/admin/tracks/show.html.haml @@ -1,3 +1,4 @@ +.unobtrusive-flash-container .row .col-md-12 .page-header diff --git a/app/views/admin/tracks/toggle_cfp_inclusion.js.erb b/app/views/admin/tracks/toggle_cfp_inclusion.js.erb new file mode 100644 index 00000000..6ee83003 --- /dev/null +++ b/app/views/admin/tracks/toggle_cfp_inclusion.js.erb @@ -0,0 +1,8 @@ +$('.alert').remove(); + +track_id = <%= @track.id %>; +track_cfp_td = $('#cfp_switch_' + track_id); +track_cfp_value = <%= @track.cfp_active %>; + +track_cfp_td.attr('data-order', track_cfp_value); +$('#tracks').DataTable().cell(track_cfp_td).invalidate(); diff --git a/spec/controllers/admin/tracks_controller_spec.rb b/spec/controllers/admin/tracks_controller_spec.rb index 70ca48a1..795906aa 100644 --- a/spec/controllers/admin/tracks_controller_spec.rb +++ b/spec/controllers/admin/tracks_controller_spec.rb @@ -228,16 +228,45 @@ describe Admin::TracksController do before :each do self_organized_track.cfp_active = false self_organized_track.save! - patch :toggle_cfp_inclusion, conference_id: conference.short_title, id: self_organized_track.short_name - self_organized_track.reload end - it 'assigns the correct track' do - expect(assigns(:track)).to eq self_organized_track + context 'toggles successfully' do + before :each do + patch :toggle_cfp_inclusion, conference_id: conference.short_title, id: self_organized_track.short_name, format: :js + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows success message in flash notice' do + expect(flash[:notice]).to match('Successfully changed cfp inclusion of My awesome track to true') + end + + it 'becomes true' do + expect(self_organized_track.cfp_active).to eq true + end end - it 'becomes true' do - expect(self_organized_track.cfp_active).to eq true + context 'save fails' do + before :each do + allow_any_instance_of(Track).to receive(:save).and_return(false) + patch :toggle_cfp_inclusion, conference_id: conference.short_title, id: self_organized_track.short_name, format: :js + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows error message in flash notice' do + expect(flash[:error]).to match('Failed to toggle cfp inclusion of My awesome track to true') + end + + it 'stays false' do + expect(self_organized_track.cfp_active).to eq false + end end end @@ -245,16 +274,45 @@ describe Admin::TracksController do before :each do self_organized_track.cfp_active = true self_organized_track.save! - patch :toggle_cfp_inclusion, conference_id: conference.short_title, id: self_organized_track.short_name - self_organized_track.reload end - it 'assigns the correct track' do - expect(assigns(:track)).to eq self_organized_track + context 'toggles successfully' do + before :each do + patch :toggle_cfp_inclusion, conference_id: conference.short_title, id: self_organized_track.short_name, format: :js + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows success message in flash notice' do + expect(flash[:notice]).to match('Successfully changed cfp inclusion of My awesome track to false') + end + + it 'becomes false' do + expect(self_organized_track.cfp_active).to eq false + end end - it 'becomes false' do - expect(self_organized_track.cfp_active).to eq false + context 'save fails' do + before :each do + allow_any_instance_of(Track).to receive(:save).and_return(false) + patch :toggle_cfp_inclusion, conference_id: conference.short_title, id: self_organized_track.short_name, format: :js + self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track + end + + it 'shows error message in flash notice' do + expect(flash[:error]).to match('Failed to toggle cfp inclusion of My awesome track to false') + end + + it 'stays true' do + expect(self_organized_track.cfp_active).to eq true + end end end end diff --git a/spec/models/track_spec.rb b/spec/models/track_spec.rb index ed058176..1ad54839 100644 --- a/spec/models/track_spec.rb +++ b/spec/models/track_spec.rb @@ -54,6 +54,7 @@ describe Track do end it { is_expected.to validate_presence_of(:relevance) } + it { is_expected.to validate_presence_of(:description) } end context 'when self_organized? returns false' do @@ -62,6 +63,7 @@ describe Track do end it { is_expected.to_not validate_presence_of(:relevance) } + it { is_expected.to_not validate_presence_of(:description) } end describe '#valid_dates' do From b4be83e3a65497354044898e3548c093f6809b58 Mon Sep 17 00:00:00 2001 From: divyanshumehta Date: Wed, 9 Aug 2017 13:26:38 +0530 Subject: [PATCH 161/237] Removed delete action from abiltiy.rb and other places There was no delete action defined for proposals, but it was there in ability.rb So the ability was deleted. Fixes #1608 --- app/models/ability.rb | 2 +- app/models/admin_ability.rb | 2 +- spec/models/ability_spec.rb | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 63ec68dc..6713127c 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -87,7 +87,7 @@ class Ability event.program.cfp_open? && event.new_record? end - can [:update, :show, :delete, :index], Event do |event| + can [:update, :show, :index], Event do |event| event.users.include?(user) end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index b0c9d4c9..46038d5f 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -39,7 +39,7 @@ class AdminAbility event.program.cfp_open? && event.new_record? end - can [:update, :show, :delete, :index], Event do |event| + can [:update, :show, :index], Event do |event| event.users.include?(user) end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index ff3f14cb..7936ddbb 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -106,7 +106,6 @@ describe 'User' do it{ should be_able_to(:update, user_event_with_cfp) } it{ should be_able_to(:show, user_event_with_cfp) } - it{ should be_able_to(:delete, user_event_with_cfp) } it{ should_not be_able_to(:new, Event.new(program: program_without_cfp)) } it{ should_not be_able_to(:create, Event.new(program: program_without_cfp)) } # TODO: At moment it's not possible to manually add someone else as event_user From 5f9c0065c68174b110f84531cb8fedf0bd27a74b Mon Sep 17 00:00:00 2001 From: damien clochard Date: Sat, 12 Aug 2017 10:45:12 +0200 Subject: [PATCH 162/237] FIX : links --- TRANSLATION.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 5014159f..3923584c 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -1,5 +1,5 @@ # Translation -We are using [Transifex] (https://www.transifex.com/opensuse-community/osem/) to manage our translations. +We are using [Transifex](https://www.transifex.com/opensuse-community/osem/) to manage our translations. We are also using the _Live_ feature of Transifex. That means that all strings from OSEM instances are automatically collected and are available for translating. >Automated collection only works if you use the API key (See at the end of this file) @@ -7,7 +7,7 @@ We are also using the _Live_ feature of Transifex. That means that all strings f ## 1. Translate * Start translating: - 1. Navigate to the [project's page] (https://www.transifex.com/opensuse-community/osem) + 1. Navigate to the [project's page](https://www.transifex.com/opensuse-community/osem) 2. Click **translation** button 3. Select **language** 4. Select **resource** (events.opensuse.org) @@ -27,7 +27,7 @@ Eg. Assuming you have signed up yourself as a translator for OSEM, to translate * How to request to publish translated strings - After you make sure that you have properly reviewed the newly translated strings (they need to be marked as **reviewed** otherwise they won't go live), you can open a [new issue] (https://github.com/openSUSE/osem/issues/new) with the following information: + After you make sure that you have properly reviewed the newly translated strings (they need to be marked as **reviewed** otherwise they won't go live), you can open a [new issue](https://github.com/openSUSE/osem/issues/new) with the following information: Title: [Transifex] Publish translation for EN From 7107f9a35f12838bf9d1279c4ac54c9a167d5cbd Mon Sep 17 00:00:00 2001 From: nasia Date: Wed, 2 Aug 2017 20:10:47 +0300 Subject: [PATCH 163/237] Add emails for booth's acceptance and rejection --- .haml-lint_todo.yml | 2 ++ .rubocop_todo.yml | 1 + app/controllers/admin/booths_controller.rb | 24 +++++++++++++++++-- app/controllers/admin/emails_controller.rb | 4 +++- app/mailers/mailbot.rb | 18 ++++++++++++++ app/models/email_settings.rb | 11 ++++++++- .../booths/_change_state_dropdown.html.haml | 18 ++++++++++---- app/views/admin/emails/_help.html.haml | 8 ++++++- app/views/admin/emails/index.html.haml | 22 +++++++++++++++++ ...0731161207_add_booths_to_email_settings.rb | 10 ++++++++ db/schema.rb | 6 +++++ 11 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 db/migrate/20170731161207_add_booths_to_email_settings.rb diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index b7a18be0..4ec5de3c 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -303,6 +303,7 @@ linters: SpaceInsideHashAttributes: exclude: - "app/views/admin/conferences/_todo_list.html.haml" + - "app/views/admin/emails/index.html.haml" - "app/views/admin/questions/_form.html.haml" - "app/views/admin/questions/index.html.haml" - "app/views/admin/registrations/index.html.haml" @@ -403,6 +404,7 @@ linters: # Offense count: 14 ConsecutiveSilentScripts: exclude: + - "app/views/admin/booths/_change_state_dropdown.html.haml" - "app/views/admin/events/index.html.haml" - "app/views/admin/schedules/_day_tab.html.haml" - "app/views/admin/schedules/_event.html.haml" diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 487a9fdb..38bf269f 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -450,6 +450,7 @@ Style/IfUnlessModifier: - 'app/helpers/application_helper.rb' - 'app/models/commercial.rb' - 'app/models/conference.rb' + - 'app/models/email_settings.rb' - 'app/models/ticket_purchase.rb' - 'app/models/user.rb' - 'db/migrate/20151031092713_change_conference_id_to_venue_id_in_rooms.rb' diff --git a/app/controllers/admin/booths_controller.rb b/app/controllers/admin/booths_controller.rb index e5b55552..a200e42e 100644 --- a/app/controllers/admin/booths_controller.rb +++ b/app/controllers/admin/booths_controller.rb @@ -47,7 +47,18 @@ module Admin end def accept - update_state(:accept, 'Booth accepted!') + @booth.accept! + + if @booth.save + if @conference.email_settings.send_on_booths_acceptance + Mailbot.conference_booths_acceptance_mail(@booth).deliver + end + redirect_to admin_conference_booths_path(conference_id: @conference.short_title), + notice: 'Booth successfully accepted!' + else + redirect_to admin_conference_booths_path(conference_id: @conference.short_title) + flash[:error] = "Booth could not be accepted. #{@booth.errors.full_messages.to_sentence}." + end end def to_accept @@ -59,7 +70,16 @@ module Admin end def reject - update_state(:reject, 'Booth rejected') + @booth.reject! + + if @booth.save + Mailbot.conference_booths_rejection_mail(@booth).deliver + redirect_to admin_conference_booths_path(conference_id: @conference.short_title), + notice: 'Booth successfully rejected.' + else + redirect_to admin_conference_booths_path(conference_id: @conference.short_title) + flash[:error] = "Booth could not be rejected. #{@booth.errors.full_messages.to_sentence}." + end end def restart diff --git a/app/controllers/admin/emails_controller.rb b/app/controllers/admin/emails_controller.rb index adff714a..a4d6fe04 100644 --- a/app/controllers/admin/emails_controller.rb +++ b/app/controllers/admin/emails_controller.rb @@ -30,7 +30,9 @@ module Admin :send_on_conference_registration_dates_updated, :conference_registration_dates_updated_subject, :conference_registration_dates_updated_body, :send_on_venue_updated, :venue_updated_subject, :venue_updated_body, :send_on_cfp_dates_updated, :cfp_dates_updated_subject, :cfp_dates_updated_body, - :send_on_program_schedule_public, :program_schedule_public_subject, :program_schedule_public_body) + :send_on_program_schedule_public, :program_schedule_public_subject, :program_schedule_public_body, + :send_on_booths_acceptance, :booths_acceptance_subject, :booths_acceptance_body, + :send_on_booths_rejection, :booths_rejection_subject, :booths_rejection_body) end end end diff --git a/app/mailers/mailbot.rb b/app/mailers/mailbot.rb index 837e2c1e..63f95a40 100644 --- a/app/mailers/mailbot.rb +++ b/app/mailers/mailbot.rb @@ -97,6 +97,24 @@ class Mailbot < ActionMailer::Base conference.email_settings.cfp_dates_updated_body)) end + def conference_booths_acceptance_mail(booth) + conference = booth.conference + + mail(to: booth.submitter.email, + from: conference.contact.email, + subject: conference.email_settings.booths_acceptance_subject, + body: conference.email_settings.generate_booth_mail(booth, conference.email_settings.booths_acceptance_body)) + end + + def conference_booths_rejection_mail(booth) + conference = booth.conference + + mail(to: booth.submitter.email, + from: conference.contact.email, + subject: conference.email_settings.booths_rejection_subject, + body: conference.email_settings.generate_booth_mail(booth, conference.email_settings.booths_rejection_body)) + end + def event_comment_mail(comment, user) @comment = comment @event = @comment.commentable diff --git a/app/models/email_settings.rb b/app/models/email_settings.rb index 6d6c4478..6210cf9d 100644 --- a/app/models/email_settings.rb +++ b/app/models/email_settings.rb @@ -3,7 +3,7 @@ class EmailSettings < ActiveRecord::Base has_paper_trail on: [:update], ignore: [:updated_at], meta: { conference_id: :conference_id } - def get_values(conference, user, event = nil) + def get_values(conference, user, event = nil, booth = nil) h = { 'email' => user.email, 'name' => user.name, @@ -45,6 +45,10 @@ class EmailSettings < ActiveRecord::Base h['proposalslink'] = Rails.application.routes.url_helpers.conference_program_proposals_url( conference.short_title, host: (ENV['OSEM_HOSTNAME'] || 'localhost:3000')) end + + if booth + h['booth_title'] = booth.title + end h end @@ -58,6 +62,11 @@ class EmailSettings < ActiveRecord::Base parse_template(conf_update_template, values) end + def generate_booth_mail(booth, booth_template) + values = get_values(booth.conference, booth.submitter, nil, booth) + parse_template(booth_template, values) + end + private def parse_template(text, values) diff --git a/app/views/admin/booths/_change_state_dropdown.html.haml b/app/views/admin/booths/_change_state_dropdown.html.haml index c0418d67..8178a790 100644 --- a/app/views/admin/booths/_change_state_dropdown.html.haml +++ b/app/views/admin/booths/_change_state_dropdown.html.haml @@ -1,17 +1,25 @@ - if booth.transition_possible? :accept - %li= link_to 'Accept booth', + - if @conference.email_settings.send_on_booths_acceptance + - link = 'Accept with email' + - else + - link = 'Accept booth' + %li= link_to link, accept_admin_conference_booth_path(@conference.short_title, booth), - method: :patch, id: "accept_booth_#{booth.id}" + method: :patch ,id: "accept_booth_#{booth.id}" - if booth.transition_possible? :reject - %li= link_to 'Reject booth', + - if @conference.email_settings.send_on_booths_rejection + - link = 'Reject with email' + - else + - link = 'Reject' + %li= link_to link, reject_admin_conference_booth_path(@conference.short_title, booth), - method: :patch, confirm: 'Are you sure?', id: "reject_booth_#{booth.id}" + method: :patch, id: "reject_booth_#{booth.id}" - if booth.transition_possible? :to_reject %li= link_to 'To reject booth', to_reject_admin_conference_booth_path(@conference.short_title, booth), - method: :patch, confirm: 'Are you sure?', id: "to_reject_booth_#{booth.id}" + method: :patch, id: "to_reject_booth_#{booth.id}" - if booth.transition_possible? :restart %li= link_to 'Start review', diff --git a/app/views/admin/emails/_help.html.haml b/app/views/admin/emails/_help.html.haml index 535cd097..371bac7b 100644 --- a/app/views/admin/emails/_help.html.haml +++ b/app/views/admin/emails/_help.html.haml @@ -55,4 +55,10 @@ %tr %td {conference_splash_link} %td The link to conference splash page - + - if @conference.booths + %tr + %td {submitter_name} + %td Submitter's name + %tr + %td {booth_title} + %td Booth's title diff --git a/app/views/admin/emails/index.html.haml b/app/views/admin/emails/index.html.haml index 4b380b86..99d02130 100644 --- a/app/views/admin/emails/index.html.haml +++ b/app/views/admin/emails/index.html.haml @@ -14,6 +14,8 @@ %a{ 'aria-controls' => 'notifications', 'data-toggle' => 'tab', href: '#notifications', role: 'tab' } Update Notifications %li{ role: 'presentation' } %a{ 'aria-controls' => 'cfp', 'data-toggle' => 'tab', href: '#cfp', role: 'tab' } Call for Papers + %li{ role: 'presentation' } + %a{ 'aria-controls' => 'booths', 'data-toggle' => 'tab', href: '#booth', role: 'tab' } Booth / Tab panes .tab-content #onboarding.tab-pane.active{ role: 'tabpanel' } @@ -100,6 +102,26 @@ 'data-body-text' => "Dear {name},\n\nThe Conference Call for Papers Details of {conference} has changed.\nNew Dates : {cfp_start_date} - {cfp_end_date}.\n Link to Schedule {schedule_link} \n\nBest wishes\n\n{conference} Team" } Load Template %a.btn.btn-link.control_label.template_help_link{ 'data-name' => 'updated_cfp_help' } Show Help = render partial: 'help', locals: {id: 'updated_cfp_help', show_event_variables: false} + #booth.tab-pane{ role: 'tabpanel' } + = f.input :send_on_booths_acceptance + = f.input :booths_acceptance_subject + = f.input :booths_acceptance_body, input_html: { rows:10, cols: 20 } + %a.btn.btn-link.control_label.load_template{ 'data-subject-input-id' => 'email_settings_booths_acceptance_subject', + 'data-subject-text' => 'Your booth has been accepted!', + 'data-body-input-id' => 'email_settings_booths_acceptance_body', + 'data-body-text' => "Dear {name},\n\nWe are really pleased to inform you that your booth request {booth_title} has been accepted for the conference {conference}.\nPlease click the confirm button to let us know you can make it as soon as possible!\n\nFeel free to contact us with any questions or concerns.\n\nWe look forward to seeing you there.\n\nBest wishes\n\n{conference} Team"} Load Template + %a.btn.btn-link.control_label.template_help_link{ 'data-name' => 'booth_acceptance_help' } Show help + = render partial: 'help', locals: {id: 'booth_acceptance_help', show_event_variables: false} + = f.input :send_on_booths_rejection + = f.input :booths_rejection_subject + = f.input :booths_rejection_body, input_html: { rows:10, cols:20 } + %a.btn.btn-link.control_label.load_template{ 'data-subject-input-id' => 'email_settings_booths_rejection_subject', + 'data-subject-text' => 'Your booth request has been rejected', + 'data-body-input-id' => 'email_settings_booths_rejection_body', + 'data-body-text' => "Dear {name},\n\nThank you for your booth request {booth_title} for the conference {conference}.\n\nUnfortunately, we are sorry to inform you that your request has been rejected.\n\n\nBest wishes\n\n{conference} Team" } Load Template + %a.btn.btn-link.control_label.template_help_link{ 'data-name' => 'booth_rejection_help' } Show help + = render partial: 'help', locals: {id: 'booth_rejection_help', show_event_variables: false} + .row .col-md-12 = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/db/migrate/20170731161207_add_booths_to_email_settings.rb b/db/migrate/20170731161207_add_booths_to_email_settings.rb new file mode 100644 index 00000000..0b3a7a87 --- /dev/null +++ b/db/migrate/20170731161207_add_booths_to_email_settings.rb @@ -0,0 +1,10 @@ +class AddBoothsToEmailSettings < ActiveRecord::Migration + def change + add_column :email_settings, :send_on_booths_acceptance, :boolean, default: false + add_column :email_settings, :booths_acceptance_subject, :string + add_column :email_settings, :booths_acceptance_body, :text + add_column :email_settings, :send_on_booths_rejection, :boolean, default: false + add_column :email_settings, :booths_rejection_subject, :string + add_column :email_settings, :booths_rejection_body, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 9e6123a3..6cc32e82 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -205,6 +205,12 @@ ActiveRecord::Schema.define(version: 20170807092805) do t.string "cfp_dates_updated_subject" t.text "program_schedule_public_body" t.text "cfp_dates_updated_body" + t.boolean "send_on_booths_acceptance", default: false + t.string "booths_acceptance_subject" + t.text "booths_acceptance_body" + t.boolean "send_on_booths_rejection", default: false + t.string "booths_rejection_subject" + t.text "booths_rejection_body" end create_table "event_schedules", force: :cascade do |t| From 1391668c0f4536f6685b0b8ee4ce655a7ac58dc4 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Tue, 18 Jul 2017 02:57:46 +0530 Subject: [PATCH 164/237] Add routes and controller to scan Qr code Added TicketScanning controller and routes to scan qr code on PhysicalTickets. Added test for the same --- .../admin/ticket_scannings_controller.rb | 16 +++++ app/models/admin_ability.rb | 8 +++ config/routes.rb | 1 + .../admin/ticket_scannings_controller_spec.rb | 60 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 app/controllers/admin/ticket_scannings_controller.rb create mode 100644 spec/controllers/admin/ticket_scannings_controller_spec.rb diff --git a/app/controllers/admin/ticket_scannings_controller.rb b/app/controllers/admin/ticket_scannings_controller.rb new file mode 100644 index 00000000..488f28a1 --- /dev/null +++ b/app/controllers/admin/ticket_scannings_controller.rb @@ -0,0 +1,16 @@ +module Admin + class TicketScanningsController < Admin::BaseController + before_action :authenticate_user! + load_resource :physical_ticket, find_by: :token + # We authorize manually in these actions + skip_authorize_resource only: [:create] + + def create + @ticket_scanning = TicketScanning.new(physical_ticket: @physical_ticket) + authorize! :create, @ticket_scanning + @ticket_scanning.save + redirect_to conferences_path, + notice: "Ticket with token #{@physical_ticket.token} successfully scanned." + end + end +end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 4244d049..256262f4 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -145,6 +145,10 @@ class AdminAbility can :manage, Sponsor, conference_id: conf_ids can :manage, SponsorshipLevel, conference_id: conf_ids can :manage, Ticket, conference_id: conf_ids + can :create, TicketScanning do |ticket_scanning| + conf_id = ticket_scanning.physical_ticket.ticket_purchase.conference_id + conf_ids.include? conf_id + end can :index, Comment, commentable_type: 'Event', commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id) @@ -220,6 +224,10 @@ class AdminAbility can :manage, Question do |question| !(question.conferences.pluck(:id) & conf_ids_for_info_desk).empty? end + can :create, TicketScanning do |ticket_scanning| + conf_id = ticket_scanning.physical_ticket.ticket_purchase.conference_id + conf_ids_for_info_desk.include? conf_id + end # Abilities for Role (Conference resource) can [:index, :show], Role do |role| diff --git a/config/routes.rb b/config/routes.rb index 5a17d314..98211087 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -26,6 +26,7 @@ Osem::Application.routes.draw do patch :toggle_confirmation end end + resource :ticket_scanning, only: [:create] resources :comments, only: [:index] resources :conferences do resource :contact, except: [:index, :new, :create, :show, :destroy] diff --git a/spec/controllers/admin/ticket_scannings_controller_spec.rb b/spec/controllers/admin/ticket_scannings_controller_spec.rb new file mode 100644 index 00000000..245bd885 --- /dev/null +++ b/spec/controllers/admin/ticket_scannings_controller_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper' + +describe Admin::TicketScanningsController do + let(:admin) { create(:admin) } + let(:conference) { create(:conference) } + let(:user) { create(:user) } + let(:paid_ticket_purchase) { create(:ticket_purchase, conference: conference, user: user) } + let(:physical_ticket) { create(:physical_ticket, ticket_purchase: paid_ticket_purchase) } + + context 'logged in as user with no role' do + before :each do + sign_in user + end + describe 'POST #create' do + it 'does not create new ticket scanning' do + expected = expect do + post :create, physical_ticket_id: physical_ticket.token + end + expected.to_not change(TicketScanning, :count) + end + + it 'redirects to root' do + post :create, physical_ticket_id: physical_ticket.token + expect(flash[:alert]).to eq('You are not authorized to access this page.') + expect(response).to redirect_to(root_path) + end + end + end + + context 'logged in as admin' do + before :each do + sign_in admin + end + describe 'POST #create' do + context 'with valid physical_ticket' do + it 'creates new ticket scanning' do + expected = expect do + post :create, physical_ticket_id: physical_ticket.token + end + expected.to change { TicketScanning.count }.by(1) + end + + it 'redirects to index' do + post :create, physical_ticket_id: physical_ticket.token + expect(flash[:notice]).to eq("Ticket with token #{physical_ticket.token} successfully scanned.") + expect(response).to redirect_to(conferences_path) + end + end + + context 'with Invalid physical_ticket' do + it 'raises exception' do + expected = expect do + post :create, physical_ticket_id: 'XXXX' + end + expected.to raise_exception(ActiveRecord::RecordNotFound) + end + end + end + end +end From 8b5ebb3dd7e283129d78f4d67cd1982f558d2a0a Mon Sep 17 00:00:00 2001 From: nasia Date: Thu, 27 Jul 2017 11:22:14 +0300 Subject: [PATCH 165/237] Add confirmed booths to splashpage --- .haml-lint_todo.yml | 1 + .../admin/splashpages_controller.rb | 3 ++- app/models/booth.rb | 2 ++ app/views/admin/splashpages/_form.html.haml | 1 + app/views/admin/splashpages/show.html.haml | 7 ++++++ app/views/conferences/_booths.html.haml | 24 +++++++++++++++++++ .../conferences/_conference_details.html.haml | 4 ++++ app/views/conferences/show.html.haml | 4 ++++ ...81731_add_include_booths_to_splashpages.rb | 5 ++++ db/schema.rb | 1 + 10 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 app/views/conferences/_booths.html.haml create mode 100644 db/migrate/20170727081731_add_include_booths_to_splashpages.rb diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 4ec5de3c..a456dcd2 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -118,6 +118,7 @@ linters: - "app/views/conference_registrations/_registration_info.html.haml" - "app/views/conference_registrations/_volunteer.html.haml" - "app/views/conference_registrations/show.html.haml" + - "app/views/conferences/_booths.html.haml" - "app/views/conferences/_call_for_paper.html.haml" - "app/views/conferences/_conference_details.html.haml" - "app/views/conferences/_gallery.html.haml" diff --git a/app/controllers/admin/splashpages_controller.rb b/app/controllers/admin/splashpages_controller.rb index 2745cc8b..5f04a67b 100644 --- a/app/controllers/admin/splashpages_controller.rb +++ b/app/controllers/admin/splashpages_controller.rb @@ -47,7 +47,8 @@ module Admin :include_tracks, :include_program, :include_cfp, :include_venue, :include_registrations, :include_tickets, :include_lodgings, - :include_sponsors, :include_social_media) + :include_sponsors, :include_social_media, + :include_booths) end end end diff --git a/app/models/booth.rb b/app/models/booth.rb index 853bca9e..d7cc3eb2 100644 --- a/app/models/booth.rb +++ b/app/models/booth.rb @@ -25,6 +25,8 @@ class Booth < ActiveRecord::Base :submitter_relationship, presence: true + scope :confirmed, -> { where(state: 'confirmed') } + mount_uploader :picture, PictureUploader, mount_on: :logo_link state_machine initial: :new do diff --git a/app/views/admin/splashpages/_form.html.haml b/app/views/admin/splashpages/_form.html.haml index f945b2c9..c1897745 100644 --- a/app/views/admin/splashpages/_form.html.haml +++ b/app/views/admin/splashpages/_form.html.haml @@ -14,6 +14,7 @@ = f.input :include_tickets, label: 'Display tickets', input_html: { checked: params[:action] == 'new' || @splashpage.try(:include_tickets) } = f.input :include_lodgings, label: 'Display the lodgings', input_html: { checked: params[:action] == 'new' || @splashpage.try(:include_lodgings) } = f.input :include_sponsors, label: 'Display sponsors', input_html: { checked: params[:action] == 'new' || @splashpage.try(:include_sponsors) } + = f.input :include_booths, label: 'Display confirmed booths', input_html: { checked: params[:action] == 'new' || @splashpage.try(:include_booths) } = f.input :include_social_media, label: 'Display social media', input_html: { checked: params[:action] == 'new' || @splashpage.try(:include_social_media) } = f.inputs name: 'Access' do = f.input :public, label: 'Make splash page public?' diff --git a/app/views/admin/splashpages/show.html.haml b/app/views/admin/splashpages/show.html.haml index b4e5f24c..c185b119 100644 --- a/app/views/admin/splashpages/show.html.haml +++ b/app/views/admin/splashpages/show.html.haml @@ -66,6 +66,13 @@ Yes - else No + %dt + Include Booths + %dd + - if @splashpage.include_booths + Yes + - else + No %dt Include Social Media: %dd diff --git a/app/views/conferences/_booths.html.haml b/app/views/conferences/_booths.html.haml new file mode 100644 index 00000000..b40af9b8 --- /dev/null +++ b/app/views/conferences/_booths.html.haml @@ -0,0 +1,24 @@ += content_for :splash_nav do + %li + %a.smoothscroll{ href: '#booths' } Booths + +.container + .row + .col-md-12.text-center + %h2 Booths + - @conference.booths.confirmed.each_slice(3).with_index do |slice, index_for_row| + .row.row-centered + - slice.each.with_index do |booth, index_for_column| + .col-md-4.col-sm-4.col-xs-10.col-centered.col-top + .thumbnail + - if booth.logo_link + = link_to booth.website_url, class: 'thumbnail' do + = image_tag booth.picture.large.url + .caption + %h3.text-center + = booth.title + %p.text-center.text-muted + = link_to "#show_descrition_#{index_for_row}_#{index_for_column}", "data-toggle"=>"collapse" do + learn more + .collapse{ id: "show_descrition_#{index_for_row}_#{index_for_column}" } + = markdown(booth.description) diff --git a/app/views/conferences/_conference_details.html.haml b/app/views/conferences/_conference_details.html.haml index e8ca2449..f4ec7101 100644 --- a/app/views/conferences/_conference_details.html.haml +++ b/app/views/conferences/_conference_details.html.haml @@ -38,6 +38,10 @@ = link_to "My Proposals", conference_program_proposals_path(conference.short_title), class: 'btn btn-default' - elsif can? :new, conference.program.events.new = link_to "Submit Proposal", new_conference_program_proposal_path(conference.short_title), class: 'btn btn-default' + - if current_user && current_user.booths.where(conference_id: conference.id).count > 0 + = link_to 'My Booth Requests', conference_booths_path(conference.short_title), class: 'btn btn-default' + - elsif can? :new, conference.booths.new + = link_to 'Request Booth', new_conference_booth_path(conference.short_title), class: 'btn btn-default' - if current_user.nil? || !current_user.subscribed?(conference) = link_to 'Subscribe', conference_subscriptions_path(conference.short_title), method: :post, class: 'btn btn-default' - else diff --git a/app/views/conferences/show.html.haml b/app/views/conferences/show.html.haml index edc72726..afda1516 100644 --- a/app/views/conferences/show.html.haml +++ b/app/views/conferences/show.html.haml @@ -65,6 +65,10 @@ %section#tickets = render 'tickets' + - if @conference.booths.confirmed.any? and @conference.splashpage.include_booths + %section#booths + = render 'booths' + - if @conference.sponsors.any? and @conference.splashpage.include_sponsors %section#sponsors = render 'sponsors' diff --git a/db/migrate/20170727081731_add_include_booths_to_splashpages.rb b/db/migrate/20170727081731_add_include_booths_to_splashpages.rb new file mode 100644 index 00000000..da11ea8d --- /dev/null +++ b/db/migrate/20170727081731_add_include_booths_to_splashpages.rb @@ -0,0 +1,5 @@ +class AddIncludeBoothsToSplashpages < ActiveRecord::Migration + def change + add_column :splashpages, :include_booths, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 6cc32e82..6c40c572 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -451,6 +451,7 @@ ActiveRecord::Schema.define(version: 20170807092805) do t.datetime "created_at" t.datetime "updated_at" t.boolean "include_cfp", default: false + t.boolean "include_booths" end create_table "sponsors", force: :cascade do |t| From 703813248dfef66f12b2285b6ea50a664b5f160d Mon Sep 17 00:00:00 2001 From: nasia Date: Wed, 16 Aug 2017 11:42:57 +0300 Subject: [PATCH 166/237] Request a booth only when cfp is open --- app/models/ability.rb | 4 +++- app/models/cfp.rb | 9 +++++++++ spec/controllers/booths_controller_spec.rb | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 6713127c..18f9d4c4 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -75,7 +75,9 @@ class Ability can [:new, :create], Payment, user_id: user.id can [:index, :show], PhysicalTicket, user: user - can [:new, :create], Booth + can [:new, :create], Booth do |booth| + booth.new_record? && booth.conference.program.cfps.for_booths.try(:open?) + end can [:edit, :update, :index, :show], Booth do |booth| booth.users.include?(user) diff --git a/app/models/cfp.rb b/app/models/cfp.rb index 8248cd1a..17b37809 100644 --- a/app/models/cfp.rb +++ b/app/models/cfp.rb @@ -94,6 +94,15 @@ class Cfp < ActiveRecord::Base find_by(cfp_type: 'tracks') end + ## + # Finds the cfp for booths if it exists + # + # ====Returns + # * +Cfp+ -> The cfp with type 'booths' + def self.for_booths + find_by(cfp_type: 'booths') + end + private def before_end_of_conference diff --git a/spec/controllers/booths_controller_spec.rb b/spec/controllers/booths_controller_spec.rb index 243bc6e2..56f3b9d9 100644 --- a/spec/controllers/booths_controller_spec.rb +++ b/spec/controllers/booths_controller_spec.rb @@ -8,6 +8,7 @@ describe BoothsController do context 'user is signed in with submitter role' do before :each do + create(:cfp, program: conference.program, cfp_type: 'booths') sign_in booth.submitter end From e73218b5ca009ee7a159d55b99f09db320ec6951 Mon Sep 17 00:00:00 2001 From: nasia Date: Fri, 28 Jul 2017 21:46:48 +0300 Subject: [PATCH 167/237] Add booth limit --- .haml-lint_todo.yml | 2 ++ app/controllers/admin/booths_controller.rb | 23 +++++++++++-------- .../admin/conferences_controller.rb | 2 +- app/models/booth.rb | 1 + app/models/conference.rb | 9 ++++++++ .../booths/_change_state_dropdown.html.haml | 16 +++++++------ app/views/admin/booths/index.html.haml | 22 ++++++++++++++++++ app/views/admin/conferences/edit.html.haml | 3 +++ ...28182033_add_booth_limit_to_conferences.rb | 5 ++++ db/schema.rb | 1 + 10 files changed, 66 insertions(+), 18 deletions(-) create mode 100644 db/migrate/20170728182033_add_booth_limit_to_conferences.rb diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index a456dcd2..2e4c2995 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -11,6 +11,8 @@ linters: # Offense count: 945 LineLength: exclude: + - "app/views/admin/booths/_change_state_dropdown.html.haml" + - "app/views/admin/booths/_form.html.haml" - "app/views/admin/booths/index.html.haml" - "app/views/admin/booths/show.html.haml" - "app/views/admin/campaigns/_form.html.haml" diff --git a/app/controllers/admin/booths_controller.rb b/app/controllers/admin/booths_controller.rb index a200e42e..26bacc8f 100644 --- a/app/controllers/admin/booths_controller.rb +++ b/app/controllers/admin/booths_controller.rb @@ -47,18 +47,21 @@ module Admin end def accept - @booth.accept! - if @booth.save - if @conference.email_settings.send_on_booths_acceptance - Mailbot.conference_booths_acceptance_mail(@booth).deliver + if can? :accept, @booth + @booth.accept! + + if @booth.save + if @conference.email_settings.send_on_booths_acceptance + Mailbot.conference_booths_acceptance_mail(@booth).deliver + end + redirect_to admin_conference_booths_path(conference_id: @conference.short_title), + notice: 'Booth successfully accepted!' + else + redirect_to admin_conference_booths_path(conference_id: @conference.short_title) + flash[:error] = "Booth could not be accepted. #{@booth.errors.full_messages.to_sentence}." end - redirect_to admin_conference_booths_path(conference_id: @conference.short_title), - notice: 'Booth successfully accepted!' - else - redirect_to admin_conference_booths_path(conference_id: @conference.short_title) - flash[:error] = "Booth could not be accepted. #{@booth.errors.full_messages.to_sentence}." - end + end end def to_accept diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index 6716a253..3905012c 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -211,7 +211,7 @@ module Admin :vpositions_attributes, :use_volunteers, :color, :sponsorship_levels_attributes, :sponsors_attributes, :targets, :targets_attributes, - :campaigns, :campaigns_attributes, :registration_limit, :organization_id, :ticket_layout) + :campaigns, :campaigns_attributes, :registration_limit, :organization_id, :ticket_layout, :booth_limit) end end end diff --git a/app/models/booth.rb b/app/models/booth.rb index d7cc3eb2..4e42d839 100644 --- a/app/models/booth.rb +++ b/app/models/booth.rb @@ -25,6 +25,7 @@ class Booth < ActiveRecord::Base :submitter_relationship, presence: true + scope :accepted, -> { where(state: 'accepted') } scope :confirmed, -> { where(state: 'confirmed') } mount_uploader :picture, PictureUploader, mount_on: :logo_link diff --git a/app/models/conference.rb b/app/models/conference.rb index b528d755..729db645 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -738,6 +738,15 @@ class Conference < ActiveRecord::Base (start_hour..(end_hour - 1)).cover?(current_hour) ? current_hour - start_hour : 0 end + ## + # + # ====Returns + # * +True+ -> if accepted booths are equal to the booth limit + # * +False+ -> Accepted booths have not reached the booth limit + def maximum_accepted_booths? + booth_limit > 0 && booths.accepted.count + booths.confirmed.count >= booth_limit + end + ## # Return the current conference object to be used in RevisionCount # diff --git a/app/views/admin/booths/_change_state_dropdown.html.haml b/app/views/admin/booths/_change_state_dropdown.html.haml index 8178a790..85f8b971 100644 --- a/app/views/admin/booths/_change_state_dropdown.html.haml +++ b/app/views/admin/booths/_change_state_dropdown.html.haml @@ -1,11 +1,13 @@ - if booth.transition_possible? :accept - - if @conference.email_settings.send_on_booths_acceptance - - link = 'Accept with email' - - else - - link = 'Accept booth' - %li= link_to link, - accept_admin_conference_booth_path(@conference.short_title, booth), - method: :patch ,id: "accept_booth_#{booth.id}" + - if can? :accept, @booth + - if @conference.email_settings.send_on_booths_acceptance + - link = 'Accept with email' + - else + - link = 'Accept booth' + %li= link_to link, + accept_admin_conference_booth_path(@conference.short_title, booth), + method: :patch ,id: "accept_booth_#{booth.id}", + data: (@conference.booth_limit > 0 ? { confirm: 'You are able to accept '+ pluralize(@conference.booth_limit - @conference.booths.accepted.count, 'more booth') + " (booth limit set to #{@conference.booth_limit}). Are you sure you want to accept this one?" } : nil ) - if booth.transition_possible? :reject - if @conference.email_settings.send_on_booths_rejection diff --git a/app/views/admin/booths/index.html.haml b/app/views/admin/booths/index.html.haml index 27f505ad..a7ee53cd 100644 --- a/app/views/admin/booths/index.html.haml +++ b/app/views/admin/booths/index.html.haml @@ -9,8 +9,30 @@ = link_to 'Add Booth', new_admin_conference_booth_path(@conference.short_title), class: 'button btn btn-primary' %p.text-muted All the booth requests + + .row .col-md-12 + %h4 + - if @conference.booth_limit == 0 + %p + Set the + = link_to 'Booth limit', edit_admin_conference_path(@conference.short_title) + to make sure you are not accepting more booths than you can accommodate. + - elsif !@conference.maximum_accepted_booths? + %p + You cannot accept more than + %b + = pluralize(@conference.booth_limit, 'booth') + ( + = pluralize(@conference.booths.accepted.count + @conference.booths.confirmed.count, 'accepted booth') + so far) + - else + %p + You have reached the maximum number of accepted booths. + ( + = link_to "#{@conference.booth_limit} booths", edit_admin_conference_path(@conference.short_title) + ) .margin-booth-table %table.table.table-striped.table-bordered.table-hover.datatable %thead diff --git a/app/views/admin/conferences/edit.html.haml b/app/views/admin/conferences/edit.html.haml index 2d5df126..26ae198f 100644 --- a/app/views/admin/conferences/edit.html.haml +++ b/app/views/admin/conferences/edit.html.haml @@ -26,4 +26,7 @@ = f.input :end_hour, input_html: {size: 2, type: 'number', min: 1, max: 24} = f.inputs name: 'Registrations' do = f.input :registration_limit, as: :number, in: 0..9999, hint: 'Limit the number of registrations to the conference (0 no limit). Please note that the registration limit doesn\'t apply to speakers of confirmed events (they will still be able to register even if it has been reached). You currently have ' + pluralize(@conference.registrations.count, 'registration') + = f.inputs name: 'Booths' do + = f.input :booth_limit, as: :number, in: 0..9999, + hint: 'Booth limit is the maximum number of booths that you can accept for this conference. By setting this number (0 no limit) you can be sure that you are not going to accept more booths than the conference can accommodate. You currently have ' + pluralize(@conference.booths.accepted.count, 'accepted booth') +'.' = f.action :submit, as: :button, button_html: {class: 'btn btn-primary'} diff --git a/db/migrate/20170728182033_add_booth_limit_to_conferences.rb b/db/migrate/20170728182033_add_booth_limit_to_conferences.rb new file mode 100644 index 00000000..60643784 --- /dev/null +++ b/db/migrate/20170728182033_add_booth_limit_to_conferences.rb @@ -0,0 +1,5 @@ +class AddBoothLimitToConferences < ActiveRecord::Migration + def change + add_column :conferences, :booth_limit, :integer, default: 0 + end +end diff --git a/db/schema.rb b/db/schema.rb index 6c40c572..83499b33 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -127,6 +127,7 @@ ActiveRecord::Schema.define(version: 20170807092805) do t.integer "end_hour", default: 20 t.integer "organization_id" t.integer "ticket_layout", default: 0 + t.integer "booth_limit", default: 0 end add_index "conferences", ["organization_id"], name: "index_conferences_on_organization_id" From 52cde784fa7c8f1ddb4cae926d744bdd8a19ddfe Mon Sep 17 00:00:00 2001 From: nasia Date: Tue, 15 Aug 2017 18:02:51 +0300 Subject: [PATCH 168/237] Add :accept booth to ability --- .rubocop_todo.yml | 3 + app/controllers/admin/booths_controller.rb | 23 +++-- app/models/admin_ability.rb | 5 ++ .../booths/_change_state_dropdown.html.haml | 11 ++- app/views/admin/booths/index.html.haml | 84 +++++++++---------- app/views/admin/emails/index.html.haml | 2 +- 6 files changed, 68 insertions(+), 60 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 38bf269f..a91f2ae9 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -330,6 +330,8 @@ Metrics/LineLength: # Configuration parameters: CountComments. Metrics/MethodLength: Max: 56 + Exclude: + - 'app/models/admin_ability.rb' # Offense count: 3 # Configuration parameters: CountComments. @@ -443,6 +445,7 @@ Style/HashSyntax: # Configuration parameters: MaxLineLength. Style/IfUnlessModifier: Exclude: + - 'app/controllers/admin/booths_controller.rb' - 'app/controllers/admin/events_controller.rb' - 'app/controllers/api/v1/events_controller.rb' - 'app/controllers/conference_registrations_controller.rb' diff --git a/app/controllers/admin/booths_controller.rb b/app/controllers/admin/booths_controller.rb index 26bacc8f..a200e42e 100644 --- a/app/controllers/admin/booths_controller.rb +++ b/app/controllers/admin/booths_controller.rb @@ -47,21 +47,18 @@ module Admin end def accept + @booth.accept! - if can? :accept, @booth - @booth.accept! - - if @booth.save - if @conference.email_settings.send_on_booths_acceptance - Mailbot.conference_booths_acceptance_mail(@booth).deliver - end - redirect_to admin_conference_booths_path(conference_id: @conference.short_title), - notice: 'Booth successfully accepted!' - else - redirect_to admin_conference_booths_path(conference_id: @conference.short_title) - flash[:error] = "Booth could not be accepted. #{@booth.errors.full_messages.to_sentence}." + if @booth.save + if @conference.email_settings.send_on_booths_acceptance + Mailbot.conference_booths_acceptance_mail(@booth).deliver end - end + redirect_to admin_conference_booths_path(conference_id: @conference.short_title), + notice: 'Booth successfully accepted!' + else + redirect_to admin_conference_booths_path(conference_id: @conference.short_title) + flash[:error] = "Booth could not be accepted. #{@booth.errors.full_messages.to_sentence}." + end end def to_accept diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 466380cc..f742b775 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -74,6 +74,11 @@ class AdminAbility cannot :destroy, Track do |track| track.self_organized? end + # Can't accept a booth when booth_limit is reached + cannot :accept, Booth do |booth| + conference = booth.conference + conference.maximum_accepted_booths? + end end # Abilities for signed in users with roles diff --git a/app/views/admin/booths/_change_state_dropdown.html.haml b/app/views/admin/booths/_change_state_dropdown.html.haml index 85f8b971..12b982df 100644 --- a/app/views/admin/booths/_change_state_dropdown.html.haml +++ b/app/views/admin/booths/_change_state_dropdown.html.haml @@ -1,13 +1,17 @@ + - if booth.transition_possible? :accept - - if can? :accept, @booth + - if can? :accept, booth + - if @conference.booth_limit > 0 + - confirm_message = ' You are able to accept '+ pluralize(@conference.booth_limit - (@conference.booths.accepted.count + @conference.booths.confirmed.count), 'more booth') + " (booth limit set to #{@conference.booth_limit}). Are you sure you want to accept this one?" - if @conference.email_settings.send_on_booths_acceptance - link = 'Accept with email' + - confirm_message = "By accepting this booth, an email will be sent informing the submitter for the acceptance. You may change the state to \'To accept\' until you are completely sure." + confirm_message - else - link = 'Accept booth' %li= link_to link, accept_admin_conference_booth_path(@conference.short_title, booth), method: :patch ,id: "accept_booth_#{booth.id}", - data: (@conference.booth_limit > 0 ? { confirm: 'You are able to accept '+ pluralize(@conference.booth_limit - @conference.booths.accepted.count, 'more booth') + " (booth limit set to #{@conference.booth_limit}). Are you sure you want to accept this one?" } : nil ) + data: (confirm_message ? { confirm: confirm_message } : nil) - if booth.transition_possible? :reject - if @conference.email_settings.send_on_booths_rejection @@ -16,7 +20,8 @@ - link = 'Reject' %li= link_to link, reject_admin_conference_booth_path(@conference.short_title, booth), - method: :patch, id: "reject_booth_#{booth.id}" + method: :patch, id: "reject_booth_#{booth.id}", + data: (@conference.email_settings.send_on_booths_rejection ? { confirm: 'By rejecting this booth, an email will be sent informing the submitter about the rejection. You may change the state to \'To reject\' until you are completely sure.'} : nil) - if booth.transition_possible? :to_reject %li= link_to 'To reject booth', diff --git a/app/views/admin/booths/index.html.haml b/app/views/admin/booths/index.html.haml index a7ee53cd..fc3f3ba3 100644 --- a/app/views/admin/booths/index.html.haml +++ b/app/views/admin/booths/index.html.haml @@ -10,7 +10,6 @@ %p.text-muted All the booth requests - .row .col-md-12 %h4 @@ -33,46 +32,45 @@ ( = link_to "#{@conference.booth_limit} booths", edit_admin_conference_path(@conference.short_title) ) - .margin-booth-table - %table.table.table-striped.table-bordered.table-hover.datatable - %thead - %th - %b ID - %th - %b Logo - %th - %b Title - %th - %b Submitter - %th - %b Responsibles - %th - %b State - %th - %b Actions - - @booths.each do |booth| - %tr + %table.table.table-striped.table-bordered.table-hover.datatable + %thead + %th + %b ID + %th + %b Logo + %th + %b Title + %th + %b Submitter + %th + %b Responsibles + %th + %b State + %th + %b Actions + - @booths.each do |booth| + %tr + %td + = booth.id + %td + - if booth.logo_link + = image_tag(booth.picture.thumb.url, width: '20%') + %td + = link_to booth.title, admin_conference_booth_path(@conference.short_title, booth) + %td + = link_to booth.submitter.name, admin_user_path(booth.submitter) if booth.submitter + %td + .responsibles + - booth.responsibles.each_with_index do |responsible, i| + = link_to responsible.name, admin_user_path(responsible) + = ", " unless i == booth.responsibles.length - 1 + %td + .btn-group + %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } + = booth.state.humanize + %span.caret + %ul.dropdown-menu{ role: 'menu' } + = render 'change_state_dropdown', booth: booth %td - = booth.id - %td - - if booth.logo_link - = image_tag(booth.picture.thumb.url, width: '20%') - %td - = link_to booth.title, admin_conference_booth_path(@conference.short_title, booth) - %td - = link_to booth.submitter.name, admin_user_path(booth.submitter) if booth.submitter - %td - .responsibles - - booth.responsibles.each_with_index do |responsible, i| - = link_to responsible.name, admin_user_path(responsible) - = ", " unless i == booth.responsibles.length - 1 - %td - .btn-group - %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } - = booth.state.humanize - %span.caret - %ul.dropdown-menu{ role: 'menu' } - = render 'change_state_dropdown', booth: booth - %td - = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id), - class: 'btn btn-primary' + = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id), + class: 'btn btn-primary' diff --git a/app/views/admin/emails/index.html.haml b/app/views/admin/emails/index.html.haml index 99d02130..83ebe210 100644 --- a/app/views/admin/emails/index.html.haml +++ b/app/views/admin/emails/index.html.haml @@ -109,7 +109,7 @@ %a.btn.btn-link.control_label.load_template{ 'data-subject-input-id' => 'email_settings_booths_acceptance_subject', 'data-subject-text' => 'Your booth has been accepted!', 'data-body-input-id' => 'email_settings_booths_acceptance_body', - 'data-body-text' => "Dear {name},\n\nWe are really pleased to inform you that your booth request {booth_title} has been accepted for the conference {conference}.\nPlease click the confirm button to let us know you can make it as soon as possible!\n\nFeel free to contact us with any questions or concerns.\n\nWe look forward to seeing you there.\n\nBest wishes\n\n{conference} Team"} Load Template + 'data-body-text' => "Dear {name},\n\nWe are pleased to inform you that your booth request {booth_title} has been accepted for the conference {conference}.\nPlease click the confirm button to let us know you can make it as soon as possible!\n\nFeel free to contact us with any questions or concerns.\n\nWe are looking forward to seeing you there.\n\nBest wishes\n\n{conference} Team"} Load Template %a.btn.btn-link.control_label.template_help_link{ 'data-name' => 'booth_acceptance_help' } Show help = render partial: 'help', locals: {id: 'booth_acceptance_help', show_event_variables: false} = f.input :send_on_booths_rejection From d0a961099261fbb6ed0569957caf5e87eddcdb66 Mon Sep 17 00:00:00 2001 From: nikhilgupta1211 Date: Sun, 20 Aug 2017 16:27:35 +0530 Subject: [PATCH 169/237] Made Sidebar collapsible for small screens Added a hamburger button in _admin_html.haml for navbar collapse Fixes #853 --- app/assets/stylesheets/osem.css.scss | 6 ++++++ app/views/layouts/_admin_sidebar.html.haml | 2 +- app/views/layouts/_navigation.html.haml | 10 ++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/osem.css.scss b/app/assets/stylesheets/osem.css.scss index 5a331436..775418b3 100644 --- a/app/assets/stylesheets/osem.css.scss +++ b/app/assets/stylesheets/osem.css.scss @@ -94,3 +94,9 @@ p.comment-body { .box{ height: 230px; } + +/* sidebar hamburger btn */ +.side-nav-btn{ + margin-left: 10px; + float: left; +} diff --git a/app/views/layouts/_admin_sidebar.html.haml b/app/views/layouts/_admin_sidebar.html.haml index 1c7bac9a..28ef62e2 100644 --- a/app/views/layouts/_admin_sidebar.html.haml +++ b/app/views/layouts/_admin_sidebar.html.haml @@ -1,4 +1,4 @@ -%ul.nav.nav-stacked.nav-pills.mySidebar +%ul.nav.nav-stacked.nav-pills.mySidebar.collapse.navbar-collapse#side-nav .btn-group %button{type:'button', class: 'btn btn-default btn-link dropdown-toggle', 'data-toggle'=>'dropdown'} %span.fa.fa-cog diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index 9750be92..9995123b 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -1,7 +1,13 @@ .navbar.navbar-default.navbar-fixed-top.nav-osem{role: 'navigation'} .container .navbar-header - %button{"data-target"=>".navbar-collapse", "data-toggle"=>"collapse", class: 'navbar-toggle', type: 'button'} + - if @conference && @conference.short_title.present? + %button{ "data-target"=>"#side-nav", "data-toggle"=>"collapse", class: 'navbar-toggle side-nav-btn', type: 'button' } + %span.sr-only Toggle navigation + %span.icon-bar + %span.icon-bar + %span.icon-bar + %button{"data-target"=>"#main-nav", "data-toggle"=>"collapse", class: 'navbar-toggle', type: 'button'} %span.sr-only Toggle navigation %span.icon-bar @@ -11,7 +17,7 @@ = link_to (ENV['OSEM_NAME'] || 'OSEM'), root_path, class: 'navbar-brand', title: 'Open Source Event Manager' - else = link_to conference.organization.name, organizations_path, class: 'navbar-brand', title: 'Open Source Event Manager' - .collapse.navbar-collapse + .collapse.navbar-collapse#main-nav - if content_for :splash_nav %ul.nav.navbar-nav#splash-nav = content_for :splash_nav From 4b735cff69f9ac8f316d25d095c079d971024eb1 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Thu, 27 Jul 2017 17:25:17 +0530 Subject: [PATCH 170/237] Added qr code Added qr code on ticket pdf and ticket show page. --- app/assets/stylesheets/osem.css.scss | 4 ++++ app/controllers/physical_ticket_controller.rb | 1 + app/pdfs/ticket_pdf.rb | 6 +++++- app/views/physical_ticket/show.html.haml | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/osem.css.scss b/app/assets/stylesheets/osem.css.scss index 775418b3..79768c5d 100644 --- a/app/assets/stylesheets/osem.css.scss +++ b/app/assets/stylesheets/osem.css.scss @@ -99,4 +99,8 @@ p.comment-body { .side-nav-btn{ margin-left: 10px; float: left; + } + +.qr-image{ + margin-left: 120px; } diff --git a/app/controllers/physical_ticket_controller.rb b/app/controllers/physical_ticket_controller.rb index fb25ae63..af02155c 100644 --- a/app/controllers/physical_ticket_controller.rb +++ b/app/controllers/physical_ticket_controller.rb @@ -13,6 +13,7 @@ class PhysicalTicketController < ApplicationController @file_name = "ticket_for_#{@conference.short_title}" @user = @physical_ticket.user @ticket_layout = @conference.ticket_layout.to_sym + @qrcode_image = RQRCode::QRCode.new(@physical_ticket.token).as_png(size: 180, border_modules: 0) respond_to do |format| format.html format.pdf do diff --git a/app/pdfs/ticket_pdf.rb b/app/pdfs/ticket_pdf.rb index 1c26ec77..ecb4cd2c 100644 --- a/app/pdfs/ticket_pdf.rb +++ b/app/pdfs/ticket_pdf.rb @@ -77,5 +77,9 @@ class TicketPdf < Prawn::Document move_up 180 end - def draw_fourth_square; end + def draw_fourth_square + x = @mid_horizontal + (@right - @mid_horizontal - 180) / 2 + y = cursor - (bounds.top - @mid_vertical - 180) / 2 + print_qr_code(@physical_ticket.token, pos: [x, y], extent: 180, stroke: false) + end end diff --git a/app/views/physical_ticket/show.html.haml b/app/views/physical_ticket/show.html.haml index 067f0a9b..40513ae8 100644 --- a/app/views/physical_ticket/show.html.haml +++ b/app/views/physical_ticket/show.html.haml @@ -67,6 +67,7 @@ = @physical_ticket.ticket_purchase.id %br .col-md-5.col-md-offset-2.box.well + = image_tag(@qrcode_image.to_data_url, class: 'img-responsive qr-image') .row .col-md-12 %p.text-left From 157c270497356ad17e8c18a0946025aba9d5c108 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Sat, 12 Aug 2017 01:27:16 +0530 Subject: [PATCH 171/237] Registration tickets to be set for registration period Admin must create at least one registration ticket before creating registration period. --- app/models/admin_ability.rb | 5 ++++- app/models/conference.rb | 6 +++++- app/views/admin/registration_periods/show.html.haml | 11 +++++++++-- .../admin/registration_periods_controller_spec.rb | 2 +- spec/factories/tickets.rb | 3 +++ spec/features/organization_admin_ability_spec.rb | 1 + spec/features/organizer_ability_spec.rb | 1 + spec/features/registration_periods_spec.rb | 1 + spec/models/admin_ability_spec.rb | 1 + spec/models/registration_period_spec.rb | 1 + 10 files changed, 27 insertions(+), 5 deletions(-) diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index f742b775..39183543 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -123,7 +123,10 @@ class AdminAbility can :manage, Commercial, commercialable_type: 'Conference', commercialable_id: conf_ids can :manage, Registration, conference_id: conf_ids - can :manage, RegistrationPeriod, conference_id: conf_ids + can :manage, RegistrationPeriod do |registration_period| + conference = registration_period.conference + conf_ids.include?(conference.id) && conference.tickets.for_registration.any? + end can :manage, Booth, conference_id: conf_ids can :manage, Question, conference_id: conf_ids can :manage, Question do |question| diff --git a/app/models/conference.rb b/app/models/conference.rb index 729db645..919bf7e5 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -26,7 +26,11 @@ class Conference < ActiveRecord::Base has_many :ticket_purchases, dependent: :destroy has_many :payments, dependent: :destroy has_many :supporters, through: :ticket_purchases, source: :user - has_many :tickets, dependent: :destroy + has_many :tickets, dependent: :destroy do + def for_registration + where(registration_ticket: true) + end + end has_many :resources, dependent: :destroy has_many :booths, dependent: :destroy diff --git a/app/views/admin/registration_periods/show.html.haml b/app/views/admin/registration_periods/show.html.haml index 057a7a37..e923d089 100644 --- a/app/views/admin/registration_periods/show.html.haml +++ b/app/views/admin/registration_periods/show.html.haml @@ -25,5 +25,12 @@ = link_to 'Delete', admin_conference_registration_period_path, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' - else - - if can? :create, @conference.build_registration_period - = link_to 'New Registration Period', new_admin_conference_registration_period_path, class: 'btn btn-primary' + - unless @conference.tickets.for_registration.empty? + - if can? :create, @conference.build_registration_period + = link_to 'New Registration Period', new_admin_conference_registration_period_path, class: 'btn btn-primary' + - else + .h3.text-left + No Registration Tickets! + %small + = link_to 'Create registration tickets', new_admin_conference_ticket_path + before creating the registration period. diff --git a/spec/controllers/admin/registration_periods_controller_spec.rb b/spec/controllers/admin/registration_periods_controller_spec.rb index 6177fde7..fd98ce77 100644 --- a/spec/controllers/admin/registration_periods_controller_spec.rb +++ b/spec/controllers/admin/registration_periods_controller_spec.rb @@ -5,7 +5,7 @@ describe Admin::RegistrationPeriodsController do # It is necessary to use bang version of let to build roles before user let(:conference) { create(:conference) } let!(:organizer_role) { Role.find_by(name: 'organizer', resource: conference) } - + let!(:registration_ticket) { create(:registration_ticket, conference: conference) } let(:organizer) { create(:user, role_ids: organizer_role.id) } let(:organizer2) { create(:user, email: 'organizer2@email.osem', role_ids: organizer_role.id) } let(:participant) { create(:user) } diff --git a/spec/factories/tickets.rb b/spec/factories/tickets.rb index 88532b86..c4bb1539 100644 --- a/spec/factories/tickets.rb +++ b/spec/factories/tickets.rb @@ -3,5 +3,8 @@ FactoryGirl.define do title { "#{Faker::Hipster.word} Ticket" } price_cents 1000 price_currency 'USD' + factory :registration_ticket do + registration_ticket true + end end end diff --git a/spec/features/organization_admin_ability_spec.rb b/spec/features/organization_admin_ability_spec.rb index 8bccd2cf..d84a7c01 100644 --- a/spec/features/organization_admin_ability_spec.rb +++ b/spec/features/organization_admin_ability_spec.rb @@ -5,6 +5,7 @@ feature 'Has correct abilities' do let(:conference) { create(:full_conference, organization: organization) } let(:role_organization_admin) { Role.find_by(name: 'organization_admin', resource: organization) } let(:user_organization_admin) { create(:user, role_ids: [role_organization_admin.id]) } + let!(:registration_ticket) { create(:registration_ticket, conference: conference) } context 'when user is organization_admin' do before do diff --git a/spec/features/organizer_ability_spec.rb b/spec/features/organizer_ability_spec.rb index 5345b58c..0127ea2f 100644 --- a/spec/features/organizer_ability_spec.rb +++ b/spec/features/organizer_ability_spec.rb @@ -8,6 +8,7 @@ feature 'Has correct abilities' do let(:role_organizer_conf) { Role.find_by(name: 'organizer', resource: conference) } let(:role_organizer_other_conf) { Role.find_by(name: 'organizer', resource: other_conference) } let(:user_organizer) { create(:user, role_ids: [role_organizer_conf.id, role_organizer_other_conf.id]) } + let!(:registration_ticket) { create(:registration_ticket, conference: conference) } context 'when user is organizer' do before do diff --git a/spec/features/registration_periods_spec.rb b/spec/features/registration_periods_spec.rb index c6cc992e..5c1c90b5 100644 --- a/spec/features/registration_periods_spec.rb +++ b/spec/features/registration_periods_spec.rb @@ -6,6 +6,7 @@ feature RegistrationPeriod do let!(:conference) { create(:conference) } let!(:organizer_role) { Role.find_by(name: 'organizer', resource: conference) } let!(:organizer) { create(:user, email: 'admin@example.com', role_ids: [organizer_role.id]) } + let!(:registration_ticket) { create(:registration_ticket, conference: conference) } shared_examples 'successfully' do scenario 'create and update registration period', js: true do diff --git a/spec/models/admin_ability_spec.rb b/spec/models/admin_ability_spec.rb index 126d32de..805dd621 100644 --- a/spec/models/admin_ability_spec.rb +++ b/spec/models/admin_ability_spec.rb @@ -11,6 +11,7 @@ describe 'User with admin role' do let!(:organization) { create(:organization) } let!(:my_conference) { create(:full_conference, organization: organization) } + let!(:registration_ticket) { create(:registration_ticket, conference: my_conference) } let(:my_venue) { my_conference.venue || create(:venue, conference: my_conference) } let(:my_registration) { create(:registration, conference: my_conference, user: admin) } diff --git a/spec/models/registration_period_spec.rb b/spec/models/registration_period_spec.rb index ef28bab1..52fb3755 100644 --- a/spec/models/registration_period_spec.rb +++ b/spec/models/registration_period_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe RegistrationPeriod do let!(:conference) { create(:conference, start_date: Date.today, end_date: Date.today + 6) } + let!(:registration_ticket) { create(:registration_ticket, conference: conference) } let!(:registration_period) { create(:registration_period, start_date: Date.today - 2, end_date: Date.today - 1, conference: conference) } describe 'validations' do From db8fdb3d387ad70671f6b262f5f1d301990dfce7 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 22 Aug 2017 17:24:50 +0530 Subject: [PATCH 172/237] add permissions and actions to assign and unassign organization admin role --- .../admin/organizations_controller.rb | 42 +++++++++++++++++++ app/models/admin_ability.rb | 8 ++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/app/controllers/admin/organizations_controller.rb b/app/controllers/admin/organizations_controller.rb index 087bf7f8..d125c5cf 100644 --- a/app/controllers/admin/organizations_controller.rb +++ b/app/controllers/admin/organizations_controller.rb @@ -1,6 +1,7 @@ module Admin class OrganizationsController < Admin::BaseController load_and_authorize_resource :organization + before_action :verify_user, only: [:assign_org_admins, :unassign_org_admins] def index @organizations = Organization.all @@ -43,8 +44,49 @@ module Admin end end + def assign_org_admins + if @user.has_role? 'organization_admin', @organization + flash[:error] = "User #{@user.email} already has the role organization admin" + elsif @user.add_role 'organization_admin', @organization + flash[:notice] = "Successfully added role organization admin to user #{@user.email}" + else + flash[:error] = "Coud not add role organization admin to #{@user.email}" + end + + redirect_to admins_admin_organization_path(@organization) + end + + def unassign_org_admins + if @user.remove_role 'organization_admin', @organization + flash[:notice] = "Successfully removed role organization admin from user #{@user.email}" + else + flash[:error] = "Could not remove role organization admin from user #{@user.email}" + end + + redirect_to admins_admin_organization_path(@organization) + end + + def admins + @role = @organization.roles.first + @users = @role.users + render 'show_org_admins' + end + private + def user_params + params.require(:user).permit(:email) + end + + def verify_user + @user = User.find_by(email: user_params[:email]) + unless @user + redirect_to admins_admin_organization_path(@organization), + error: 'Could not find user. Please provide a valid email!' + return + end + end + def organization_params params.require(:organization).permit(:name, :description, :picture) end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 39183543..cfe17d1d 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -28,7 +28,7 @@ class AdminAbility conference.registration_open? && !conference.registration_limit_exceeded? || conference.program.speakers.confirmed.include?(user) end - can :index, Organization + can [:index, :admins], Organization can :index, Ticket can :manage, TicketPurchase, user_id: user.id can [:new, :create], Payment, user_id: user.id @@ -96,13 +96,11 @@ class AdminAbility org_ids_for_organization_admin = Organization.with_role(:organization_admin, user).pluck(:id) conf_ids_for_organization_admin = Conference.where(organization_id: org_ids_for_organization_admin).pluck(:id) - can [:read, :update, :destroy], Organization, id: org_ids_for_organization_admin + can [:read, :update, :destroy, :assign_org_admins, :unassign_org_admins, :admins], Organization, id: org_ids_for_organization_admin can :new, Conference can :manage, Conference, organization_id: org_ids_for_organization_admin can [:index, :show], Role - can [:edit, :update], Role do |role| - role.resource_type == 'Organization' && (org_ids_for_organization_admin.include? role.resource_id) - end + signed_in_with_organizer_role(user, conf_ids_for_organization_admin) end From a91c67be0afa368e5ed0d5a262603ca84cbb7b30 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 22 Aug 2017 17:25:34 +0530 Subject: [PATCH 173/237] add views for organization admin role --- .haml-lint_todo.yml | 1 + .../_users_with_org_admin_role.haml | 25 +++++++++++++++++++ app/views/admin/organizations/index.html.haml | 2 ++ .../admin/organizations/show_org_admins.haml | 24 ++++++++++++++++++ config/routes.rb | 8 +++++- 5 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 app/views/admin/organizations/_users_with_org_admin_role.haml create mode 100644 app/views/admin/organizations/show_org_admins.haml diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 2e4c2995..25ccb622 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -78,6 +78,7 @@ linters: - "app/views/admin/resources/show.html.haml" - "app/views/admin/roles/_form.html.haml" - "app/views/admin/roles/_users.html.haml" + - "app/views/admin/roles/_users_with_org_admin_role.haml" - "app/views/admin/roles/index.html.haml" - "app/views/admin/roles/show.html.haml" - "app/views/admin/rooms/_form.html.haml" diff --git a/app/views/admin/organizations/_users_with_org_admin_role.haml b/app/views/admin/organizations/_users_with_org_admin_role.haml new file mode 100644 index 00000000..e107868c --- /dev/null +++ b/app/views/admin/organizations/_users_with_org_admin_role.haml @@ -0,0 +1,25 @@ +.page-header + %h3 Users (#{users.length}) +- if users.present? + %table.table.table-striped.table-bordered.table-hover.datatable#users + %thead + %th Name + %th Email + - if ( can? :unassign_org_admins, organization ) + %th + Actions + %tbody + - users.each do |user| + %tr + %td= user.name + %td= user.email + - if ( can? :unassign_org_admins, organization ) + %td + = link_to 'Remove from organization admin', + unassign_org_admins_admin_organization_path(organization.id, + role.name, + user: {email: user.email}), + method: :delete, + class: 'btn btn-danger' +- else + %h5 No users found! diff --git a/app/views/admin/organizations/index.html.haml b/app/views/admin/organizations/index.html.haml index aa682c57..baf9bc80 100644 --- a/app/views/admin/organizations/index.html.haml +++ b/app/views/admin/organizations/index.html.haml @@ -25,6 +25,8 @@ = organization.conferences.past.count %td .btn-group + = link_to 'Admins', admins_admin_organization_path(organization), + method: :get, class: 'btn btn-success' = link_to 'Edit', edit_admin_organization_path(organization), method: :get, class: 'btn btn-primary' = link_to 'Delete', admin_organization_path(organization), diff --git a/app/views/admin/organizations/show_org_admins.haml b/app/views/admin/organizations/show_org_admins.haml new file mode 100644 index 00000000..7fe1f943 --- /dev/null +++ b/app/views/admin/organizations/show_org_admins.haml @@ -0,0 +1,24 @@ +.row + .col-md-12 + .page-header + %h2 + Organization admins for #{@organization.name} + .text-muted + = @role.description + +.row.col-md-3 + - if ( can? :assign_org_admins, @organization ) + = semantic_form_for :user, + url: assign_org_admins_admin_organization_path(@organization, + @role.name), method: :post do |u| + + = u.label 'Add user by email: ' + .input-group + = u.input :email, label: false, placeholder: "User's email" + .input-group-btn + = u.submit 'Add', id: 'user-add', class: 'btn btn-primary' + +.row + .col-md-12 + = render partial: 'users_with_org_admin_role', + locals: { users: @users, organization: @organization, role: @role } diff --git a/config/routes.rb b/config/routes.rb index 523a076d..3b955953 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -20,7 +20,13 @@ Osem::Application.routes.draw do end namespace :admin do - resources :organizations + resources :organizations do + member do + get :admins + post :assign_org_admins + delete :unassign_org_admins + end + end resources :users do member do patch :toggle_confirmation From c596a9fda7a541f769d12d402eeb7f88201e8b38 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 22 Aug 2017 17:26:11 +0530 Subject: [PATCH 174/237] add tests to assign and unassign organization admin role --- .../admin/organizations_controller_spec.rb | 27 +++++++++++ .../admin/roles_controller_spec.rb | 1 - spec/features/roles_spec.rb | 45 +++++++++++++++++++ spec/models/admin_ability_spec.rb | 18 +++++++- 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/spec/controllers/admin/organizations_controller_spec.rb b/spec/controllers/admin/organizations_controller_spec.rb index abe5005b..801cce83 100644 --- a/spec/controllers/admin/organizations_controller_spec.rb +++ b/spec/controllers/admin/organizations_controller_spec.rb @@ -167,5 +167,32 @@ describe Admin::OrganizationsController do end end end + + describe 'POST #assign_org_admins' do + let(:org_admin_role) { Role.find_by(name: 'organization_admin', resource: organization) } + + before do + post :assign_org_admins, id: organization.id, + user: { email: user.email } + end + + it 'assigns organization_admin role' do + expect(user.roles).to eq [org_admin_role] + end + end + + describe 'DELETE #unassign_org_admins' do + let(:org_admin_role) { Role.find_by(name: 'organization_admin', resource: organization) } + let!(:org_admin_user) { create(:user, role_ids: [org_admin_role.id]) } + + before do + delete :unassign_org_admins, id: organization.id, + user: { email: org_admin_user.email } + end + + it 'unassigns organization_admin role' do + expect(org_admin_user.reload.roles).to eq [] + end + end end end diff --git a/spec/controllers/admin/roles_controller_spec.rb b/spec/controllers/admin/roles_controller_spec.rb index d5cdc67e..dcc81313 100644 --- a/spec/controllers/admin/roles_controller_spec.rb +++ b/spec/controllers/admin/roles_controller_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe Admin::RolesController do - let(:conference) { create(:conference) } let(:organizer_role) { Role.find_by(name: 'organizer', resource: conference) } let(:cfp_role) { Role.find_by(name: 'cfp', resource: conference) } diff --git a/spec/features/roles_spec.rb b/spec/features/roles_spec.rb index ebdeacaf..ba9e5d4c 100644 --- a/spec/features/roles_spec.rb +++ b/spec/features/roles_spec.rb @@ -98,6 +98,51 @@ feature Role do end end + context 'organization_admin' do + let!(:organization) { create(:organization) } + let!(:org_admin_role) { Role.find_by(name: 'organization_admin', resource: organization) } + let!(:organization_admin) { create(:user, role_ids: [org_admin_role.id]) } + let(:user_with_no_role) { create :user } + let!(:other_organization) { create(:organization) } + + before do + sign_in organization_admin + visit admin_organizations_path + end + + context 'for the organization it belongs to' do + scenario 'successfully adds role organization_admin' do + click_link('Admins', href: admins_admin_organization_path(organization.id)) + + fill_in 'user_email', with: user_with_no_role.email + click_button 'Add' + user_with_no_role.reload + + expect(user_with_no_role.has_role?('organization_admin', organization)).to eq true + end + + scenario 'successfully removes role organization_admin' do + click_link('Admins', href: admins_admin_organization_path(organization.id)) + + first('tr').find('.btn-danger').click + expect(organization_admin.has_role?('organization_admin', organization)).to eq false + end + end + + context 'for the organizations it does not belong to' do + scenario 'does not successfully add role organization_admin' do + click_link('Admins', href: admins_admin_organization_path(other_organization.id)) + + expect(page.has_field?('user_email')).to eq false + end + + scenario 'does not successfully removes role organization_admin' do + click_link('Admins', href: admins_admin_organization_path(other_organization.id)) + expect(page.has_css?('.btn-danger')).to eq false + end + end + end + context 'organizer' do Role.all.each.map(&:name).each do |role| it_behaves_like 'successfully', role, 'organizer' diff --git a/spec/models/admin_ability_spec.rb b/spec/models/admin_ability_spec.rb index 805dd621..f148b2ae 100644 --- a/spec/models/admin_ability_spec.rb +++ b/spec/models/admin_ability_spec.rb @@ -63,7 +63,7 @@ describe 'User with admin role' do it{ should_not be_able_to(:update, Role.find_by(name: 'organization_admin', resource: other_organization)) } it{ should_not be_able_to(:edit, Role.find_by(name: 'organization_admin', resource: other_organization)) } - it{ should_not be_able_to(:show, Role.find_by(name: 'organization_admin', resource: other_organization)) } + it{ should be_able_to(:admins, organization) } it{ should_not be_able_to(:new, User.new) } it{ should_not be_able_to(:create, User.new) } @@ -127,6 +127,8 @@ describe 'User with admin role' do let(:other_organization) { create(:organization) } let(:other_conference) { create(:conference, organization: other_organization) } + it{ should be_able_to(:assign_org_admins, organization) } + it{ should be_able_to(:unassign_org_admins, organization) } it{ should be_able_to(:manage, my_conference) } it{ should be_able_to(:read, organization) } it{ should be_able_to(:update, organization) } @@ -137,6 +139,8 @@ describe 'User with admin role' do it{ should_not be_able_to(:create, Conference.new(organization_id: other_organization.id)) } it{ should_not be_able_to(:new, Organization.new) } it{ should_not be_able_to(:create, Organization.new) } + + it_behaves_like 'user with any role' end context 'when user has the role organizer' do @@ -214,6 +218,9 @@ describe 'User with admin role' do it{ should be_able_to(:manage, resource) } + it{ should_not be_able_to(:assign_org_admins, organization) } + it{ should_not be_able_to(:unassign_org_admins, organization) } + %w[organizer cfp info_desk volunteers_coordinator].each do |role| it{ should be_able_to(:toggle_user, Role.find_by(name: role, resource: my_conference)) } it{ should be_able_to(:edit, Role.find_by(name: role, resource: my_conference)) } @@ -299,6 +306,8 @@ describe 'User with admin role' do it{ should be_able_to(:index, resource) } it{ should be_able_to(:show, resource) } it{ should be_able_to(:update, resource) } + it{ should_not be_able_to(:assign_org_admins, organization) } + it{ should_not be_able_to(:unassign_org_admins, organization) } it_behaves_like 'user with any role' it_behaves_like 'user with non-organizer role', 'cfp' @@ -366,6 +375,8 @@ describe 'User with admin role' do it{ should be_able_to(:index, resource) } it{ should be_able_to(:show, resource) } it{ should be_able_to(:update, resource) } + it{ should_not be_able_to(:assign_org_admins, organization) } + it{ should_not be_able_to(:unassign_org_admins, organization) } it_behaves_like 'user with any role' it_behaves_like 'user with non-organizer role', 'info_desk' @@ -433,6 +444,8 @@ describe 'User with admin role' do it{ should be_able_to(:index, resource) } it{ should be_able_to(:show, resource) } it{ should be_able_to(:update, resource) } + it{ should_not be_able_to(:assign_org_admins, organization) } + it{ should_not be_able_to(:unassign_org_admins, organization) } it 'should be_able to :manage Vposition' it 'should be_able to :manage Vday' @@ -509,6 +522,9 @@ describe 'User with admin role' do it{ should_not be_able_to(:edit, my_self_organized_track) } it{ should_not be_able_to(:update, my_self_organized_track) } + it{ should_not be_able_to(:assign_org_admins, organization) } + it{ should_not be_able_to(:unassign_org_admins, organization) } + it_behaves_like 'user with any role' it_behaves_like 'user with non-organizer role', 'track_organizer' end From 48accd02aefbbfa8eadfb47523a1d23e28332a0a Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 22 Aug 2017 21:41:13 +0530 Subject: [PATCH 175/237] Fix warning in rspec --- spec/models/registration_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/registration_spec.rb b/spec/models/registration_spec.rb index 25ec9888..e7824c08 100644 --- a/spec/models/registration_spec.rb +++ b/spec/models/registration_spec.rb @@ -20,7 +20,7 @@ describe 'Registration' do describe 'registration_limit_not_exceed' do it 'is not valid when limit exceeded' do conference.registration_limit = 1 - expect { create(:registration, conference: conference, user: user) }.to raise_error + expect { create(:registration, conference: conference, user: user) }.to raise_error('Validation failed: User already Registered!, Registration limit exceeded') expect(user.registrations.size).to be 1 end end From 1a5aa14e2cb825ed79af4567cce5a2bf2790211b Mon Sep 17 00:00:00 2001 From: shlok007 Date: Sun, 13 Aug 2017 02:31:46 +0530 Subject: [PATCH 176/237] Mention organization name while creating a conference --- app/controllers/admin/conferences_controller.rb | 3 ++- app/views/admin/conferences/new.html.haml | 1 + spec/features/conference_spec.rb | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index 3905012c..d8c101d1 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -72,11 +72,12 @@ module Admin def new @conference = Conference.new + @organizations = Organization.accessible_by(current_ability, :update).pluck(:name, :id) end def create @conference = Conference.new(conference_params) - @conference.organization = Organization.find_or_create_by(name: 'organization') + if @conference.save # user that creates the conference becomes organizer of that conference current_user.add_role :organizer, @conference diff --git a/app/views/admin/conferences/new.html.haml b/app/views/admin/conferences/new.html.haml index 014758de..9e115457 100644 --- a/app/views/admin/conferences/new.html.haml +++ b/app/views/admin/conferences/new.html.haml @@ -2,6 +2,7 @@ .col-md-8 = semantic_form_for(@conference, url: admin_conferences_path) do |f| = f.inputs 'Basic Information' do + = f.input :organization, as: :select, collection: @organizations = f.input :title, hint: "The name of your conference as it shall appear throughout the site. Example: 'OpenSUSE Conference 2013'", input_html: { required: 'required' } = f.input :short_title, hint: "A short and unique handle for your conference, using only letters, numbers, underscores, and dashes. This will be used to identify your conference in URLs etc. Example: 'froscon2011'", diff --git a/spec/features/conference_spec.rb b/spec/features/conference_spec.rb index f3205e07..0dc4e228 100644 --- a/spec/features/conference_spec.rb +++ b/spec/features/conference_spec.rb @@ -2,13 +2,15 @@ require 'spec_helper' feature Conference do let!(:user) { create(:admin) } - + let!(:organization) { create(:organization) } shared_examples 'add and update conference' do scenario 'adds a new conference', feature: true, js: true do expected_count = Conference.count + 1 sign_in user visit new_admin_conference_path + + select organization.name, from: 'conference_organization_id' fill_in 'conference_title', with: 'Example Con' fill_in 'conference_short_title', with: 'ExCon' @@ -27,7 +29,7 @@ feature Conference do expect(flash) .to eq('Conference was successfully created.') expect(Conference.count).to eq(expected_count) - + expect(Conference.last.organization).to eq(organization) expect(user.has_role? :organizer, Conference.last).to eq(true) end From 0ac5d18ef27e5658aa290e1ec80f3d03fb0f90a5 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Sat, 22 Jul 2017 12:34:48 +0530 Subject: [PATCH 177/237] route to conference#show for custom domain --- app/controllers/conferences_controller.rb | 9 ++++++++- config/initializers/domain_constraint.rb | 6 ++++++ config/routes.rb | 4 ++++ ...0170721184810_add_custom_domain_to_conferences.rb | 5 +++++ db/schema.rb | 12 +++++++----- 5 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 config/initializers/domain_constraint.rb create mode 100644 db/migrate/20170721184810_add_custom_domain_to_conferences.rb diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb index 53e5bd6d..15a59a0c 100644 --- a/app/controllers/conferences_controller.rb +++ b/app/controllers/conferences_controller.rb @@ -9,10 +9,17 @@ class ConferencesController < ApplicationController @antiquated = @conferences - @current end - def show; end + def show + # have to change "localhost" to ENV['OSEM_HOSTNAME'] in production + check_custom_domain if request.host != 'localhost' + end private + def check_custom_domain + @conference = @conference.custom_domain.present? ? Conference.find_by(custom_domain: request.domain) : @conference + end + def respond_to_options respond_to do |format| format.html { head :ok } diff --git a/config/initializers/domain_constraint.rb b/config/initializers/domain_constraint.rb new file mode 100644 index 00000000..67e19a75 --- /dev/null +++ b/config/initializers/domain_constraint.rb @@ -0,0 +1,6 @@ +class DomainConstraint + def self.matches?(request) + @domains = Conference.pluck(:custom_domain).compact + @domains.include?(request.domain) + end +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 3b955953..c4a5f6ce 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,9 @@ Osem::Application.routes.draw do + constraints DomainConstraint do + get '/', to: 'conferences#show' + end + if ENV['OSEM_ICHAIN_ENABLED'] == 'true' devise_for :users, controllers: { registrations: :registrations } else diff --git a/db/migrate/20170721184810_add_custom_domain_to_conferences.rb b/db/migrate/20170721184810_add_custom_domain_to_conferences.rb new file mode 100644 index 00000000..d5aef4fd --- /dev/null +++ b/db/migrate/20170721184810_add_custom_domain_to_conferences.rb @@ -0,0 +1,5 @@ +class AddCustomDomainToConferences < ActiveRecord::Migration + def change + add_column :conferences, :custom_domain, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 83499b33..d9949b1e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,10 +11,10 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170807092805) do +ActiveRecord::Schema.define(version: 20170816203325) do create_table "ahoy_events", force: :cascade do |t| - t.integer "visit_id" + t.uuid "visit_id", limit: 16 t.integer "user_id" t.string "name" t.text "properties" @@ -127,6 +127,7 @@ ActiveRecord::Schema.define(version: 20170807092805) do t.integer "end_hour", default: 20 t.integer "organization_id" t.integer "ticket_layout", default: 0 + t.string "custom_domain" t.integer "booth_limit", default: 0 end @@ -511,10 +512,10 @@ ActiveRecord::Schema.define(version: 20170807092805) do create_table "tickets", force: :cascade do |t| t.integer "conference_id" - t.string "title", null: false + t.string "title", null: false t.text "description" - t.integer "price_cents", default: 0, null: false - t.string "price_currency", default: "USD", null: false + t.integer "price_cents", default: 0, null: false + t.string "price_currency", default: "USD", null: false t.boolean "registration_ticket", default: false end @@ -572,6 +573,7 @@ ActiveRecord::Schema.define(version: 20170807092805) do t.boolean "is_admin", default: false t.string "username" t.boolean "is_disabled", default: false + t.string "token" end add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true From f4775f8e6ab31a05d83fafdb6eba7e025c7db826 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Tue, 25 Jul 2017 07:42:50 +0530 Subject: [PATCH 178/237] fix access denied error for program in custom domains --- app/controllers/conferences_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb index 15a59a0c..6e5dd5dd 100644 --- a/app/controllers/conferences_controller.rb +++ b/app/controllers/conferences_controller.rb @@ -2,7 +2,6 @@ class ConferencesController < ApplicationController protect_from_forgery with: :null_session before_action :respond_to_options load_and_authorize_resource find_by: :short_title - load_resource :program, through: :conference, singleton: true, except: :index def index @current = Conference.where('end_date >= ?', Date.current).reorder(start_date: :asc) @@ -10,14 +9,15 @@ class ConferencesController < ApplicationController end def show - # have to change "localhost" to ENV['OSEM_HOSTNAME'] in production + # have to change "localhost" to ENV['OSEM_HOSTNAME'] in production check_custom_domain if request.host != 'localhost' + @program = @conference.program end private def check_custom_domain - @conference = @conference.custom_domain.present? ? Conference.find_by(custom_domain: request.domain) : @conference + @conference = @conference.nil? ? Conference.find_by(custom_domain: request.domain) : @conference end def respond_to_options From 66b48be968a0cb9d6519278fcba5c55117127c03 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 26 Jul 2017 09:04:07 +0530 Subject: [PATCH 179/237] controller tests for custom domain --- spec/controllers/conferences_controller_spec.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/controllers/conferences_controller_spec.rb b/spec/controllers/conferences_controller_spec.rb index 6479eb34..dffae77a 100644 --- a/spec/controllers/conferences_controller_spec.rb +++ b/spec/controllers/conferences_controller_spec.rb @@ -23,6 +23,15 @@ describe ConferencesController do get :show, id: conference.short_title expect(response).to render_template :show end + + it 'assigns correct conference from a custom domain' do + conference.update_attribute(:custom_domain, 'lvh.me') + @request.host = 'lvh.me' + + get :show + expect(response).to render_template :show + expect(assigns(:conference)).to eq conference + end end end From 835859e350ab41d4a93b077412c84cf2b0c37010 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 2 Aug 2017 20:16:50 +0530 Subject: [PATCH 180/237] refactored DomainConstraint and conference_controller_spec use params id instead of OSEM_HOSTNAME to load conference --- app/controllers/conferences_controller.rb | 14 +++++++++----- config/initializers/domain_constraint.rb | 6 +++--- spec/controllers/conferences_controller_spec.rb | 7 ++++++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb index 6e5dd5dd..f141529d 100644 --- a/app/controllers/conferences_controller.rb +++ b/app/controllers/conferences_controller.rb @@ -1,7 +1,7 @@ class ConferencesController < ApplicationController protect_from_forgery with: :null_session before_action :respond_to_options - load_and_authorize_resource find_by: :short_title + load_and_authorize_resource find_by: :short_title, except: :show def index @current = Conference.where('end_date >= ?', Date.current).reorder(start_date: :asc) @@ -9,15 +9,19 @@ class ConferencesController < ApplicationController end def show - # have to change "localhost" to ENV['OSEM_HOSTNAME'] in production - check_custom_domain if request.host != 'localhost' + @conference = if params[:id] + Conference.find_by_short_title(params[:id]) + else + load_conference_by_domain + end + authorize! :show, @conference @program = @conference.program end private - def check_custom_domain - @conference = @conference.nil? ? Conference.find_by(custom_domain: request.domain) : @conference + def load_conference_by_domain + Conference.find_by(custom_domain: request.domain) end def respond_to_options diff --git a/config/initializers/domain_constraint.rb b/config/initializers/domain_constraint.rb index 67e19a75..5b35e5c7 100644 --- a/config/initializers/domain_constraint.rb +++ b/config/initializers/domain_constraint.rb @@ -1,6 +1,6 @@ class DomainConstraint def self.matches?(request) - @domains = Conference.pluck(:custom_domain).compact - @domains.include?(request.domain) + domains = Conference.where.not(custom_domain: nil).pluck(:custom_domain) + domains.include?(request.domain) end -end \ No newline at end of file +end diff --git a/spec/controllers/conferences_controller_spec.rb b/spec/controllers/conferences_controller_spec.rb index dffae77a..cdbebf9f 100644 --- a/spec/controllers/conferences_controller_spec.rb +++ b/spec/controllers/conferences_controller_spec.rb @@ -23,12 +23,17 @@ describe ConferencesController do get :show, id: conference.short_title expect(response).to render_template :show end + end - it 'assigns correct conference from a custom domain' do + context 'accessing conference via custom domain' do + before do conference.update_attribute(:custom_domain, 'lvh.me') @request.host = 'lvh.me' + end + it 'assigns correct conference' do get :show + expect(response).to render_template :show expect(assigns(:conference)).to eq conference end From 834e9d96e4ac60a3c28455722d05ad2c6f2f6fda Mon Sep 17 00:00:00 2001 From: nasia Date: Fri, 11 Aug 2017 15:14:22 +0300 Subject: [PATCH 181/237] Add booths to admin sidebar --- app/controllers/admin/booths_controller.rb | 4 ++++ app/views/admin/booths/_change_state_dropdown.html.haml | 5 +++++ app/views/layouts/_admin_sidebar.html.haml | 6 +++++- config/routes.rb | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/controllers/admin/booths_controller.rb b/app/controllers/admin/booths_controller.rb index a200e42e..a65de090 100644 --- a/app/controllers/admin/booths_controller.rb +++ b/app/controllers/admin/booths_controller.rb @@ -90,6 +90,10 @@ module Admin update_state(:cancel, 'Booth is canceled') end + def confirm + update_state(:confirm, 'Booth successfully confirmed') + end + private def update_state(transition, notice) diff --git a/app/views/admin/booths/_change_state_dropdown.html.haml b/app/views/admin/booths/_change_state_dropdown.html.haml index 12b982df..338e43f7 100644 --- a/app/views/admin/booths/_change_state_dropdown.html.haml +++ b/app/views/admin/booths/_change_state_dropdown.html.haml @@ -42,3 +42,8 @@ %li= link_to 'Cancel booth', cancel_admin_conference_booth_path(@conference.short_title, booth), method: :patch, id: "cancel_booth_#{booth.id}" + +- if booth.transition_possible? :confirm + %li= link_to 'Confirm booth', + confirm_admin_conference_booth_path(@conference.short_title, booth), + method: :patch, id: "confirm_booth_#{booth.id}" diff --git a/app/views/layouts/_admin_sidebar.html.haml b/app/views/layouts/_admin_sidebar.html.haml index 28ef62e2..1f8bf6b5 100644 --- a/app/views/layouts/_admin_sidebar.html.haml +++ b/app/views/layouts/_admin_sidebar.html.haml @@ -116,7 +116,11 @@ - if can? :update, @conference.tickets.build %li{class: active_nav_li(admin_conference_tickets_path(@conference.short_title)) } = link_to 'Tickets', admin_conference_tickets_path(@conference.short_title) - + - if can? :manage, @conference.booths + %li + = link_to admin_conference_booths_path(@conference.short_title) do + %span.fa.fa-shopping-bag + Booths - if (can? :manage, @conference.targets.build) || (can? :manage, @conference.campaigns.build) %li %a diff --git a/config/routes.rb b/config/routes.rb index c4a5f6ce..1e26807c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -57,6 +57,7 @@ Osem::Application.routes.draw do patch :reset patch :to_reject patch :cancel + patch :confirm end end From bc45531efda66c367e88e674fae6eb4576d46e9d Mon Sep 17 00:00:00 2001 From: nasia Date: Tue, 15 Aug 2017 15:46:33 +0300 Subject: [PATCH 182/237] Add My Booth Requests to user menu --- .haml-lint_todo.yml | 1 + app/views/layouts/_admin_sidebar.html.haml | 2 +- app/views/layouts/_user_menu.html.haml | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 25ccb622..49feab3d 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -153,6 +153,7 @@ linters: - "app/views/layouts/_admin_sidebar_index.html.haml" - "app/views/layouts/_messages.html.haml" - "app/views/layouts/_navigation.html.haml" + - "app/views/layouts/_user_menu.html.haml" - "app/views/layouts/application.html.haml" - "app/views/organizations/index.html.haml" - "app/views/payments/_payment.html.haml" diff --git a/app/views/layouts/_admin_sidebar.html.haml b/app/views/layouts/_admin_sidebar.html.haml index 1f8bf6b5..e8f1ccd9 100644 --- a/app/views/layouts/_admin_sidebar.html.haml +++ b/app/views/layouts/_admin_sidebar.html.haml @@ -116,7 +116,7 @@ - if can? :update, @conference.tickets.build %li{class: active_nav_li(admin_conference_tickets_path(@conference.short_title)) } = link_to 'Tickets', admin_conference_tickets_path(@conference.short_title) - - if can? :manage, @conference.booths + - if can? :manage, @conference.booths.build %li = link_to admin_conference_booths_path(@conference.short_title) do %span.fa.fa-shopping-bag diff --git a/app/views/layouts/_user_menu.html.haml b/app/views/layouts/_user_menu.html.haml index fe1e9a35..bad4c16d 100644 --- a/app/views/layouts/_user_menu.html.haml +++ b/app/views/layouts/_user_menu.html.haml @@ -16,6 +16,11 @@ = link_to(conference_program_tracks_path(@conference.short_title)) do %span.fa.fa-road My Tracks +-if @conference && @conference.program && (@conference.program.cfps.for_booths.try(:open?) || current_user.booths.where(conference_id: @conference.id).count > 0) + %li + = link_to (conference_booths_path(@conference.short_title)) do + %span.fa.fa-shopping-bag + My Booth Requests %li - if ENV['OSEM_ICHAIN_ENABLED'] == 'true' = link_to(destroy_user_ichain_session_path, method: 'delete') do From 7af712f49211fd12b1fb55b555b16d1628429148 Mon Sep 17 00:00:00 2001 From: divyanshumehta Date: Wed, 10 May 2017 16:24:20 +0530 Subject: [PATCH 183/237] Made lodging cards of same height w.r.t. to its row. Fixes #1456. --- app/views/conferences/_lodging.html.haml | 34 +++++++++++++----------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/app/views/conferences/_lodging.html.haml b/app/views/conferences/_lodging.html.haml index e94286a4..561e2421 100644 --- a/app/views/conferences/_lodging.html.haml +++ b/app/views/conferences/_lodging.html.haml @@ -12,22 +12,26 @@ = @conference.venue.city %p.lead We recommend these affordable lodging accommodations for your visit. - - @conference.lodgings.each_slice(3) do |slice| - .row.row-centered - - slice.each do |lodging| - .col-md-4.col-sm-4.ticket.col-centered.col-top - .thumbnail - - unless lodging.picture? - %p.text-center - %i.fa.fa-home.fa-5x + + .row.row-centered{ style:"display: flex; flex-wrap: wrap" } + - @conference.lodgings.each do |lodging| + .col-md-4.col-sm-4.col-centered.col-top{ style:"display:flex;" } + .thumbnail + - if lodging.picture? + -if lodging.website_link.present? + = link_to(lodging.website_link, class: 'thumbnail') do + = image_tag lodging.picture.large.url, class: 'img-responsive img-lodging' - else + = image_tag lodging.picture.large.url, class: 'img-responsive img-lodging' + - else + %p.text-center -if lodging.website_link.present? = link_to(lodging.website_link, class: 'thumbnail') do - = image_tag lodging.picture.large.url, class: 'img-responsive img-lodging' + %i.fa.fa-home.fa-5x - else - = image_tag lodging.picture.large.url, class: 'img-responsive img-lodging' - .caption - %h3.text-center - = lodging.name - -if lodging.description.present? - = markdown(lodging.description) + %i.fa.fa-home.fa-5x + .caption + %h3.text-center + = lodging.name + -if lodging.description.present? + = markdown(lodging.description) From 68788ce9fc71ecdbebaea9351612e6a5995f5d04 Mon Sep 17 00:00:00 2001 From: Nishanth Vijayan Date: Sat, 6 Aug 2016 17:22:53 +0530 Subject: [PATCH 184/237] Show conference changelog Use load_and_authorize_resource in versions controlller Add conference specifc route to revision history page Users with role can view revision_history only for the versions they have access to Handle versions where conference_id is not set (records before papertrail was introduced) --- app/controllers/admin/versions_controller.rb | 17 ++- app/helpers/application_helper.rb | 19 --- app/helpers/versions_helper.rb | 48 +++++++- app/models/admin_ability.rb | 13 +- .../versions/_object_desc_and_link.html.haml | 114 +++++++++++------- app/views/admin/versions/index.html.haml | 10 ++ app/views/layouts/_admin_sidebar.html.haml | 7 ++ .../layouts/_admin_sidebar_index.html.haml | 2 +- app/views/layouts/_user_menu.html.haml | 2 +- config/routes.rb | 2 + lib/tasks/version.rake | 24 +++- .../admin/versions_controller_spec.rb | 9 ++ spec/features/versions_spec.rb | 114 ++++++++++-------- 13 files changed, 240 insertions(+), 141 deletions(-) diff --git a/app/controllers/admin/versions_controller.rb b/app/controllers/admin/versions_controller.rb index 07108d38..8048595f 100644 --- a/app/controllers/admin/versions_controller.rb +++ b/app/controllers/admin/versions_controller.rb @@ -1,17 +1,17 @@ module Admin class VersionsController < Admin::BaseController - skip_authorization_check + load_resource :conference, find_by: :short_title + load_and_authorize_resource class: PaperTrail::Version def index - authorize! :index, PaperTrail::Version.new(item_type: 'User') - conf_ids_for_organizer = current_user.is_admin? ? Conference.pluck(:id) : Conference.with_role(:organizer, current_user).pluck(:id) - @versions = PaperTrail::Version.where(["conference_id IN (?) OR item_type = 'User'", conf_ids_for_organizer]) + @conf_ids_with_role = current_user.is_admin? ? Conference.pluck(:short_title) : Conference.with_role([:organizer, :cfp, :info_desk], current_user).pluck(:short_title) + + return if @conference.blank? + authorize! :index, PaperTrail::Version.new(conference_id: @conference.id) + @versions = @versions.where(conference_id: @conference.id) end def revert_attribute - @version = PaperTrail::Version.find(params[:id]) - authorize! :revert_attribute, @version - if params[:attribute] && @version.changeset.reject{ |_, values| values[0].blank? && values[1].blank? }.keys.include?(params[:attribute]) if @version.item[params[:attribute]] == @version.changeset[params[:attribute]][0] flash[:error] = 'The item is already in the state that you are trying to revert it back to' @@ -33,9 +33,6 @@ module Admin end def revert_object - @version = PaperTrail::Version.find(params[:id]) - authorize! :revert_object, @version - if @version.event != 'create' if @version.reify.save flash[:notice] = 'The selected change was successfully reverted' diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 0c460f26..e55656ea 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -98,25 +98,6 @@ module ApplicationHelper .reverse.sub(',', ' dna ').reverse end - # Recieves a model_name and id - # Returns nil if model_name is invalid - # Returns object in its current state if its alive - # Otherwise Returns object state just before deletion - def current_or_last_object_state(model_name, id) - return nil unless id.present? && model_name.present? - begin - object = model_name.constantize.find_by(id: id) - rescue NameError - return nil - end - - if object.nil? - object_last_version = PaperTrail::Version.where(item_type: model_name, item_id: id).last - object = object_last_version.reify if object_last_version - end - object - end - def normalize_array_length(hashmap, length) hashmap.each do |_, value| if value.length < length diff --git a/app/helpers/versions_helper.rb b/app/helpers/versions_helper.rb index e919eb79..10ccef74 100644 --- a/app/helpers/versions_helper.rb +++ b/app/helpers/versions_helper.rb @@ -2,8 +2,52 @@ module VersionsHelper ## # Groups functions related to change description ## - def link_if_alive(version, link_text, link_url) - version.item ? link_to(link_text, link_url) : link_text + def link_if_alive(version, link_text, link_url, conference) + version.item && conference ? link_to(link_text, link_url) : "#{link_text} with ID #{version.item_id}" + end + + def link_to_conference(conference_id) + return 'deleted conference' if conference_id.nil? + + conference = Conference.find_by(id: conference_id) + if conference + link_to conference.short_title, + edit_admin_conference_path(conference.short_title) + else + short_title = current_or_last_object_state('Conference', conference_id).try(:short_title) || '' + " #{short_title} with ID #{conference_id}" + end + end + + def link_to_user(user_id) + return 'Someone (probably via the console)' unless user_id + + user = User.find_by(id: user_id) + if user + link_to user.name, admin_user_path(id: user_id) + else + name = current_or_last_object_state('User', user_id).try(:name) + "#{name ? name : 'Unknown user'} with ID #{user_id}" + end + end + + # Recieves a model_name and id + # Returns nil if model_name is invalid + # Returns object in its current state if its alive + # Otherwise Returns object state just before deletion + def current_or_last_object_state(model_name, id) + return nil unless id.present? && model_name.present? + begin + object = model_name.constantize.find_by(id: id) + rescue NameError + return nil + end + + if object.nil? + object_last_version = PaperTrail::Version.where(item_type: model_name, item_id: id).last + object = object_last_version.reify if object_last_version + end + object end def subscription_change_description(version) diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index cfe17d1d..5c08a073 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -167,9 +167,8 @@ class AdminAbility role.resource_type == 'Track' && (track_ids.include? role.resource_id) end - can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| - version.item_type == 'User' || (conf_ids.include? version.conference_id) - end + can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'User' + can [:index, :revert_object, :revert_attribute], PaperTrail::Version, conference_id: conf_ids end def signed_in_with_cfp_role(user) @@ -208,9 +207,10 @@ class AdminAbility (Conference.with_role(:cfp, user).pluck(:id).include? role.resource_id) end - can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Event', conference_id: conf_ids_for_cfp - can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Vote', conference_id: conf_ids_for_cfp - can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version| + 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 + 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) && (version.object.to_s.include?('Event') || version.object_changes.to_s.include?('Event')) end @@ -244,6 +244,7 @@ class AdminAbility role.resource_type == 'Conference' && role.name == 'info_desk' && (Conference.with_role(:info_desk, user).pluck(:id).include? role.resource_id) end + can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Registration', conference_id: conf_ids_for_info_desk end def signed_in_with_volunteers_coordinator_role(user) diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index d29e5f9b..c5b5e84e 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -1,84 +1,92 @@ +- conference = Conference.find_by(id: version.conference_id) +- conference_short_title = conference.try(:short_title) || current_or_last_object_state(version.item_type, version.item_id).try(:conference).try(:short_title) || '' + - case version.item_type - when 'UsersRole' - users_role = current_or_last_object_state(version.item_type, version.item_id) - - user = current_or_last_object_state('User', users_role.user_id) = 'role' - = link_to users_role.role.name, admin_conference_role_path(conference_id: Conference.find(version.conference_id).short_title, id: users_role.role.name) + = link_to users_role.role.name, admin_conference_role_path(conference.short_title, users_role.role.name) = version.event == 'create' ? 'to' : 'from' = 'user' - - = link_to (user.try(:name) || 'deleted user'), admin_user_path(id: users_role.user.id) + = link_to_user(users_role.user_id) - when 'Subscription', 'Registration' = 'conference' - = link_to Conference.find(version.conference_id).title, - admin_conference_registrations_path(conference_id: Conference.find(version.conference_id).short_title) + = link_to_conference(version.conference_id) - when 'Commercial' - commercial = current_or_last_object_state(version.item_type, version.item_id) - commercialable = current_or_last_object_state(commercial.commercialable_type, commercial.commercialable_id) - - commercialable_last_version = PaperTrail::Version.where(item_type: commercial.commercialable_type, item_id: commercial.commercialable_id).last - case commercial.commercialable_type - when 'Event' - commercial in - - if commercialable_last_version.item - event + = 'commercial in event' + - if commercialable && conference = link_to commercialable.title, - admin_conference_program_event_path(conference_id: Conference.find(version.conference_id).short_title, id: commercialable.id) + admin_conference_program_event_path(conference_id: conference.short_title, + id: commercialable.id) - else = commercialable.title + = "with ID #{commercialable.id}" - when 'Venue' - commercial in venue - - if commercialable_last_version.item + = 'commercial in venue' + - if commercialable && conference = link_to commercialable.name, - edit_admin_conference_venue_path(conference_id: Conference.find(version.conference_id).short_title, - id: commercialable.id, anchor: 'commercials-content') + edit_admin_conference_venue_path(conference_id: conference_short_title, + id: commercialable.id, anchor: 'commercials-content') - else = commercialable.name + = "with ID #{commercialable.id}" - when 'Conference' - = link_to 'commercial', - admin_conference_commercials_path(conference_id: Conference.find(version.conference_id).short_title) + = 'commercial in conference' + - if commercialable + = link_to commercialable.short_title, + admin_conference_commercials_path(conference_id: commercialable.short_title) + - else + = commercialable.short_title + = "with ID #{commercialable.id}" - when 'EventsRegistration', 'Comment', 'Vote', 'Event' = 'event' - object = current_or_last_object_state(version.item_type, version.item_id) - event_id = object.try(:event_id) || object.try(:commentable_id) || object.id = link_to (current_or_last_object_state('Event', event_id).try(:title) || 'deleted event'), - admin_conference_program_event_path(conference_id: Conference.find(version.conference_id).short_title, id: event_id) + admin_conference_program_event_path(conference_id: conference_short_title, id: event_id) - when 'Target' = 'target' - target = current_or_last_object_state(version.item_type, version.item_id) - = link_if_alive version, target.to_s, admin_conference_targets_path(conference_id: Conference.find(version.conference_id).short_title) + = link_if_alive version, target.to_s, admin_conference_targets_path(conference_id: conference_short_title), conference - when 'EventSchedule' - event_schedule = current_or_last_object_state(version.item_type, version.item_id) event - = link_to (current_or_last_object_state('Event', event_schedule.event_id).try(:title) || 'deleted event'), - admin_conference_program_event_path(conference_id: Conference.find(version.conference_id).short_title, id: event_schedule.event_id) + = link_to (current_or_last_object_state('Event', event_schedule.event_id).try(:title) || 'deleted'), + admin_conference_program_event_path(conference_id: conference_short_title, id: event_schedule.event_id) in = link_to "Schedule #{event_schedule.schedule_id}", - admin_conference_schedule_path(conference_id: Conference.find(version.conference_id).short_title, id: event_schedule.schedule_id) + admin_conference_schedule_path(conference_id: conference_short_title, id: event_schedule.schedule_id) - when 'Schedule' = link_if_alive version, "Schedule #{version.item_id}", - admin_conference_schedule_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) + admin_conference_schedule_path(conference_id: conference_short_title, id: version.item_id), + conference - when 'Conference' = 'conference' - = link_to Conference.find(version.conference_id).title, - edit_admin_conference_path(id: Conference.find(version.conference_id).short_title) + = link_to_conference(version.item_id) - when 'RegistrationPeriod' = link_if_alive version, 'registration period', - admin_conference_registration_period_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_registration_period_path(conference_id: conference_short_title), + conference - when 'Contact' = link_if_alive version, 'contact details', - edit_admin_conference_contact_path(conference_id: Conference.find(version.conference_id).short_title) + edit_admin_conference_contact_path(conference_id: conference_short_title), + conference - when 'Booth' = 'booth' @@ -88,94 +96,108 @@ - when 'Program' = link_if_alive version, 'program', - admin_conference_program_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_program_path(conference_id: conference_short_title), + conference - when 'Cfp' = 'cfp for' - cfp = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, cfp.cfp_type, - admin_conference_program_cfp_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) + admin_conference_program_cfp_path(conference_id: conference_short_title, id: version.item_id), + conference - when 'Track' = 'track' - track = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, track.name, - admin_conference_program_track_path(conference_id: Conference.find(version.conference_id).short_title, id: track.try(:short_name)) + admin_conference_program_track_path(conference_id: conference_short_title, id: track.try(:short_name)), + conference - when 'EventType' = 'event type' - event_type = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, event_type.title, - admin_conference_program_event_types_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_program_event_types_path(conference_id: conference_short_title), + conference - when 'Role' = 'role' - role = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, role.name, - admin_conference_role_path(conference_id: Conference.find(version.conference_id).short_title, id: role.name) + admin_conference_role_path(conference_id: conference_short_title, id: role.name), + conference - when 'Venue' = 'venue' - venue = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, venue.name, - admin_conference_venue_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_venue_path(conference_id: conference_short_title), + conference - when 'Lodging' = 'lodging' - lodging = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, lodging.name, - admin_conference_lodgings_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_lodgings_path(conference_id: conference_short_title), + conference - when 'Room' = 'room' - room = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, room.name, - admin_conference_venue_rooms_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_venue_rooms_path(conference_id: conference_short_title), + conference - when 'Sponsor' = 'sponsor' - sponsor = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, sponsor.name, - admin_conference_sponsors_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_sponsors_path(conference_id: conference_short_title), + conference - when 'SponsorshipLevel' = 'sponsorship level' - sponsorship_level = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, sponsorship_level.title, - admin_conference_sponsorship_levels_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_sponsorship_levels_path(conference_id: conference_short_title), + conference - when 'Ticket' = 'ticket' - ticket = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, ticket.title, - admin_conference_ticket_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) + admin_conference_ticket_path(conference_id: conference_short_title, id: version.item_id), + conference - when 'Campaign' = 'campaign' - campaign = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, campaign.name, - admin_conference_campaigns_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_campaigns_path(conference_id: conference_short_title), + conference - when 'DifficultyLevel' = 'difficulty level' - difficulty_level = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, difficulty_level.title, - admin_conference_program_difficulty_level_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id) + admin_conference_program_difficulty_level_path(conference_id: conference_short_title, id: version.item_id), + conference - when 'Splashpage' = link_if_alive version, 'splashpage', - admin_conference_splashpage_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_splashpage_path(conference_id: conference_short_title), + conference - when 'EmailSettings' = link_if_alive version, 'email settings', - admin_conference_emails_path(conference_id: Conference.find(version.conference_id).short_title) + admin_conference_emails_path(conference_id: conference_short_title), + conference - when 'User' - if version.event == 'update' = 'user' - = link_to (current_or_last_object_state('User', version.item_id).try(:name) || 'deleted user'), admin_user_path(id: version.item_id) + = link_to_user(version.item_id) - unless %w(Conference Subscription Registration User).include?(version.item_type) - = "in conference" - = link_to Conference.find(version.conference_id).short_title, - edit_admin_conference_path(id: Conference.find(version.conference_id).short_title) + = 'in conference' + = link_to_conference(version.conference_id) diff --git a/app/views/admin/versions/index.html.haml b/app/views/admin/versions/index.html.haml index 69af134b..3a5113b1 100644 --- a/app/views/admin/versions/index.html.haml +++ b/app/views/admin/versions/index.html.haml @@ -1,6 +1,16 @@ .row .col-md-12 .page-header + + .dropdown.pull-right + %button.btn.btn-success.dropdown-toggle{ 'data-toggle' => 'dropdown', type: 'button' } + = @conference.nil? ? 'All Conferences' : @conference.short_title + %span.caret + %ul.dropdown-menu + %li= link_to 'All Conferences & Users', admin_revision_history_path + - @conf_ids_with_role.each do |conference_short_title| + %li= link_to conference_short_title, admin_conference_revision_history_path(conference_id: conference_short_title) + %h1 Revision History %p.text-muted Log of changes made to conferences and associated resources diff --git a/app/views/layouts/_admin_sidebar.html.haml b/app/views/layouts/_admin_sidebar.html.haml index e8f1ccd9..4385d307 100644 --- a/app/views/layouts/_admin_sidebar.html.haml +++ b/app/views/layouts/_admin_sidebar.html.haml @@ -143,8 +143,15 @@ = link_to(admin_conference_roles_path(@conference.short_title)) do %span.fa.fa-group Roles + - if can? :index, @conference.resources.new %li = link_to admin_conference_resources_path(@conference.short_title) do %span.fa.fa-pencil-square Resources + + - if can?(:index, PaperTrail::Version.new(conference_id: @conference.id, item_type: 'Event')) || can?(:index, PaperTrail::Version.new(conference_id: @conference.id, item_type: 'Registration')) + %li{:class=> active_nav_li(admin_conference_revision_history_path(@conference.short_title))} + = link_to(admin_conference_revision_history_path(@conference.short_title)) do + %span.fa.fa-history + Revision History diff --git a/app/views/layouts/_admin_sidebar_index.html.haml b/app/views/layouts/_admin_sidebar_index.html.haml index 01356f42..9a3d19f3 100644 --- a/app/views/layouts/_admin_sidebar_index.html.haml +++ b/app/views/layouts/_admin_sidebar_index.html.haml @@ -27,7 +27,7 @@ = link_to(admin_users_path) do %span.fa.fa-user Users - - if can? :index, PaperTrail::Version.new(item_type: 'User') + - if can? :index, PaperTrail::Version %li = link_to(admin_revision_history_path) do %span.fa.fa-history diff --git a/app/views/layouts/_user_menu.html.haml b/app/views/layouts/_user_menu.html.haml index bad4c16d..10d4c386 100644 --- a/app/views/layouts/_user_menu.html.haml +++ b/app/views/layouts/_user_menu.html.haml @@ -53,7 +53,7 @@ = link_to(admin_users_path) do %span.fa.fa-user Users -- if can? :index, PaperTrail::Version.new(item_type: 'User') +- if can? :index, PaperTrail::Version %li = link_to(admin_revision_history_path) do %span.fa.fa-history diff --git a/config/routes.rb b/config/routes.rb index 1e26807c..ec55b8a3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -141,6 +141,8 @@ Osem::Application.routes.draw do patch :update_conference end end + + get '/revision_history' => 'versions#index' end get '/revision_history' => 'versions#index' diff --git a/lib/tasks/version.rake b/lib/tasks/version.rake index e4005c15..a25653c6 100644 --- a/lib/tasks/version.rake +++ b/lib/tasks/version.rake @@ -1,7 +1,7 @@ namespace :data do desc 'Sets conference_id in all pre-existing PaperTrail::Version objects' task set_conference_in_versions: :environment do - + ids_with_failure = [] PaperTrail::Version.where(conference_id: nil, item_type: %w[Conference Event]).each do |version| # All pre-existing versions are either of Conference or Event if version.item_type == 'Conference' @@ -9,13 +9,25 @@ namespace :data do elsif version.item_type == 'Event' event = (version.item || version.reify || version.next.reify) - if event.try(:program) - version.update_attributes(conference_id: event.program.conference_id) - else - puts "Setting conference_id value failed for PaperTrail::Version object with ID=#{version.id}" - end + + conference_id = if event.try(:program) + event.program.conference_id + # Event had attribute conference_id before it was replaced with program_id + elsif version.changeset[:conference_id] + version.changeset[:conference_id].second + elsif version.changeset[:program_id] + version.changeset[:program_id].second + elsif version.object && (object = YAML.safe_load(version.object)) + object['conference_id'] + else + ids_with_failure << version.id + puts "Setting conference_id value failed for PaperTrail::Version object with ID=#{version.id}" + nil + end + version.update_attributes(conference_id: conference_id) end end puts 'All done!' + puts "IDs with failures: #{ids_with_failure}" if ids_with_failure.any? end end diff --git a/spec/controllers/admin/versions_controller_spec.rb b/spec/controllers/admin/versions_controller_spec.rb index 4694837d..f1400e3b 100644 --- a/spec/controllers/admin/versions_controller_spec.rb +++ b/spec/controllers/admin/versions_controller_spec.rb @@ -97,5 +97,14 @@ describe Admin::VersionsController do expect(flash[:error]).to match('Revert failed. Attribute missing or invalid') end end + + describe 'GET #index' do + it 'raises error if user is not an organizer of specified conference' do + user = create(:user) + sign_in user + get :index, conference_id: conference.short_title + expect(flash[:alert]).to match('You are not authorized to access this area.') + end + end end end diff --git a/spec/features/versions_spec.rb b/spec/features/versions_spec.rb index 11afa1d2..2f1f7f8e 100644 --- a/spec/features/versions_spec.rb +++ b/spec/features/versions_spec.rb @@ -35,23 +35,25 @@ feature 'Version' do scenario 'display changes in cfp', feature: true, versioning: true, js: true do cfp = create(:cfp, program: conference.program) cfp.update_attributes(start_date: (Date.today + 1).strftime('%d/%m/%Y'), end_date: (Date.today + 3).strftime('%d/%m/%Y')) + cfp_id = cfp.id cfp.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new cfp for events in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated start date and end date of cfp for events in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted cfp for events in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new cfp for events with ID #{cfp_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated start date and end date of cfp for events with ID #{cfp_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted cfp for events with ID #{cfp_id} in conference #{conference.short_title}") end scenario 'display changes in registration_period', feature: true, versioning: true, js: true do registration_period = create(:registration_period, conference: conference) registration_period.update_attributes(start_date: (Date.today + 1).strftime('%d/%m/%Y'), end_date: (Date.today + 3).strftime('%d/%m/%Y')) + registration_period_id = registration_period.id registration_period.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new registration period in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated start date and end date of registration period in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted registration period in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new registration period with ID #{registration_period_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated start date and end date of registration period with ID #{registration_period_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted registration period with ID #{registration_period_id} in conference #{conference.short_title}") end scenario 'display changes in conference', feature: true, versioning: true, js: true do @@ -61,32 +63,34 @@ feature 'Version' do visit admin_revision_history_path select '100', from: 'versionstable_length' - expect(page).to have_text('Someone (probably via the console) created new conference New Con') + expect(page).to have_text('Someone (probably via the console) created new conference NewCon') expect(page).to have_text('Someone (probably via the console) created new event type Talk in conference NewCon') expect(page).to have_text('Someone (probably via the console) created new event type Workshop in conference NewCon') - expect(page).to have_text('Someone (probably via the console) updated title and short title of conference New Con') + expect(page).to have_text('Someone (probably via the console) updated title and short title of conference NewCon') end scenario 'display changes in event_type', feature: true, versioning: true, js: true do event_type = create(:event_type, program: conference.program, name: 'Discussion') event_type.update_attributes(length: 90, maximum_abstract_length: 10000) + event_type_id = event_type.id event_type.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new event type Discussion in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated length and maximum abstract length of event type Discussion in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted event type Discussion in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new event type Discussion with ID #{event_type_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated length and maximum abstract length of event type Discussion with ID #{event_type_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted event type Discussion with ID #{event_type_id} in conference #{conference.short_title}") end scenario 'display changes in lodging', feature: true, versioning: true, js: true do lodging = create(:lodging, conference: conference, name: 'Hotel XYZ') lodging.update_attributes(description: 'Nice view,close to venue', website_link: 'http://www.example.com') + lodging_id = lodging.id lodging.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new lodging Hotel XYZ in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated description and website link of lodging Hotel XYZ in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted lodging Hotel XYZ in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new lodging Hotel XYZ with ID #{lodging_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated description and website link of lodging Hotel XYZ with ID #{lodging_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted lodging Hotel XYZ with ID #{lodging_id} in conference #{conference.short_title}") end scenario 'display changes in role', feature: true, versioning: true, js: true do @@ -102,12 +106,13 @@ feature 'Version' do venue = create(:venue, conference: conference) room = create(:room, venue: venue, name: 'Auditorium') room.update_attributes(size: 120) + room_id = room.id room.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new room Auditorium in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated size of room Auditorium in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted room Auditorium in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new room Auditorium with ID #{room_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated size of room Auditorium with ID #{room_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted room Auditorium with ID #{room_id} in conference #{conference.short_title}") end scenario 'display changes in sponsor', feature: true, versioning: true, js: true do @@ -115,55 +120,60 @@ feature 'Version' do sponsor = create(:sponsor, conference: conference, name: 'SUSE', sponsorship_level: conference.sponsorship_levels.first) sponsor.update_attributes(website_url: 'https://www.suse.com/company/history', sponsorship_level: conference.sponsorship_levels.second) sponsor.destroy + sponsor_id = sponsor.id visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new sponsor SUSE in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated website url and sponsorship level of sponsor SUSE in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted sponsor SUSE in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new sponsor SUSE with ID #{sponsor_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated website url and sponsorship level of sponsor SUSE with ID #{sponsor_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted sponsor SUSE with ID #{sponsor_id} in conference #{conference.short_title}") end scenario 'display changes in sponsorship_level', feature: true, versioning: true, js: true do sponsorship_level = create(:sponsorship_level, conference: conference) sponsorship_level.update_attributes(title: 'Gold') + sponsorship_level_id = sponsorship_level.id sponsorship_level.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new sponsorship level Gold in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated title of sponsorship level Gold in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted sponsorship level Gold in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new sponsorship level Gold with ID #{sponsorship_level_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated title of sponsorship level Gold with ID #{sponsorship_level_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted sponsorship level Gold with ID #{sponsorship_level_id} in conference #{conference.short_title}") end scenario 'display changes in ticket', feature: true, versioning: true, js: true do ticket = create(:ticket, conference: conference, title: 'Gold') ticket.update_attributes(price: 50, description: 'Premium Ticket') + ticket_id = ticket.id ticket.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new ticket Gold in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated price cents and description of ticket Gold in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted ticket Gold in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new ticket Gold with ID #{ticket_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated price cents and description of ticket Gold with ID #{ticket_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted ticket Gold with ID #{ticket_id} in conference #{conference.short_title}") end scenario 'display changes in track', feature: true, versioning: true, js: true do track = create(:track, program: conference.program, name: 'Distribution') track.update_attributes(description: 'Events about Linux distributions') + track_id = track.id track.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new track Distribution in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated description of track Distribution in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted track Distribution in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new track Distribution with ID #{track_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated description of track Distribution with ID #{track_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted track Distribution with ID #{track_id} in conference #{conference.short_title}") end scenario 'display changes in venue', feature: true, versioning: true, js: true do venue = create(:venue, conference: conference, name: 'Example University') venue.update_attributes(website: 'www.example.com new', description: 'Just another beautiful venue') + venue_id = venue.id venue.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new venue Example University in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated website and description of venue Example University in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted venue Example University in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new venue Example University with ID #{venue_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated website and description of venue Example University with ID #{venue_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted venue Example University with ID #{venue_id} in conference #{conference.short_title}") end scenario 'display changes in event', feature: true, versioning: true, js: true do @@ -209,12 +219,13 @@ feature 'Version' do scenario 'display changes in difficulty levels', feature: true, versioning: true, js: true do difficulty_level = create(:difficulty_level, program: conference.program, title: 'Expert') difficulty_level.update_attributes(description: 'Only for Experts') + difficulty_level_id = difficulty_level.id difficulty_level.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new difficulty level Expert in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated description of difficulty level Expert in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted difficulty level Expert in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new difficulty level Expert with ID #{difficulty_level_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated description of difficulty level Expert with ID #{difficulty_level_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted difficulty level Expert with ID #{difficulty_level_id} in conference #{conference.short_title}") end scenario 'display changes in splashpages', feature: true, versioning: true, js: true do @@ -232,13 +243,14 @@ feature 'Version' do uncheck('Display social media') check('Make splash page public?') click_button 'Save Splashpage' + splashpage_id = conference.splashpage.id click_link 'Delete' visit admin_revision_history_path - expect(page).to have_text("#{organizer.name} created new splashpage in conference #{conference.short_title}") + expect(page).to have_text("#{organizer.name} created new splashpage with ID #{splashpage_id} in conference #{conference.short_title}") expect(page).to have_text("#{organizer.name} updated public, include program, include cfp, include venue, include tickets, include lodgings, - include sponsors and include social media of splashpage in conference #{conference.short_title}") - expect(page).to have_text("#{organizer.name} deleted splashpage in conference #{conference.short_title}") + include sponsors and include social media of splashpage with ID #{splashpage_id} in conference #{conference.short_title}") + expect(page).to have_text("#{organizer.name} deleted splashpage with ID #{splashpage_id} in conference #{conference.short_title}") end scenario 'displays users subscribe/unsubscribe to conferences', feature: true, versioning: true, js: true do @@ -249,10 +261,10 @@ feature 'Version' do PaperTrail::Version.last.item.destroy! visit admin_revision_history_path - expect(page).to have_text("#{organizer.name} subscribed to conference #{conference.title}") - expect(page).to have_text("#{organizer.name} unsubscribed from conference #{conference.title}") - expect(page).to have_text("Someone (probably via the console) subscribed #{organizer.name} to conference #{conference.title}") - expect(page).to have_text("Someone (probably via the console) unsubscribed #{organizer.name} from conference #{conference.title}") + expect(page).to have_text("#{organizer.name} subscribed to conference #{conference.short_title}") + expect(page).to have_text("#{organizer.name} unsubscribed from conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) subscribed #{organizer.name} to conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) unsubscribed #{organizer.name} from conference #{conference.short_title}") end scenario 'display changes in conference commercials', feature: true, versioning: true, js: true do @@ -312,8 +324,8 @@ feature 'Version' do Registration.last.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) registered #{organizer.name} to conference #{conference.title}") - expect(page).to have_text("Someone (probably via the console) unregistered #{organizer.name} from conference #{conference.title}") + expect(page).to have_text("Someone (probably via the console) registered #{organizer.name} to conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) unregistered #{organizer.name} from conference #{conference.short_title}") end scenario 'display changes in event registration', feature: true, versioning: true, js: true do @@ -335,12 +347,13 @@ feature 'Version' do scenario 'display changes in target', feature: true, versioning: true, js: true do target = create(:target, conference: conference) target.update_attributes(due_date: Date.today, target_count: 1000) + target_id = target.id target.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new target 1000 Submissions by #{Date.today} in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated due date and target count of target 1000 Submissions by #{Date.today} in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted target 1000 Submissions by #{Date.today} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new target 1000 Submissions by #{Date.today} with ID #{target_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated due date and target count of target 1000 Submissions by #{Date.today} with ID #{target_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted target 1000 Submissions by #{Date.today} with ID #{target_id} in conference #{conference.short_title}") end scenario 'display changes in comment', feature: true, versioning: true, js: true do @@ -376,12 +389,13 @@ feature 'Version' do scenario 'display changes in campaign', feature: true, versioning: true, js: true do campaign = create(:campaign, conference: conference, name: 'Test Campaign', utm_campaign: 'campaign') campaign.update_attributes(utm_source: 'source', utm_medium: 'medium', utm_term: 'term', utm_content: 'content') + campaign_id = campaign.id campaign.destroy visit admin_revision_history_path - expect(page).to have_text("Someone (probably via the console) created new campaign Test Campaign in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) updated utm source, utm medium, utm term and utm content of campaign Test Campaign in conference #{conference.short_title}") - expect(page).to have_text("Someone (probably via the console) deleted campaign Test Campaign in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) created new campaign Test Campaign with ID #{campaign_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) updated utm source, utm medium, utm term and utm content of campaign Test Campaign with ID #{campaign_id} in conference #{conference.short_title}") + expect(page).to have_text("Someone (probably via the console) deleted campaign Test Campaign with ID #{campaign_id} in conference #{conference.short_title}") end scenario 'display password reset requests', feature: true, versioning: true, js: true do From 16f294f3e83af0b7a6cdda65c816ed2a14836a45 Mon Sep 17 00:00:00 2001 From: shlok007 Date: Wed, 23 Aug 2017 19:53:35 +0530 Subject: [PATCH 185/237] minor inprovements and included organizations in changelog --- app/controllers/admin/versions_controller.rb | 12 +- app/helpers/paths_helper.rb | 8 - app/helpers/versions_helper.rb | 31 ++-- app/models/admin_ability.rb | 2 +- app/models/conference.rb | 4 + app/models/organization.rb | 2 + .../versions/_object_desc_and_link.html.haml | 140 +++++++++++------- app/views/admin/versions/index.html.haml | 2 +- .../admin/versions_controller_spec.rb | 50 ++++++- spec/features/cfp_ability_spec.rb | 2 +- spec/features/info_desk_ability_spec.rb | 2 +- spec/features/versions_spec.rb | 34 ++++- 12 files changed, 199 insertions(+), 90 deletions(-) diff --git a/app/controllers/admin/versions_controller.rb b/app/controllers/admin/versions_controller.rb index 8048595f..5056f3ff 100644 --- a/app/controllers/admin/versions_controller.rb +++ b/app/controllers/admin/versions_controller.rb @@ -1,14 +1,18 @@ module Admin class VersionsController < Admin::BaseController - load_resource :conference, find_by: :short_title + load_resource :conference, find_by: :short_title, only: :index load_and_authorize_resource class: PaperTrail::Version def index - @conf_ids_with_role = current_user.is_admin? ? Conference.pluck(:short_title) : Conference.with_role([:organizer, :cfp, :info_desk], current_user).pluck(:short_title) + @conferences_with_role = current_user.is_admin? ? Conference.pluck(:short_title) : Conference.with_role([:organizer, :cfp, :info_desk], current_user).pluck(:short_title) + + if current_user.has_role? :organization_admin, :any + @conferences_with_role = Organization.with_role('organization_admin', current_user).map { |org| org.conferences.pluck :short_title }.flatten + end + @conferences_with_role.uniq! return if @conference.blank? - authorize! :index, PaperTrail::Version.new(conference_id: @conference.id) - @versions = @versions.where(conference_id: @conference.id) + @versions = PaperTrail::Version.where(conference_id: @conference.id).accessible_by(current_ability) end def revert_attribute diff --git a/app/helpers/paths_helper.rb b/app/helpers/paths_helper.rb index 97de8bca..df01ab2f 100644 --- a/app/helpers/paths_helper.rb +++ b/app/helpers/paths_helper.rb @@ -2,14 +2,6 @@ module PathsHelper ## # Includes functions related to links or redirects ## - def link_to_user(user_id) - user = User.find_by(id: user_id) - if user - link_to user.name, admin_user_path(id: user_id) - else - 'Someone (probably via the console)' - end - end def active_nav_li(link) if current_page?(link) diff --git a/app/helpers/versions_helper.rb b/app/helpers/versions_helper.rb index 10ccef74..5788fe9d 100644 --- a/app/helpers/versions_helper.rb +++ b/app/helpers/versions_helper.rb @@ -6,6 +6,14 @@ module VersionsHelper version.item && conference ? link_to(link_text, link_url) : "#{link_text} with ID #{version.item_id}" end + def link_to_organization(organization_id) + return 'deleted organization' unless organization_id + + org = Organization.find_by(id: organization_id) + return current_or_last_object_state('Organization', organization_id).try(:name) unless org + org.name.to_s + end + def link_to_conference(conference_id) return 'deleted conference' if conference_id.nil? @@ -26,12 +34,12 @@ module VersionsHelper if user link_to user.name, admin_user_path(id: user_id) else - name = current_or_last_object_state('User', user_id).try(:name) + name = current_or_last_object_state('User', user_id).try(:name) || PaperTrail::Version.where(item_type: 'User', item_id: user_id).last.changeset['name'].second if PaperTrail::Version.where(item_type: 'User', item_id: user_id).any? "#{name ? name : 'Unknown user'} with ID #{user_id}" end end - # Recieves a model_name and id + # Receives a model_name and id # Returns nil if model_name is invalid # Returns object in its current state if its alive # Otherwise Returns object state just before deletion @@ -51,30 +59,31 @@ module VersionsHelper end def subscription_change_description(version) - user = current_or_last_object_state(version.item_type, version.item_id).user - user_name = user.name unless user.id.to_s == version.whodunnit + user_id = current_or_last_object_state(version.item_type, version.item_id).user_id + user_name = User.find_by(id: user_id).try(:name) || current_or_last_object_state('User', user_id).try(:name) || PaperTrail::Version.where(item_type: 'User', item_id: user_id).last.changeset[:name].second unless user_id.to_s == version.whodunnit version.event == 'create' ? "subscribed #{user_name} to" : "unsubscribed #{user_name} from" end def registration_change_description(version) if version.item_type == 'Registration' - user = current_or_last_object_state(version.item_type, version.item_id).user + user_id = current_or_last_object_state(version.item_type, version.item_id).user_id elsif version.item_type == 'EventsRegistration' registration_id = current_or_last_object_state(version.item_type, version.item_id).registration_id - user = current_or_last_object_state('Registration', registration_id).user + user_id = current_or_last_object_state('Registration', registration_id).user_id end + user_name = User.find_by(id: user_id).try(:name) || current_or_last_object_state('User', user_id).try(:name) || PaperTrail::Version.where(item_type: 'User', item_id: user_id).last.changeset[:name].second - if user.id.to_s == version.whodunnit + if user_id.to_s == version.whodunnit case version.event when 'create' then 'registered to' when 'update' then "updated #{updated_attributes(version)} of the registration for" - when 'destroy' then 'unregistered from' + when 'destroy' then 'unregistered from' end else case version.event - when 'create' then "registered #{user.name} to" - when 'update' then "updated #{updated_attributes(version)} of #{user.name}'s registration for" - when 'destroy' then "unregistered #{user.name} from" + when 'create' then "registered #{user_name} to" + when 'update' then "updated #{updated_attributes(version)} of #{user_name}'s registration for" + when 'destroy' then "unregistered #{user_name} from" end end end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 5c08a073..7fd805d1 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -208,7 +208,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 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 919bf7e5..034e755b 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -760,6 +760,10 @@ class Conference < ActiveRecord::Base self end + def to_param + short_title + end + private # Returns a different html colour for every i and consecutive colors are diff --git a/app/models/organization.rb b/app/models/organization.rb index de3d4f94..0354df5b 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -1,6 +1,8 @@ class Organization < ActiveRecord::Base resourcify :roles, dependent: :delete_all + has_paper_trail + has_many :conferences, dependent: :destroy after_create :create_roles diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index c5b5e84e..12f9dbbc 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -1,17 +1,32 @@ -- conference = Conference.find_by(id: version.conference_id) -- conference_short_title = conference.try(:short_title) || current_or_last_object_state(version.item_type, version.item_id).try(:conference).try(:short_title) || '' +- unless version.item_type == 'Role' || version.item_type == 'UsersRole' + - conference = Conference.find_by(id: version.conference_id) + - conference_short_title = conference.try(:short_title) || current_or_last_object_state('Conference', version.conference_id).try(:short_title) || ' ' - case version.item_type +- when 'Organization' + organization + = link_to_organization(version.item_id) + - when 'UsersRole' - users_role = current_or_last_object_state(version.item_type, version.item_id) - = 'role' - = link_to users_role.role.name, admin_conference_role_path(conference.short_title, users_role.role.name) + - role = Role.find_by(id: users_role.role_id) if users_role + role + - if role.name == 'organization_admin' + -# organization_admin belongs to organization and not conferences + - organization = Organization.find(version.conference_id) + = link_if_alive version, role.name, + admins_admin_organization_path(organization), organization + - else + - conference = Conference.find_by(id: version.conference_id) + - conference_short_title = conference.try(:short_title) || current_or_last_object_state('Conference', version.conference_id).try(:short_title) || ' ' + = link_if_alive version, role.try(:name), admin_conference_role_path(role.try(:name) || ' ', conference_short_title), conference + = version.event == 'create' ? 'to' : 'from' - = 'user' + user = link_to_user(users_role.user_id) - when 'Subscription', 'Registration' - = 'conference' + conference = link_to_conference(version.conference_id) - when 'Commercial' @@ -20,72 +35,71 @@ - case commercial.commercialable_type - when 'Event' - = 'commercial in event' + commercial in event - if commercialable && conference = link_to commercialable.title, - admin_conference_program_event_path(conference_id: conference.short_title, - id: commercialable.id) + admin_conference_program_event_path(conference, commercialable.id) - else = commercialable.title = "with ID #{commercialable.id}" - when 'Venue' - = 'commercial in venue' + commercial in venue - if commercialable && conference = link_to commercialable.name, - edit_admin_conference_venue_path(conference_id: conference_short_title, - id: commercialable.id, anchor: 'commercials-content') + edit_admin_conference_venue_path(conference_short_title, + commercialable.id, anchor: 'commercials-content') - else = commercialable.name = "with ID #{commercialable.id}" - when 'Conference' - = 'commercial in conference' + commercial in conference - if commercialable = link_to commercialable.short_title, - admin_conference_commercials_path(conference_id: commercialable.short_title) + admin_conference_commercials_path(commercialable.short_title) - else = commercialable.short_title = "with ID #{commercialable.id}" - when 'EventsRegistration', 'Comment', 'Vote', 'Event' - = 'event' + event - object = current_or_last_object_state(version.item_type, version.item_id) - event_id = object.try(:event_id) || object.try(:commentable_id) || object.id = link_to (current_or_last_object_state('Event', event_id).try(:title) || 'deleted event'), - admin_conference_program_event_path(conference_id: conference_short_title, id: event_id) + admin_conference_program_event_path(conference_short_title, event_id) - when 'Target' - = 'target' + target - target = current_or_last_object_state(version.item_type, version.item_id) - = link_if_alive version, target.to_s, admin_conference_targets_path(conference_id: conference_short_title), conference + = link_if_alive version, target.to_s, admin_conference_targets_path(conference_short_title), conference - when 'EventSchedule' - event_schedule = current_or_last_object_state(version.item_type, version.item_id) event = link_to (current_or_last_object_state('Event', event_schedule.event_id).try(:title) || 'deleted'), - admin_conference_program_event_path(conference_id: conference_short_title, id: event_schedule.event_id) + admin_conference_program_event_path(conference_short_title, event_schedule.event_id) in = link_to "Schedule #{event_schedule.schedule_id}", - admin_conference_schedule_path(conference_id: conference_short_title, id: event_schedule.schedule_id) + admin_conference_schedule_path(conference_short_title, event_schedule.schedule_id) - when 'Schedule' = link_if_alive version, "Schedule #{version.item_id}", - admin_conference_schedule_path(conference_id: conference_short_title, id: version.item_id), + admin_conference_schedule_path(conference_short_title, version.item_id), conference - when 'Conference' - = 'conference' + conference = link_to_conference(version.item_id) - when 'RegistrationPeriod' = link_if_alive version, 'registration period', - admin_conference_registration_period_path(conference_id: conference_short_title), + admin_conference_registration_period_path(conference_short_title), conference - when 'Contact' = link_if_alive version, 'contact details', - edit_admin_conference_contact_path(conference_id: conference_short_title), + edit_admin_conference_contact_path(conference_short_title), conference - when 'Booth' @@ -96,108 +110,120 @@ - when 'Program' = link_if_alive version, 'program', - admin_conference_program_path(conference_id: conference_short_title), + admin_conference_program_path(conference_short_title), conference - when 'Cfp' - = 'cfp for' + cfp for - cfp = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, cfp.cfp_type, - admin_conference_program_cfp_path(conference_id: conference_short_title, id: version.item_id), + admin_conference_program_cfp_path(conference_short_title, version.item_id), conference - when 'Track' - = 'track' + track - track = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, track.name, - admin_conference_program_track_path(conference_id: conference_short_title, id: track.try(:short_name)), + admin_conference_program_track_path(conference_short_title, track.try(:short_name)), conference - when 'EventType' - = 'event type' + event type - event_type = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, event_type.title, - admin_conference_program_event_types_path(conference_id: conference_short_title), + admin_conference_program_event_types_path(conference_short_title), conference - when 'Role' - = 'role' + role - role = current_or_last_object_state(version.item_type, version.item_id) - = link_if_alive version, role.name, - admin_conference_role_path(conference_id: conference_short_title, id: role.name), - conference + - role_name = role.try(:name) || PaperTrail::Version.where(item_type: 'Role', item_id: version.item_id).last.changeset[:name].second + - if role_name == 'organization_admin' + -# organization_admin belongs to organization and not conferences + - organization = Organization.find(version.conference_id) + = link_if_alive version, role_name, + admins_admin_organization_path(organization), organization + - else + - conference = Conference.find_by(id: version.conference_id) + - conference_short_title = conference.try(:short_title) || current_or_last_object_state('Conference', version.conference_id).try(:short_title) || ' ' + = link_if_alive version, role_name, + admin_conference_role_path(conference_short_title, role_name), conference - when 'Venue' - = 'venue' + venue - venue = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, venue.name, - admin_conference_venue_path(conference_id: conference_short_title), + admin_conference_venue_path(conference_short_title), conference - when 'Lodging' - = 'lodging' + lodging - lodging = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, lodging.name, - admin_conference_lodgings_path(conference_id: conference_short_title), + admin_conference_lodgings_path(conference_short_title), conference - when 'Room' - = 'room' + room - room = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, room.name, - admin_conference_venue_rooms_path(conference_id: conference_short_title), + admin_conference_venue_rooms_path(conference_short_title), conference - when 'Sponsor' - = 'sponsor' + sponsor - sponsor = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, sponsor.name, - admin_conference_sponsors_path(conference_id: conference_short_title), + admin_conference_sponsors_path(conference_short_title), conference - when 'SponsorshipLevel' - = 'sponsorship level' + sponsorship level - sponsorship_level = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, sponsorship_level.title, - admin_conference_sponsorship_levels_path(conference_id: conference_short_title), + admin_conference_sponsorship_levels_path(conference_short_title), conference - when 'Ticket' - = 'ticket' + ticket - ticket = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, ticket.title, - admin_conference_ticket_path(conference_id: conference_short_title, id: version.item_id), + admin_conference_ticket_path(conference_short_title, version.item_id), conference - when 'Campaign' - = 'campaign' + campaign - campaign = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, campaign.name, - admin_conference_campaigns_path(conference_id: conference_short_title), + admin_conference_campaigns_path(conference_short_title), conference - when 'DifficultyLevel' - = 'difficulty level' + difficulty level - difficulty_level = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, difficulty_level.title, - admin_conference_program_difficulty_level_path(conference_id: conference_short_title, id: version.item_id), + admin_conference_program_difficulty_level_path(conference_short_title, version.item_id), conference - when 'Splashpage' = link_if_alive version, 'splashpage', - admin_conference_splashpage_path(conference_id: conference_short_title), + admin_conference_splashpage_path(conference_short_title), conference - when 'EmailSettings' = link_if_alive version, 'email settings', - admin_conference_emails_path(conference_id: conference_short_title), + admin_conference_emails_path(conference_short_title), conference - when 'User' - if version.event == 'update' - = 'user' + user = link_to_user(version.item_id) -- unless %w(Conference Subscription Registration User).include?(version.item_type) - = 'in conference' - = link_to_conference(version.conference_id) +- unless %w(Conference Subscription Registration User Organization).include?(version.item_type) + - if (version.item_type == 'Role' && role_name == 'organization_admin') || (version.item_type == 'UsersRole' && role.name == 'organization_admin') + in organization + = link_to_organization(version.conference_id) + - else + in conference + = link_to_conference(version.conference_id) diff --git a/app/views/admin/versions/index.html.haml b/app/views/admin/versions/index.html.haml index 3a5113b1..963e0a57 100644 --- a/app/views/admin/versions/index.html.haml +++ b/app/views/admin/versions/index.html.haml @@ -8,7 +8,7 @@ %span.caret %ul.dropdown-menu %li= link_to 'All Conferences & Users', admin_revision_history_path - - @conf_ids_with_role.each do |conference_short_title| + - @conferences_with_role.each do |conference_short_title| %li= link_to conference_short_title, admin_conference_revision_history_path(conference_id: conference_short_title) %h1 Revision History diff --git a/spec/controllers/admin/versions_controller_spec.rb b/spec/controllers/admin/versions_controller_spec.rb index f1400e3b..f04bc33d 100644 --- a/spec/controllers/admin/versions_controller_spec.rb +++ b/spec/controllers/admin/versions_controller_spec.rb @@ -4,6 +4,9 @@ describe Admin::VersionsController do let!(:conference) { create(:conference, short_title: 'exampletitle', description: 'Example Description') } let(:admin) { create(:admin) } + let(:role_organizer) { conference.roles.find_by(name: 'organizer') } + let(:role_cfp) { conference.roles.find_by(name: 'cfp') } + let(:role_info_desk) { conference.roles.find_by(name: 'info_desk') } with_versioning do describe 'GET #revert' do @@ -99,11 +102,54 @@ describe Admin::VersionsController do end describe 'GET #index' do - it 'raises error if user is not an organizer of specified conference' do + it 'raises error if user is not of any role' do user = create(:user) sign_in user get :index, conference_id: conference.short_title - expect(flash[:alert]).to match('You are not authorized to access this area.') + expect(flash[:alert]).to match('You are not authorized to access this page.') + end + + context 'with conference' do + before :each do + @user = create(:user) + + conference.update_attributes(short_title: 'testtitle', description: 'Some random text') + @version_organizer = PaperTrail::Version.last + create(:cfp, program: conference.program) + @version_cfp = PaperTrail::Version.last + registration = create(:registration, conference: conference) + registration.update_attributes(attended: true) + @version_info_desk = PaperTrail::Version.last + end + + it 'when user has role cfp' do + @user.roles = [role_cfp] + sign_in @user + get :index, conference_id: conference.short_title + + expect(assigns(:versions).include?(@version_cfp)).to eq true + expect(assigns(:versions).include?(@version_organizer)).to eq false + end + + it 'when user has role info_desk' do + @user.roles = [role_info_desk] + sign_in @user + get :index, conference_id: conference.short_title + + expect(assigns(:versions).include?(@version_info_desk)).to eq true + expect(assigns(:versions).include?(@version_organizer)).to eq false + expect(assigns(:versions).include?(@version_cfp)).to eq false + end + + it 'when user has role organizer' do + @user.roles = [role_organizer] + sign_in @user + get :index, conference_id: conference.short_title + + expect(assigns(:versions).include?(@version_organizer)).to eq true + expect(assigns(:versions).include?(@version_cfp)).to eq true + expect(assigns(:versions).include?(@version_info_desk)).to eq true + end end end end diff --git a/spec/features/cfp_ability_spec.rb b/spec/features/cfp_ability_spec.rb index 1607401c..7229ab8d 100644 --- a/spec/features/cfp_ability_spec.rb +++ b/spec/features/cfp_ability_spec.rb @@ -298,7 +298,7 @@ feature 'Has correct abilities' do expect(current_path).to eq(root_path) visit admin_revision_history_path - expect(current_path).to eq(root_path) + expect(current_path).to eq(admin_revision_history_path) end end end diff --git a/spec/features/info_desk_ability_spec.rb b/spec/features/info_desk_ability_spec.rb index c005f9de..f4ef4fce 100644 --- a/spec/features/info_desk_ability_spec.rb +++ b/spec/features/info_desk_ability_spec.rb @@ -160,7 +160,7 @@ feature 'Has correct abilities' do expect(current_path).to eq(edit_admin_conference_resource_path(conference.short_title, conference.resources.first)) visit admin_revision_history_path - expect(current_path).to eq(root_path) + expect(current_path).to eq(admin_revision_history_path) visit admin_conference_path(conference.short_title) expect(current_path).to eq(admin_conference_path(conference.short_title)) diff --git a/spec/features/versions_spec.rb b/spec/features/versions_spec.rb index 2f1f7f8e..0db2d1f9 100644 --- a/spec/features/versions_spec.rb +++ b/spec/features/versions_spec.rb @@ -93,7 +93,7 @@ feature 'Version' do expect(page).to have_text("Someone (probably via the console) deleted lodging Hotel XYZ with ID #{lodging_id} in conference #{conference.short_title}") end - scenario 'display changes in role', feature: true, versioning: true, js: true do + scenario 'display changes in conference role', feature: true, versioning: true, js: true do visit edit_admin_conference_role_path(conference.short_title, 'cfp') fill_in 'role_description', with: 'For the members of the call for papers team' click_button 'Update Role' @@ -301,14 +301,40 @@ feature 'Version' do expect(page).to have_no_text('Someone (probably via the console) created new commercial') end - scenario 'display changes in users_role', feature: true, versioning: true, js: true do + scenario 'display changes in organization', feature: true, versioning: true, js: true do + admin = create(:admin) + sign_in admin + + visit new_admin_organization_path + fill_in 'organization_name', with: 'New org' + click_button 'Create Organization' + + visit admin_revision_history_path + expect(page).to have_text('created new organization New org') + end + + scenario 'display changes in users_role for organization role', feature: true, versioning: true, js: true do user = create(:user) + role = Role.find_by(resource_id: conference.organization.id, resource_type: 'Organization') + user.add_role :organization_admin, conference.organization + user_role = UsersRole.find_by(user_id: user.id, role_id: role.id) + user.remove_role :organization_admin, conference.organization + + visit admin_revision_history_path + expect(page).to have_text("added role organization_admin with ID #{user_role.id} to user #{user.name} in organization #{conference.organization.name}") + expect(page).to have_text("removed role organization_admin with ID #{user_role.id} from user #{user.name} in organization #{conference.organization.name}") + end + + scenario 'display changes in users_role for conference role', feature: true, versioning: true, js: true do + user = create(:user) + role = Role.find_by(name: 'cfp', resource_id: conference.id, resource_type: 'Conference') user.add_role :cfp, conference + user_role = UsersRole.find_by(user_id: user.id, role_id: role.id) user.remove_role :cfp, conference visit admin_revision_history_path - expect(page).to have_text("added role cfp to user #{user.name} in conference #{conference.short_title}") - expect(page).to have_text("removed role cfp from user #{user.name} in conference #{conference.short_title}") + expect(page).to have_text("added role cfp with ID #{user_role.id} to user #{user.name} in conference #{conference.short_title}") + expect(page).to have_text("removed role cfp with ID #{user_role.id} from user #{user.name} in conference #{conference.short_title}") end scenario 'display changes in email settings', feature: true, versioning: true, js: true do From 7067803cb9afb1850d2adb78b6f8b10d073f625c Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Tue, 8 Aug 2017 14:18:42 +0300 Subject: [PATCH 186/237] Validate that tracks don't overlap Also, add scope for accepted tracks --- app/models/track.rb | 18 ++++++++ spec/models/track_spec.rb | 88 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/app/models/track.rb b/app/models/track.rb index c624cab8..f2b1ac95 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -31,9 +31,11 @@ class Track < ActiveRecord::Base validates :description, presence: true, if: :self_organized? validate :valid_dates validate :valid_room, if: :self_organized_and_accepted_or_confirmed? + validate :overlapping before_validation :capitalize_color + scope :accepted, -> { where(state: 'accepted') } scope :confirmed, -> { where(state: 'confirmed') } scope :cfp_active, -> { where(cfp_active: true) } @@ -209,4 +211,20 @@ class Track < ActiveRecord::Base errors.add(:room, "must be a room of #{program.conference.venue.name}") end end + + ## + # Check that there is no other track in the same room with overlapping dates + def overlapping + return unless start_date && end_date && room && program.try(:tracks) + (program.tracks.accepted + program.tracks.confirmed - [self]).each do |other_track| + if other_track.room == room && + other_track.start_date && other_track.end_date && + (other_track.start_date <= start_date && other_track.end_date >= start_date || + other_track.start_date <= end_date && other_track.end_date >= end_date || + start_date <= other_track.start_date && other_track.end_date <= end_date) + errors.add(:track, 'has overlapping dates with a confirmed or accepted track in the same room') + break + end + end + end end diff --git a/spec/models/track_spec.rb b/spec/models/track_spec.rb index 1ad54839..f9c53653 100644 --- a/spec/models/track_spec.rb +++ b/spec/models/track_spec.rb @@ -136,9 +136,97 @@ describe Track do end end end + + describe '#overlapping' do + before :each do + @conference = create(:conference, start_date: Date.current - 1.day, end_date: Date.current + 2.days) + @conference.venue = create(:venue) + @room = create(:room, venue: @conference.venue) + end + + context 'is valid' do + it 'when the tracks are in different rooms' do + other_room = create(:room, venue: @conference.venue) + create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: other_room, start_date: Date.current, end_date: Date.current) + track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) + expect(track.valid?).to eq true + end + + it 'when it ends before the other tracks' do + create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) + track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current - 1.day, end_date: Date.current - 1.day) + expect(track.valid?).to eq true + end + + it 'when it starts after the other tracks' do + create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) + track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current + 1.day, end_date: Date.current + 1.day) + expect(track.valid?).to eq true + end + end + + context 'is invalid' do + it 'when it starts or ends with another track in the same room' do + create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) + track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) + expect(track.valid?).to eq false + expect(track.errors[:track]).to eq ['has overlapping dates with a confirmed or accepted track in the same room'] + end + + it 'when it starts before another track and ends after the other starts and before it ends' do + create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current + 2.days) + track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current - 1.day, end_date: Date.current + 1.day) + expect(track.valid?).to eq false + expect(track.errors[:track]).to eq ['has overlapping dates with a confirmed or accepted track in the same room'] + end + + it 'when it starts after another track and before it ends and ends after the other' do + create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current + 2.days) + track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current + 1.day, end_date: Date.current + 3.days) + expect(track.valid?).to eq false + expect(track.errors[:track]).to eq ['has overlapping dates with a confirmed or accepted track in the same room'] + end + + it 'when it starts after another track and ends before the other' do + create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current + 2.days) + track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current + 1.day, end_date: Date.current + 1.day) + expect(track.valid?).to eq false + expect(track.errors[:track]).to eq ['has overlapping dates with a confirmed or accepted track in the same room'] + end + + it 'when it starts before another track and ends after the other' do + create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) + track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current - 1.day, end_date: Date.current + 1.day) + expect(track.valid?).to eq false + expect(track.errors[:track]).to eq ['has overlapping dates with a confirmed or accepted track in the same room'] + end + end + end end describe 'scope' do + describe '#accepted' do + before :each do + @program = create(:program) + end + + context 'includes' do + it 'when track is accepted' do + accepted_track = create(:track, state: 'accepted', program: @program) + expect(@program.tracks.accepted.include?(accepted_track)).to eq true + end + end + + context 'excludes' do + %w[new to_accept confirmed to_reject rejected canceled withdrawn].each do |state| + it "when track is #{state.humanize}" do + not_accepted_track = create(:track, state: state, program: @program) + expect(@program.tracks.accepted.include?(not_accepted_track)).to eq false + end + end + end + end + describe '#confirmed' do before :each do @program = create(:program) From c4eec6a3de27041162db476bed3f3b667013b59b Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Tue, 8 Aug 2017 16:18:11 +0300 Subject: [PATCH 187/237] Validate room and start_time for EventSchedule Don't allow an event to be scheduled outside of it's track's room and time slot --- app/models/event_schedule.rb | 24 ++++++++++++ spec/models/event_schedule_spec.rb | 63 ++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/app/models/event_schedule.rb b/app/models/event_schedule.rb index 82f1e55a..a7cc1ed1 100644 --- a/app/models/event_schedule.rb +++ b/app/models/event_schedule.rb @@ -12,6 +12,8 @@ class EventSchedule < ActiveRecord::Base validates :event, uniqueness: { scope: :schedule } validate :start_after_end_hour validate :start_before_start_hour + validate :room_of_track + validate :during_track scope :confirmed, -> { joins(:event).where('state = ?', 'confirmed') } scope :canceled, -> { joins(:event).where('state = ?', 'canceled') } @@ -52,4 +54,26 @@ class EventSchedule < ActiveRecord::Base def conference_id schedule.program.conference_id end + + ## + # Validates that the event is scheduled in the same room as it's track + # + def room_of_track + if event && event.track.try(:room) && event.track.room != room + errors.add(:room, "must be the same as the track's room (#{event.track.room.name})") + end + end + + ## + # Validates that the event is scheduled within it's track's time slot + # + def during_track + if event && event.track.try(:start_date) && event.track.start_date > start_time + errors.add(:start_time, "can't be before the track's start date (#{event.track.start_date})") + end + + if event && event.track.try(:end_date) && event.track.end_date + 1.day < end_time + errors.add(:end_time, "can't be after the track's end date (#{event.track.end_date})") + end + end end diff --git a/spec/models/event_schedule_spec.rb b/spec/models/event_schedule_spec.rb index 6d1325b7..8e22430b 100644 --- a/spec/models/event_schedule_spec.rb +++ b/spec/models/event_schedule_spec.rb @@ -45,5 +45,68 @@ describe EventSchedule do end end end + + describe '#room_of_track' do + before :each do + conference = create(:conference) + conference.venue = create(:venue) + @room = create(:room, venue: conference.venue) + @track = create(:track, program: conference.program, room: @room) + @event = create(:event, program: conference.program, track: @track) + end + + context 'is valid' do + it 'when scheduled in the track\'s room' do + event_schedule = build(:event_schedule, event: @event, room: @room) + expect(event_schedule.valid?).to eq true + end + + it 'when the track doesn\'t have a room' do + @track.room = nil + @track.save! + event_schedule = build(:event_schedule, event: @event) + expect(event_schedule.valid?).to eq true + end + end + + context 'is invalid' do + it 'when scheduled in different room than the track\'s' do + event_schedule = build(:event_schedule, event: @event) + expect(event_schedule.valid?).to eq false + expect(event_schedule.errors[:room]).to eq ["must be the same as the track's room (#{@room.name})"] + end + end + end + + describe '#during_track' do + before :each do + conference = create(:conference, start_date: Date.current - 1.day, start_hour: 0, end_hour: 24) + conference.venue = create(:venue) + @room = create(:room, venue: conference.venue) + @track = create(:track, program: conference.program, room: @room, start_date: Date.current, end_date: Date.current) + @event = create(:event, program: conference.program, track: @track) + end + + context 'is valid' do + it 'when scheduled during the track\'s time slot' do + event_schedule = build(:event_schedule, event: @event, room: @room, start_time: Date.current + 3.hours) + expect(event_schedule.valid?).to eq true + end + end + + context 'is invalid' do + it 'when scheduled before the track\'s start date' do + event_schedule = build(:event_schedule, event: @event, room: @room, start_time: Date.current - 1.hour) + expect(event_schedule.valid?).to eq false + expect(event_schedule.errors[:start_time]).to eq ["can't be before the track's start date (#{@track.start_date})"] + end + + it 'when event ends after the track\'s end date' do + event_schedule = build(:event_schedule, event: @event, room: @room, start_time: Date.current + 1.day - 10.minutes) + expect(event_schedule.valid?).to eq false + expect(event_schedule.errors[:end_time]).to eq ["can't be after the track's end date (#{@track.end_date})"] + end + end + end end end From a87c6e55f7e9a0d073a98fd899567d273d2f46b7 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 9 Aug 2017 12:05:11 +0300 Subject: [PATCH 188/237] Remove unnecessary ability from adminAbilities CanCanCan can load @events and @event in EventsController by itself --- app/controllers/admin/events_controller.rb | 13 ------------- app/controllers/admin/reports_controller.rb | 4 +++- app/models/admin_ability.rb | 4 ---- spec/features/track_organizer_ability_spec.rb | 2 +- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/app/controllers/admin/events_controller.rb b/app/controllers/admin/events_controller.rb index 1aa2e4bd..c93c3892 100644 --- a/app/controllers/admin/events_controller.rb +++ b/app/controllers/admin/events_controller.rb @@ -5,8 +5,6 @@ module Admin load_and_authorize_resource :event, through: :program load_and_authorize_resource :events_registration, only: :toggle_attendance - before_action :get_event, except: [:index, :create, :new] - # FIXME: The timezome should only be applied on output, otherwise # you get lost in timezone conversions... # around_filter :set_timezone_for_this_request @@ -16,7 +14,6 @@ module Admin end def index - @events = @program.events @tracks = @program.tracks.confirmed.cfp_active @difficulty_levels = @program.difficulty_levels @event_types = @program.event_types @@ -187,16 +184,6 @@ module Admin params.require(:comment).permit(:commentable, :body, :user_id) end - def get_event - @event = @conference.program.events.find(params[:id]) - unless @event - redirect_to admin_conference_program_events_path(conference_id: @conference.short_title), - error: 'Error! Could not find event!' - return - end - @event - end - def update_state(transition, notice, mail = false, subject = false, send_mail = false) alert = @event.update_state(transition, mail, subject, send_mail, params[:send_mail].blank?) diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb index c6d4003c..b01a4bdc 100644 --- a/app/controllers/admin/reports_controller.rb +++ b/app/controllers/admin/reports_controller.rb @@ -2,9 +2,11 @@ module Admin class ReportsController < Admin::BaseController load_and_authorize_resource :conference, find_by: :short_title load_and_authorize_resource :program, through: :conference, singleton: true + # For some reason this doesn't work, so a workaround is used + # load_and_authorize_resource :event, through: :program def index - @events = @program.events + @events = Event.accessible_by(current_ability).where(program: @program) @events_commercials = Commercial.where(commercialable_type: 'Event', commercialable_id: @events.pluck(:id)) @events_missing_commercial = @events.where.not(id: @events_commercials.pluck(:commercialable_id)) @events_with_requirements = @events.where.not(description: ['', nil]) diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index 7fd805d1..e8b8d098 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -39,10 +39,6 @@ class AdminAbility event.program.cfp_open? && event.new_record? end - can [:update, :show, :index], Event do |event| - event.users.include?(user) - end - # can manage the commercials of their own events can :manage, Commercial, commercialable_type: 'Event', commercialable_id: user.events.pluck(:id) diff --git a/spec/features/track_organizer_ability_spec.rb b/spec/features/track_organizer_ability_spec.rb index 49e46915..91c0b55a 100644 --- a/spec/features/track_organizer_ability_spec.rb +++ b/spec/features/track_organizer_ability_spec.rb @@ -101,7 +101,7 @@ feature 'Has correct abilities' do expect(current_path).to eq root_path visit admin_conference_program_events_path(conference.short_title) - expect(current_path).to eq admin_conference_program_events_path(conference.short_title) + expect(current_path).to eq root_path create(:event, program: conference.program) visit edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first) From af7efdb6fe888fa479b24b971a1e4ad92817a560 Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 9 Aug 2017 14:53:27 +0300 Subject: [PATCH 189/237] Allow the track organizer to manage events He/She can manage the events of his/her tracks and their commercials --- app/controllers/admin/events_controller.rb | 11 ++++++++--- app/models/admin_ability.rb | 9 +++++++++ spec/features/track_organizer_ability_spec.rb | 14 +++++++++----- spec/models/admin_ability_spec.rb | 9 ++++++++- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/app/controllers/admin/events_controller.rb b/app/controllers/admin/events_controller.rb index c93c3892..2d7af60e 100644 --- a/app/controllers/admin/events_controller.rb +++ b/app/controllers/admin/events_controller.rb @@ -4,6 +4,10 @@ module Admin load_and_authorize_resource :program, through: :conference, singleton: true load_and_authorize_resource :event, through: :program load_and_authorize_resource :events_registration, only: :toggle_attendance + # For some reason this doesn't work, so a workaround is used + # load_and_authorize_resource :track, through: :program, only: [:index, :show, :edit] + + before_action :get_tracks, only: [:index, :show, :edit] # FIXME: The timezome should only be applied on output, otherwise # you get lost in timezone conversions... @@ -14,7 +18,6 @@ module Admin end def index - @tracks = @program.tracks.confirmed.cfp_active @difficulty_levels = @program.difficulty_levels @event_types = @program.event_types @tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed) @@ -40,7 +43,6 @@ module Admin end def show - @tracks = @program.tracks.confirmed.cfp_active @event_types = @program.event_types @comments = @event.root_comments @comment_count = @event.comment_threads.count @@ -55,7 +57,6 @@ module Admin def edit @event_types = @program.event_types - @tracks = @program.tracks.confirmed.cfp_active @comments = @event.root_comments @comment_count = @event.comment_threads.count @user = @event.submitter @@ -195,5 +196,9 @@ module Admin return redirect_back_or_to(admin_conference_program_events_path(conference_id: @conference.short_title)) && return end end + + def get_tracks + @tracks = Track.accessible_by(current_ability).where(program: @program).confirmed.cfp_active + end end end diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index e8b8d098..af0f80eb 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -298,5 +298,14 @@ class AdminAbility can :toggle_user, Role do |role| role.resource_type == 'Track' && track_ids_for_track_organizer.include?(role.resource_id) end + + # Show Events in the admin sidebar + can :update, Event do |event| + event.new_record? && conf_ids_for_track_organizer.include?(event.program.conference_id) + end + + can :manage, Event, track_id: track_ids_for_track_organizer + can :manage, Commercial, commercialable_type: 'Event', + commercialable_id: Event.where(track_id: track_ids_for_track_organizer).pluck(:id) end end diff --git a/spec/features/track_organizer_ability_spec.rb b/spec/features/track_organizer_ability_spec.rb index 91c0b55a..69b4d3e5 100644 --- a/spec/features/track_organizer_ability_spec.rb +++ b/spec/features/track_organizer_ability_spec.rb @@ -4,7 +4,7 @@ feature 'Has correct abilities' do let(:organization) { create(:organization) } let(:conference) { create(:full_conference, organization: organization) } - let(:self_organized_track) { create(:track, :self_organized, program: conference.program) } + let(:self_organized_track) { create(:track, :self_organized, program: conference.program, state: 'confirmed', cfp_active: true) } let(:role_track_organizer) { Role.where(name: 'track_organizer', resource: self_organized_track).first_or_create } let(:user_track_organizer) { create(:user, role_ids: [role_track_organizer.id]) } @@ -28,12 +28,12 @@ feature 'Has correct abilities' do expect(page).to_not have_link('Lodgings', href: "/admin/conferences/#{conference.short_title}/lodgings") expect(page).to have_link('Program', href: "/admin/conferences/#{conference.short_title}/program") expect(page).to_not have_link('Call for Papers', href: "/admin/conferences/#{conference.short_title}/program/cfps") - expect(page).to_not have_link('Events', href: "/admin/conferences/#{conference.short_title}/program/events") + 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_not have_link('Event Types', href: "/admin/conferences/#{conference.short_title}/program/event_types") expect(page).to_not have_link('Difficulty Levels', href: "/admin/conferences/#{conference.short_title}/program/difficulty_levels") expect(page).to_not have_link('Schedules', href: "/admin/conferences/#{conference.short_title}/schedules") - expect(page).to_not have_link('Reports', href: "/admin/conferences/#{conference.short_title}/program/reports") + expect(page).to have_link('Reports', href: "/admin/conferences/#{conference.short_title}/program/reports") expect(page).to_not have_link('Registrations', href: "/admin/conferences/#{conference.short_title}/registrations") expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period") expect(page).to_not have_link('Questions', href: "/admin/conferences/#{conference.short_title}/questions") @@ -101,12 +101,16 @@ feature 'Has correct abilities' do expect(current_path).to eq root_path visit admin_conference_program_events_path(conference.short_title) - expect(current_path).to eq root_path + expect(current_path).to eq admin_conference_program_events_path(conference.short_title) create(:event, program: conference.program) visit edit_admin_conference_program_event_path(conference.short_title, conference.program.events.first) expect(current_path).to eq root_path + self_organized_track_event = create(:event, program: conference.program, track: self_organized_track) + visit edit_admin_conference_program_event_path(conference.short_title, self_organized_track_event) + expect(current_path).to eq(edit_admin_conference_program_event_path(conference.short_title, self_organized_track_event)) + visit admin_conference_program_event_types_path(conference.short_title) expect(current_path).to eq root_path @@ -219,7 +223,7 @@ feature 'Has correct abilities' do expect(current_path).to eq admin_conference_program_track_path(conference.short_title, self_organized_track) visit edit_admin_conference_program_track_path(conference.short_title, self_organized_track) - expect(current_path).to eq edit_admin_conference_program_track_path(conference.short_title, self_organized_track) + expect(current_path).to eq root_path visit admin_conference_roles_path(conference.short_title) expect(current_path).to eq admin_conference_roles_path(conference.short_title) diff --git a/spec/models/admin_ability_spec.rb b/spec/models/admin_ability_spec.rb index f148b2ae..126668fa 100644 --- a/spec/models/admin_ability_spec.rb +++ b/spec/models/admin_ability_spec.rb @@ -45,7 +45,7 @@ describe 'User with admin role' do let!(:my_event_schedule) { create(:event_schedule, schedule: my_schedule) } let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) } - let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program, state: 'confirmed') } + let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program, state: 'confirmed', cfp_active: true) } context 'user #is_admin?' do let(:venue) { my_conference.venue } @@ -459,6 +459,9 @@ describe 'User with admin role' do let(:role) { Role.where(name: 'track_organizer', resource: my_self_organized_track).first_or_create } let(:user) { create(:user, role_ids: [role.id]) } let(:new_track) { build(:track, program: my_conference.program) } + let(:new_event) { build(:event, program: my_conference.program) } + let(:my_self_organized_track_event) { create(:event, program: my_conference.program, track: my_self_organized_track) } + let(:my_self_organized_track_event_commercial) { create(:commercial, commercialable: my_self_organized_track_event) } it{ should_not be_able_to(:new, Conference.new) } it{ should_not be_able_to(:create, Conference.new) } @@ -525,6 +528,10 @@ describe 'User with admin role' do it{ should_not be_able_to(:assign_org_admins, organization) } it{ should_not be_able_to(:unassign_org_admins, organization) } + it{ should be_able_to(:update, new_event) } + it{ should be_able_to(:manage, my_self_organized_track_event) } + it{ should be_able_to(:manage, my_self_organized_track_event_commercial) } + it_behaves_like 'user with any role' it_behaves_like 'user with non-organizer role', 'track_organizer' end From 7eea9302694943858d81e450e14e188e6832f7bd Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Wed, 9 Aug 2017 18:12:20 +0300 Subject: [PATCH 190/237] Implement track scheduling Add track association to schedule Show schedules in admin sidebar to track organizers Allow track organizers to manage the schedules of their tracks Don't allow self-organized track events to be dragged or unscheduled in a conference schedule Make scheduled events of self-organized tracks appear semitransparent in conference schedules Make the rooms of confirmed self_organized tracks appear semitransparent and don't allow events to be scheduled to it in the conference schedules during the dates of its track Create admin/SchedulesController#new action Add a button in admin/Schedules#index to create schedules for tracks Add self_organized scope to Track Modify Schedules#show to handle track schedules and show a unified schedule Allow track organizers to create new schedules for their tracks Correctly identify scheduled and unscheduled events in Schedules#events Fix Event#room and Event#time for when the event is scheduled in a track schedule Modify Program#selected_event_schedules to include the event_schedules of selected track schedules Modify Track#revoke_role_and_cleanup to destroy the track's schedules and revert its events' state to new Add tabs for conference and track schedules in admin/Schedules#index Add button to Create/Show a tracks schedule in Tracks#index and #show Fix concurrent_events in application_helper because of changes in Program#selected_event_schedules Do not take into account cfp_active in Event#valid_track Modify EventsController#get_tracks accordingly Enforce cfp_active of track to be enabled for proposals in ProposalsController#create and #update Add support for multiple schedules per track Add selected_schedule_id to Track Load EventSchedules of selected track schedules for conference schedules in admin/SchedulesController#show Modify SchedulesController#show to take into account only the selected track schedules Create Event#selected_schedule_id and use it in Event#scheduled? and Event#time Validate that an EventSchedule for an event of a self-organized track belongs to one of the track's schedules Add 'Manage' button in Tracks#index, #show that sends you to the admin side of things Add admin/TracksController#update_selected_schedule to update the selected_schedule_id of tracks --- .haml-lint_todo.yml | 2 + .rubocop.yml | 1 + app/assets/javascripts/osem-schedule.js | 7 +- app/assets/stylesheets/osem-schedule.css.scss | 4 + app/controllers/admin/events_controller.rb | 2 +- app/controllers/admin/schedules_controller.rb | 35 ++++- app/controllers/admin/tracks_controller.rb | 12 ++ app/controllers/proposals_controller.rb | 13 ++ app/controllers/schedules_controller.rb | 13 +- app/helpers/application_helper.rb | 2 +- app/models/admin_ability.rb | 13 ++ app/models/event.rb | 32 ++++- app/models/event_schedule.rb | 38 ++++-- app/models/program.rb | 6 +- app/models/schedule.rb | 1 + app/models/track.rb | 14 +- app/views/admin/schedules/_day_tab.html.haml | 4 +- app/views/admin/schedules/_event.html.haml | 3 +- app/views/admin/schedules/_form.html.haml | 10 ++ app/views/admin/schedules/index.html.haml | 121 ++++++++++++------ app/views/admin/schedules/show.html.haml | 11 +- app/views/admin/tracks/index.html.haml | 10 ++ app/views/admin/tracks/show.html.haml | 10 ++ app/views/proposals/show.html.haml | 2 +- app/views/schedules/_carousel.html.haml | 2 +- app/views/tracks/index.html.haml | 2 + app/views/tracks/show.html.haml | 2 + config/routes.rb | 3 +- ...9120927_add_track_reference_to_schedule.rb | 5 + ...4174637_add_selected_schedule_to_tracks.rb | 6 + db/schema.rb | 14 +- spec/features/track_organizer_ability_spec.rb | 10 +- spec/models/admin_ability_spec.rb | 11 +- spec/models/event_schedule_spec.rb | 36 +++++- spec/models/event_spec.rb | 43 +++++-- spec/models/schedule_spec.rb | 1 + spec/models/track_spec.rb | 60 +++++++-- 37 files changed, 443 insertions(+), 118 deletions(-) create mode 100644 app/views/admin/schedules/_form.html.haml create mode 100644 db/migrate/20170809120927_add_track_reference_to_schedule.rb create mode 100644 db/migrate/20170814174637_add_selected_schedule_to_tracks.rb diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml index 49feab3d..b79ddc17 100644 --- a/.haml-lint_todo.yml +++ b/.haml-lint_todo.yml @@ -188,6 +188,7 @@ linters: - "app/views/conferences/_call_for_tracks.html.haml" - "app/views/admin/tracks/_change_state_dropdown.html.haml" - "app/views/proposals/_encouragement_text.html.haml" + - "app/views/admin/schedules/_form.html.haml" # Offense count: 223 InstanceVariables: @@ -253,6 +254,7 @@ linters: - "app/views/admin/cfps/_tracks_cfp.html.haml" - "app/views/conferences/_call_for_tracks.html.haml" - "app/views/admin/tracks/_change_state_dropdown.html.haml" + - "app/views/admin/schedules/_form.html.haml" # Offense count: 32 IdNames: diff --git a/.rubocop.yml b/.rubocop.yml index 5d24032d..9ab6f6b3 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -31,3 +31,4 @@ Metrics/BlockLength: - 'spec/models/conference_spec.rb' - 'spec/features/ability_spec.rb' - 'spec/models/ability_spec.rb' + - 'spec/models/admin_ability_spec.rb' diff --git a/app/assets/javascripts/osem-schedule.js b/app/assets/javascripts/osem-schedule.js index baae1933..39e33922 100644 --- a/app/assets/javascripts/osem-schedule.js +++ b/app/assets/javascripts/osem-schedule.js @@ -78,11 +78,12 @@ var Schedule = { }; $(document).ready( function() { - // hide the remove button for unscheduled events + // hide the remove button for unscheduled and non schedulable events $('.unscheduled-events .schedule-event-delete-button').hide(); + $('.non_schedulable .schedule-event-delete-button').hide(); // set events as draggable - $('.schedule-event').draggable({ + $('.schedule-event').not('.non_schedulable').draggable({ snap: '.schedule-room-slot', revertDuration: 200, revert: function (event, ui) { @@ -99,7 +100,7 @@ $(document).ready( function() { }); // set room cells as droppable - $('.schedule-room-slot').droppable({ + $('.schedule-room-slot').not('.non_schedulable .schedule-room-slot').droppable({ accept: '.schedule-event', tolerance: "pointer", drop: function(event, ui) { diff --git a/app/assets/stylesheets/osem-schedule.css.scss b/app/assets/stylesheets/osem-schedule.css.scss index 21fda6f3..75a71767 100644 --- a/app/assets/stylesheets/osem-schedule.css.scss +++ b/app/assets/stylesheets/osem-schedule.css.scss @@ -267,6 +267,10 @@ td.no-padding{ font-size: 7px; } +.non_schedulable{ + opacity: 0.5; +} + /* Small devices (tablets, 768px and up) */ @media (min-width: 768px) { .room, .event-title{ diff --git a/app/controllers/admin/events_controller.rb b/app/controllers/admin/events_controller.rb index 2d7af60e..bb23dac9 100644 --- a/app/controllers/admin/events_controller.rb +++ b/app/controllers/admin/events_controller.rb @@ -198,7 +198,7 @@ module Admin end def get_tracks - @tracks = Track.accessible_by(current_ability).where(program: @program).confirmed.cfp_active + @tracks = Track.accessible_by(current_ability).where(program: @program).confirmed end end end diff --git a/app/controllers/admin/schedules_controller.rb b/app/controllers/admin/schedules_controller.rb index d3c7cea3..00ef9a1d 100644 --- a/app/controllers/admin/schedules_controller.rb +++ b/app/controllers/admin/schedules_controller.rb @@ -4,14 +4,21 @@ module Admin # the schedule of a conference, which should not be accessed in the first place load_and_authorize_resource :conference, find_by: :short_title load_and_authorize_resource :program, through: :conference, singleton: true - load_and_authorize_resource :schedule, through: :program + load_and_authorize_resource :schedule, through: :program, except: [:new, :create] load_resource :event_schedules, through: :schedule load_resource :selected_schedule, through: :program, singleton: true load_resource :venue, through: :conference, singleton: true def index; end + def new + @schedule = @program.schedules.build(track: @program.tracks.new) + authorize! :new, @schedule + end + def create + @schedule = @program.schedules.new(schedule_params) + authorize! :create, @schedule if @schedule.save redirect_to admin_conference_schedule_path(@conference.short_title, @schedule.id), notice: 'Schedule was successfully created.' @@ -23,9 +30,23 @@ module Admin def show @event_schedules = @schedule.event_schedules - @unscheduled_events = @program.events.confirmed - @schedule.events - @dates = @conference.start_date..@conference.end_date - @rooms = @conference.venue.rooms if @conference.venue + + if @schedule.track + track = @schedule.track + @unscheduled_events = track.events.confirmed - @schedule.events + @dates = track.start_date..track.end_date + @rooms = [track.room] + else + @program.tracks.self_organized.confirmed.each do |t| + @event_schedules += t.selected_schedule.event_schedules if t.selected_schedule + end + self_organized_tracks_events = @program.tracks.self_organized.confirmed.map do |t| + t.events.confirmed + end + @unscheduled_events = @program.events.confirmed - @schedule.events - self_organized_tracks_events.flatten.compact + @dates = @conference.start_date..@conference.end_date + @rooms = @conference.venue.rooms if @conference.venue + end end def destroy @@ -37,5 +58,11 @@ module Admin error: "Schedule couldn't be deleted. #{@schedule.errors.full_messages.join('. ')}." end end + + private + + def schedule_params + params.require(:schedule).permit(:track_id) if params[:schedule] + end end end diff --git a/app/controllers/admin/tracks_controller.rb b/app/controllers/admin/tracks_controller.rb index 0f3940da..03f26448 100644 --- a/app/controllers/admin/tracks_controller.rb +++ b/app/controllers/admin/tracks_controller.rb @@ -101,6 +101,18 @@ module Admin update_state(:cancel, "Track #{@track.name} canceled!") end + def update_selected_schedule + if @track.update_attributes(params.require(:track).permit(:selected_schedule_id)) + respond_to do |format| + format.js { render json: {} } + end + else + respond_to do |format| + format.js { render json: { errors: "The selected schedule couldn't been updated #{@track.errors.to_a.join('. ')}" }, status: 422 } + end + end + end + private def track_params diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index baf86f3c..b75f648e 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -49,6 +49,13 @@ class ProposalsController < ApplicationController # by default. @event.speakers = [current_user] @event.submitter = current_user + + if Track.find_by(id: params[:event][:track_id]).try(:cfp_active) == false + flash.now[:error] = 'You have selected a track that doesn\'t accept proposals' + render action: 'new' + return + end + if @event.save ahoy.track 'Event submission', title: 'New submission' redirect_to conference_program_proposals_path(@conference.short_title), notice: 'Proposal was successfully submitted.' @@ -61,6 +68,12 @@ class ProposalsController < ApplicationController def update @url = conference_program_proposal_path(@conference.short_title, params[:id]) + if Track.find_by(id: params[:event][:track_id]).try(:cfp_active) == false + flash.now[:error] = 'You have selected a track that doesn\'t accept proposals' + render action: 'edit' + return + end + if @event.update(event_params) redirect_to conference_program_proposals_path(conference_id: @conference.short_title), notice: 'Proposal was successfully updated.' diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb index 5fdbeecd..eeb272e0 100644 --- a/app/controllers/schedules_controller.rb +++ b/app/controllers/schedules_controller.rb @@ -24,6 +24,13 @@ class SchedulesController < ApplicationController return unless @current_day # the schedule takes you to the current time if it is beetween the start and the end time. @hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour) + + # Ids of the schedules of confrmed self_organized tracks along with the selected_schedule_id + @selected_schedules_ids = [@conference.program.selected_schedule_id] + @conference.program.tracks.self_organized.confirmed.each do |track| + @selected_schedules_ids << track.selected_schedule_id + end + @selected_schedules_ids.compact! end def events @@ -32,11 +39,7 @@ class SchedulesController < ApplicationController @events_schedules = @program.selected_event_schedules @events_schedules = [] unless @events_schedules - @unscheduled_events = if @program.selected_schedule - @program.events.confirmed - @program.selected_schedule.events - else - @program.events.confirmed - end + @unscheduled_events = @program.events.confirmed - @events_schedules.map(&:event) day = @conference.current_conference_day @tag = day.strftime('%Y-%m-%d') if day diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e55656ea..e4a0e230 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -117,7 +117,7 @@ module ApplicationHelper def concurrent_events(event) return nil unless event.scheduled? && event.program.selected_event_schedules - event_schedule = event.program.selected_event_schedules.find_by(event: event) + event_schedule = event.program.selected_event_schedules.find { |es| es.event == event } other_event_schedules = event.program.selected_event_schedules.reject { |other_event_schedule| other_event_schedule == event_schedule } concurrent_events = [] diff --git a/app/models/admin_ability.rb b/app/models/admin_ability.rb index af0f80eb..cc318da2 100644 --- a/app/models/admin_ability.rb +++ b/app/models/admin_ability.rb @@ -307,5 +307,18 @@ class AdminAbility can :manage, Event, track_id: track_ids_for_track_organizer can :manage, Commercial, commercialable_type: 'Event', commercialable_id: Event.where(track_id: track_ids_for_track_organizer).pluck(:id) + + # Show Scheduless in the admin sidebar + can :update, Schedule do |schedule| + schedule.new_record? && conf_ids_for_track_organizer.include?(schedule.program.conference_id) + end + + # Show new track schedule button + can :new, Schedule do |schedule| + schedule.new_record? && conf_ids_for_track_organizer.include?(schedule.program.conference_id) && schedule.track.try(:new_record?) + end + + can :manage, Schedule, track_id: track_ids_for_track_organizer + can :manage, EventSchedule, schedule: { track_id: track_ids_for_track_organizer } end end diff --git a/app/models/event.rb b/app/models/event.rb index 682eb6c8..c6de2d45 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -45,7 +45,7 @@ class Event < ActiveRecord::Base validates :max_attendees, numericality: { only_integer: true, greater_than_or_equal_to: 1, allow_nil: true } validate :max_attendees_no_more_than_room_size - validate :acceptable_track + validate :valid_track scope :confirmed, -> { where(state: 'confirmed') } scope :canceled, -> { where(state: 'canceled') } @@ -85,7 +85,7 @@ class Event < ActiveRecord::Base # ====Returns # * +true+ or +false+ def scheduled? - event_schedules.find_by(schedule_id: program.selected_schedule_id).present? + event_schedules.find_by(schedule_id: selected_schedule_id).present? end def registration_possible? @@ -243,14 +243,18 @@ class Event < ActiveRecord::Base def room # We use try(:selected_schedule_id) because this function is used for # validations so program could not be present there - event_schedules.find_by(schedule_id: program.try(:selected_schedule_id)).try(:room) + if track.try(:self_organized?) + track.room + else + event_schedules.find_by(schedule_id: program.try(:selected_schedule_id)).try(:room) + end end ## # Returns the start time at which this event is scheduled # def time - event_schedules.find_by(schedule_id: program.selected_schedule_id).try(:start_time) + event_schedules.find_by(schedule_id: selected_schedule_id).try(:start_time) end def conference @@ -306,9 +310,23 @@ class Event < ActiveRecord::Base end ## - # Allow only confirmed tracks that belong to the same program and are included in the cfp - def acceptable_track + # Allow only confirmed tracks that belong to the same program as the event + # + def valid_track return unless track && track.program && program - errors.add(:track, 'is invalid') unless track.confirmed? && track.cfp_active && track.program == program + errors.add(:track, 'is invalid') unless track.confirmed? && track.program == program + end + + ## + # Return the id of the selected schedule + # + # ====Returns + # * +Integer+ -> selected_schedule_id of self-organized track or program + def selected_schedule_id + if track.try(:self_organized?) + track.selected_schedule_id + else + program.selected_schedule_id + end end end diff --git a/app/models/event_schedule.rb b/app/models/event_schedule.rb index a7cc1ed1..57edbec0 100644 --- a/app/models/event_schedule.rb +++ b/app/models/event_schedule.rb @@ -12,8 +12,9 @@ class EventSchedule < ActiveRecord::Base validates :event, uniqueness: { scope: :schedule } validate :start_after_end_hour validate :start_before_start_hour - validate :room_of_track + validate :same_room_as_track validate :during_track + validate :valid_schedule scope :confirmed, -> { joins(:event).where('state = ?', 'confirmed') } scope :canceled, -> { joins(:event).where('state = ?', 'canceled') } @@ -56,24 +57,33 @@ class EventSchedule < ActiveRecord::Base end ## - # Validates that the event is scheduled in the same room as it's track + # Validates that the event is scheduled in the same room as its track # - def room_of_track - if event && event.track.try(:room) && event.track.room != room - errors.add(:room, "must be the same as the track's room (#{event.track.room.name})") + def same_room_as_track + return unless event.try(:track).try(:room) + errors.add(:room, "must be the same as the track's room (#{event.track.room.name})") unless event.track.room == room + end + + ## + # Validates that the event is scheduled within its track's time slot + # + def during_track + return unless event.try(:track) && start_time + + if event.track.try(:start_date) && event.track.start_date > start_time + errors.add(:start_time, "can't be before the track's start date (#{event.track.start_date})") + end + + if event.track.try(:end_date) && event.track.end_date + 1.day < end_time + errors.add(:end_time, "can't be after the track's end date (#{event.track.end_date})") end end ## - # Validates that the event is scheduled within it's track's time slot + # Validates that the event is scheduled in its self-organized tracks's schedules # - def during_track - if event && event.track.try(:start_date) && event.track.start_date > start_time - errors.add(:start_time, "can't be before the track's start date (#{event.track.start_date})") - end - - if event && event.track.try(:end_date) && event.track.end_date + 1.day < end_time - errors.add(:end_time, "can't be after the track's end date (#{event.track.end_date})") - end + def valid_schedule + return unless event.try(:track).try(:self_organized?) && schedule + errors.add(:schedule, "must be one of #{event.track.name} track's schedules") unless event.track.schedules.include?(schedule) end end diff --git a/app/models/program.rb b/app/models/program.rb index 49894cbd..612d8154 100644 --- a/app/models/program.rb +++ b/app/models/program.rb @@ -71,7 +71,11 @@ class Program < ActiveRecord::Base # Returns all event_schedules for the selected schedule ordered by start_time def selected_event_schedules - selected_schedule.event_schedules.order(start_time: :asc) if selected_schedule + event_schedules = selected_schedule.event_schedules.order(start_time: :asc) if selected_schedule + tracks.self_organized.confirmed.order(start_date: :asc).each do |track| + event_schedules += track.selected_schedule.event_schedules.order(start_time: :asc) if track.selected_schedule + end + event_schedules.sort_by(&:start_time) if event_schedules end ## diff --git a/app/models/schedule.rb b/app/models/schedule.rb index b14a978c..082d0af0 100644 --- a/app/models/schedule.rb +++ b/app/models/schedule.rb @@ -1,5 +1,6 @@ class Schedule < ActiveRecord::Base belongs_to :program + belongs_to :track has_many :event_schedules, dependent: :destroy has_many :events, through: :event_schedules diff --git a/app/models/track.rb b/app/models/track.rb index f2b1ac95..c3d02950 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -7,7 +7,9 @@ class Track < ActiveRecord::Base belongs_to :program belongs_to :submitter, class_name: 'User' belongs_to :room + belongs_to :selected_schedule, class_name: 'Schedule' has_many :events, dependent: :nullify + has_many :schedules has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id } @@ -38,6 +40,7 @@ class Track < ActiveRecord::Base scope :accepted, -> { where(state: 'accepted') } scope :confirmed, -> { where(state: 'confirmed') } scope :cfp_active, -> { where(cfp_active: true) } + scope :self_organized, -> { where.not(submitter: nil) } state_machine initial: :pending do state :new @@ -102,7 +105,10 @@ class Track < ActiveRecord::Base submitter.add_role 'track_organizer', self end - # Revokes the track organizer role and removes the track from events that have it set + ## + # Revokes the track organizer role, destroys the track's schedule, removes the + # track from events that have it set and reverts their state to new + # def revoke_role_and_cleanup role = Role.find_by(name: 'track_organizer', resource: self) @@ -112,8 +118,14 @@ class Track < ActiveRecord::Base end end + self.selected_schedule_id = nil + save! + + schedules.each(&:destroy!) + events.each do |event| event.track = nil + event.state = 'new' event.save! end end diff --git a/app/views/admin/schedules/_day_tab.html.haml b/app/views/admin/schedules/_day_tab.html.haml index 7bfe3ec6..8a1dff60 100644 --- a/app/views/admin/schedules/_day_tab.html.haml +++ b/app/views/admin/schedules/_day_tab.html.haml @@ -5,7 +5,9 @@ - date_event_schedules = @event_schedules.select{ |e| e.start_time.to_date.eql? date } .row - @rooms.each do |room| - .col-md-2.col-xs-6 + - non_schedulable = room.tracks.self_organized.confirmed.any? do |track| + - !track.schedules.include?(@schedule) && (track.start_date..track.end_date).include?(date) + .col-md-2.col-xs-6{ class: ('non_schedulable' if non_schedulable) } .room-name - room_date_event_schedules = date_event_schedules.select{ |e| e.room == room } = room.name diff --git a/app/views/admin/schedules/_event.html.haml b/app/views/admin/schedules/_event.html.haml index 3a13323b..ff6fd0c3 100644 --- a/app/views/admin/schedules/_event.html.haml +++ b/app/views/admin/schedules/_event.html.haml @@ -7,12 +7,13 @@ / subtracting the padding before calculate the number of lines - lines = (height - 7) / 23 - color = event.track.try(:color).present? ? event.track.try(:color) : 'FFFFFF' +- non_schedulable = event_schedule_id && (EventSchedule.find(event_schedule_id).schedule != @schedule) .schedule-event{ style: "height: #{height}px; background-color: #{color}; color: #{contrast_color(color)}", | id: "event-#{event.id}", | event_id: event.id, | length: cells_length, | event_schedule_id: event_schedule_id, | - class: ('compact' if compact_grid) } + class: "#{'compact' if compact_grid} #{'non_schedulable' if non_schedulable}" } .schedule-event-text{ style: "-webkit-line-clamp: #{lines}; height: #{lines * 23}px;"} %span.schedule-event-delete-button{ onclick: "Schedule.remove(\'event-#{event.id}\');" } X = event.title diff --git a/app/views/admin/schedules/_form.html.haml b/app/views/admin/schedules/_form.html.haml new file mode 100644 index 00000000..8c6c091d --- /dev/null +++ b/app/views/admin/schedules/_form.html.haml @@ -0,0 +1,10 @@ +.row + .col-md-12 + .page-header + %h1 + New Track Schedule +.row + .col-md-12 + = semantic_form_for @schedule, url: admin_conference_schedules_path(@conference.short_title) do |f| + = f.input :track, collection: Track.accessible_by(current_ability).where(program: @program).self_organized.confirmed.pluck(:name, :id), include_blank: false + = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/schedules/index.html.haml b/app/views/admin/schedules/index.html.haml index acfc79a8..29c1910e 100644 --- a/app/views/admin/schedules/index.html.haml +++ b/app/views/admin/schedules/index.html.haml @@ -4,42 +4,85 @@ %h1 Schedules %p.text-muted The schedules for your conference -.row - .col-md-12 - %table.table.table-hover#event_types - %thead - %th Schedule - %th Selected - %th Actions - %tbody - - @schedules.each do |schedule| - %tr - %td - Schedule - = schedule.id - %td - = selected_scheduled?(schedule) - %td - .btn-group{role: "group"} - = link_to 'Show', admin_conference_schedule_path(@conference.short_title, schedule.id), - method: :get, class: 'btn btn-primary' - = link_to 'Delete', admin_conference_schedule_path(@conference.short_title, schedule.id), - method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete Schedule #{schedule.id}?" } -.row - .col-md-12 - - if @venue.try(:rooms).present? - .text-right - = link_to 'Add Schedule', admin_conference_schedules_path(@conference.short_title), - method: :post, class: 'btn btn-primary' - - elsif @venue - .h3 - No Rooms! - %small - = link_to 'Create rooms', admin_conference_venue_rooms_path - before creating the schedule. - - else - .h3 - No Venue! - %small - = link_to 'Create a venue with rooms', new_admin_conference_venue_path - before creating the schedule. +.tabbable + %ul.nav.nav-tabs + %li.active + = link_to 'Conference schedules', '#conference', 'data-toggle' => 'tab' + %li + = link_to 'Track schedules', '#tracks', 'data-toggle' => 'tab' + .tab-content + .tab-pane.active#conference + .row + .col-md-12 + %table.table.table-hover + %thead + %th Schedule + %th Selected + %th Actions + %tbody + - @schedules.where(track: nil).each do |schedule| + %tr + %td + Schedule + = schedule.id + %td + = selected_scheduled?(schedule) + %td + .btn-group{role: "group"} + - if can? :show, schedule + = link_to 'Show', admin_conference_schedule_path(@conference.short_title, schedule), + method: :get, class: 'btn btn-primary' + - if can? :destroy, schedule + = link_to 'Delete', admin_conference_schedule_path(@conference.short_title, schedule), + method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete Schedule #{schedule.id}?" } + .row + .col-md-12 + - if @venue.try(:rooms).present? + .text-right + - if can? :create, @program.schedules.new + = link_to 'Add Schedule', admin_conference_schedules_path(@conference.short_title), + method: :post, class: 'btn btn-primary' + - elsif @venue + .h3 + No Rooms! + %small + = link_to 'Create rooms', admin_conference_venue_rooms_path + before creating the schedule. + - else + .h3 + No Venue! + %small + = link_to 'Create a venue with rooms', new_admin_conference_venue_path + before creating the schedule. + .tab-pane#tracks + .row + .col-md-12 + %table.table.table-hover + %thead + %th Schedule + %th Track + %th Selected + %th Actions + %tbody + - @schedules.where.not(track: nil).each do |schedule| + %tr + %td + Schedule + = schedule.id + %td + - track = schedule.track + = link_to track.name, admin_conference_program_track_path(@conference.short_title, track) + %td + = schedule == schedule.track.selected_schedule ? 'Yes' : 'No' + %td + .btn-group{role: "group"} + - if can? :show, schedule + = link_to 'Show', admin_conference_schedule_path(@conference.short_title, schedule), class: 'btn btn-primary' + - if can? :destroy, schedule + = link_to 'Delete', admin_conference_schedule_path(@conference.short_title, schedule), + method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete Schedule #{schedule.id}?" } + .row + .col-md-12 + .text-right + - if can? :new, @program.schedules.build(track: @program.tracks.new) + = link_to 'Add Track Schedule', new_admin_conference_schedule_path(@conference.short_title), class: 'btn btn-primary' diff --git a/app/views/admin/schedules/show.html.haml b/app/views/admin/schedules/show.html.haml index 9b2d3571..9009fcbb 100644 --- a/app/views/admin/schedules/show.html.haml +++ b/app/views/admin/schedules/show.html.haml @@ -11,8 +11,15 @@ .row .col-md-2 Selected schedule - = check_box_tag @conference.short_title, @schedule.id, (@schedule.id == @selected_schedule.try(:id)), - method: :patch, url: (admin_conference_program_path(@conference.short_title) + '?[program][selected_schedule_id]='), + :ruby + if @schedule.track + value = @schedule == @schedule.track.selected_schedule + url = update_selected_schedule_admin_conference_program_track_path(@conference.short_title, @schedule.track) + '?[track][selected_schedule_id]=' + else + value = @schedule.id == @selected_schedule.try(:id) + url = admin_conference_program_path(@conference.short_title) + '?[program][selected_schedule_id]=' + end + = check_box_tag @conference.short_title, @schedule.id, value, method: :patch, url: url, class: 'switch-checkbox-schedule', data: { size: 'small', off_color: 'warning', on_text: 'Yes', diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 77a7cf02..48c0d1b3 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -63,9 +63,19 @@ .btn-group{role: "group"} - if can? :edit, track = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-primary' + - special_style = true - if can? :destroy, track = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } + - if track.self_organized? + - if track.selected_schedule + - if can? :show, track.selected_schedule + = link_to 'Show Schedule', admin_conference_schedule_path(@conference.short_title, track.selected_schedule), + class: 'btn btn-default' + - elsif can? :create, @program.schedules.build(track: track) + = button_to 'Create Schedule', admin_conference_schedules_path(@conference.short_title), + form: { class: 'btn', style: 'padding: 0px 0px; margin-top: -1px;' }, class: 'btn btn-default', + style: ('border-top-left-radius: 0; border-bottom-left-radius: 0;' if special_style), params: { 'schedule[track_id]' => track.id } .row .col-md-12.text-right = link_to 'New Track', new_admin_conference_program_track_path(@conference.short_title), class: 'btn btn-success' diff --git a/app/views/admin/tracks/show.html.haml b/app/views/admin/tracks/show.html.haml index 78f8830e..b8c9773e 100644 --- a/app/views/admin/tracks/show.html.haml +++ b/app/views/admin/tracks/show.html.haml @@ -21,10 +21,20 @@ - if can? :edit, @track = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, @track), method: :get, class: 'btn btn-primary' + - special_style = true - if can? :destroy, @track = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, @track), method: :delete, class: 'btn btn-danger', data: { confirm: "Do you really want to delete #{@track.name}? Attention: This track will be removed from all Events that have it set" } + - if @track.self_organized? + - if @track.selected_schedule + - if can? :show, @track.selected_schedule + = link_to 'Show Schedule', admin_conference_schedule_path(@conference.short_title, @track.selected_schedule), + class: 'btn btn-default' + - elsif can? :create, @program.schedules.build(track: @track) + = button_to 'Create Schedule', admin_conference_schedules_path(@conference.short_title), + form: { class: 'btn', style: 'padding: 0px 0px; margin-top: -1px;' }, class: 'btn btn-default', + style: ('border-top-left-radius: 0; border-bottom-left-radius: 0;' if special_style), params: { 'schedule[track_id]' => @track.id } .row .col-md-12 %table.table diff --git a/app/views/proposals/show.html.haml b/app/views/proposals/show.html.haml index 2d38d3a8..c181e283 100644 --- a/app/views/proposals/show.html.haml +++ b/app/views/proposals/show.html.haml @@ -114,7 +114,7 @@ %dl %dt Start Time: %dd - = event.program.selected_event_schedules.find_by(event: event).start_time.strftime("%Y %B %e %H:%M") + = event.program.selected_event_schedules.find { |es| es.event == event }.start_time.strftime("%Y %B %e %H:%M") %br %dt Room: %dd diff --git a/app/views/schedules/_carousel.html.haml b/app/views/schedules/_carousel.html.haml index ce28e909..dde7e72c 100644 --- a/app/views/schedules/_carousel.html.haml +++ b/app/views/schedules/_carousel.html.haml @@ -29,7 +29,7 @@ %td.room{ style: "height: #{ td_height(@rooms) }px;" } .room.elipsis.break-words{ style: "-webkit-line-clamp: #{ room_lines(@rooms) }; height: #{ room_height(@rooms) }px;" } = room.name - - event_schedules = room.event_schedules.select{ |e| (e.schedule_id == @conference.program.selected_schedule.id) && (e.end_time > start_time) && (e.start_time <= (start_time + hrs_per_slide.hour)) } + - event_schedules = room.event_schedules.select{ |e| @selected_schedules_ids.include?(e.schedule_id) && (e.end_time > start_time) && (e.start_time <= (start_time + hrs_per_slide.hour)) } - (1..intervals).each do |i| - if span > 1 - span -= 1 diff --git a/app/views/tracks/index.html.haml b/app/views/tracks/index.html.haml index 31a9fe97..d17ee766 100644 --- a/app/views/tracks/index.html.haml +++ b/app/views/tracks/index.html.haml @@ -72,6 +72,8 @@ method: :patch, class: 'btn btn-mini btn-success', id: "resubmit_track_request_#{track.id}" - if can? :edit, track = link_to 'Edit', edit_conference_program_track_path(@conference.short_title, track), class: 'btn btn-default' + - if current_user.has_role? :track_organizer, track + = link_to 'Manage', admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-default' .row .col-md-12 diff --git a/app/views/tracks/show.html.haml b/app/views/tracks/show.html.haml index 6014f23e..c81d60ec 100644 --- a/app/views/tracks/show.html.haml +++ b/app/views/tracks/show.html.haml @@ -8,6 +8,8 @@ .btn-group.pull-right - if can? :edit, @track = link_to 'Edit Track request', edit_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-primary' + - if current_user.has_role? :track_organizer, @track + = link_to 'Manage', admin_conference_program_track_path(@conference.short_title, @track), class: 'btn btn-default' .row .col-md-8 %dl.dl-horizontal diff --git a/config/routes.rb b/config/routes.rb index ec55b8a3..0e1cad2e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -40,7 +40,7 @@ Osem::Application.routes.draw do resources :comments, only: [:index] resources :conferences do resource :contact, except: [:index, :new, :create, :show, :destroy] - resources :schedules, only: [:index, :create, :show, :update, :destroy] + resources :schedules, except: [:edit, :update] resources :event_schedules, only: [:create, :update, :destroy] get 'commercials/render_commercial' => 'commercials#render_commercial' resources :commercials, only: [:index, :create, :update, :destroy] @@ -88,6 +88,7 @@ Osem::Application.routes.draw do patch :to_reject patch :reject patch :cancel + patch :update_selected_schedule end end resources :event_types diff --git a/db/migrate/20170809120927_add_track_reference_to_schedule.rb b/db/migrate/20170809120927_add_track_reference_to_schedule.rb new file mode 100644 index 00000000..2c2d7f1c --- /dev/null +++ b/db/migrate/20170809120927_add_track_reference_to_schedule.rb @@ -0,0 +1,5 @@ +class AddTrackReferenceToSchedule < ActiveRecord::Migration + def change + add_reference :schedules, :track, index: true, foreign_key: true + end +end diff --git a/db/migrate/20170814174637_add_selected_schedule_to_tracks.rb b/db/migrate/20170814174637_add_selected_schedule_to_tracks.rb new file mode 100644 index 00000000..05b7d417 --- /dev/null +++ b/db/migrate/20170814174637_add_selected_schedule_to_tracks.rb @@ -0,0 +1,6 @@ +class AddSelectedScheduleToTracks < ActiveRecord::Migration + def change + add_column :tracks, :selected_schedule_id, :integer + add_index :tracks, :selected_schedule_id + end +end diff --git a/db/schema.rb b/db/schema.rb index d9949b1e..82f5923d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -431,9 +431,11 @@ ActiveRecord::Schema.define(version: 20170816203325) do t.integer "program_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.integer "track_id" end add_index "schedules", ["program_id"], name: "index_schedules_on_program_id" + add_index "schedules", ["track_id"], name: "index_schedules_on_track_id" create_table "splashpages", force: :cascade do |t| t.integer "conference_id" @@ -520,24 +522,26 @@ ActiveRecord::Schema.define(version: 20170816203325) do end create_table "tracks", force: :cascade do |t| - t.string "guid", null: false - t.string "name", null: false + t.string "guid", null: false + t.string "name", null: false t.text "description" t.string "color" t.datetime "created_at" t.datetime "updated_at" t.integer "program_id" - t.string "short_name", null: false - t.string "state", default: "new", null: false - t.boolean "cfp_active", null: false + t.string "short_name", null: false + t.string "state", default: "new", null: false + t.boolean "cfp_active", null: false t.integer "submitter_id" t.integer "room_id" t.date "start_date" t.date "end_date" t.text "relevance" + t.integer "selected_schedule_id" end add_index "tracks", ["room_id"], name: "index_tracks_on_room_id" + add_index "tracks", ["selected_schedule_id"], name: "index_tracks_on_selected_schedule_id" add_index "tracks", ["submitter_id"], name: "index_tracks_on_submitter_id" create_table "users", force: :cascade do |t| diff --git a/spec/features/track_organizer_ability_spec.rb b/spec/features/track_organizer_ability_spec.rb index 69b4d3e5..67e0c8de 100644 --- a/spec/features/track_organizer_ability_spec.rb +++ b/spec/features/track_organizer_ability_spec.rb @@ -4,7 +4,7 @@ feature 'Has correct abilities' do let(:organization) { create(:organization) } let(:conference) { create(:full_conference, organization: organization) } - let(:self_organized_track) { create(:track, :self_organized, program: conference.program, state: 'confirmed', cfp_active: true) } + let(:self_organized_track) { create(:track, :self_organized, program: conference.program, state: 'confirmed') } let(:role_track_organizer) { Role.where(name: 'track_organizer', resource: self_organized_track).first_or_create } let(:user_track_organizer) { create(:user, role_ids: [role_track_organizer.id]) } @@ -32,7 +32,7 @@ feature 'Has correct abilities' do expect(page).to have_link('Tracks', href: "/admin/conferences/#{conference.short_title}/program/tracks") expect(page).to_not have_link('Event Types', href: "/admin/conferences/#{conference.short_title}/program/event_types") expect(page).to_not have_link('Difficulty Levels', href: "/admin/conferences/#{conference.short_title}/program/difficulty_levels") - expect(page).to_not have_link('Schedules', href: "/admin/conferences/#{conference.short_title}/schedules") + 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") expect(page).to_not have_link('Registrations', href: "/admin/conferences/#{conference.short_title}/registrations") expect(page).to_not have_link('Registration Period', href: "/admin/conferences/#{conference.short_title}/registration_period") @@ -130,12 +130,16 @@ feature 'Has correct abilities' do expect(current_path).to eq root_path visit admin_conference_schedules_path(conference.short_title) - expect(current_path).to eq root_path + expect(current_path).to eq admin_conference_schedules_path(conference.short_title) create(:schedule, program: conference.program) visit admin_conference_schedule_path(conference.short_title, conference.program.schedules.first) expect(current_path).to eq root_path + self_organized_track_schedule = create(:schedule, program: conference.program, track: self_organized_track) + visit admin_conference_schedule_path(conference.short_title, self_organized_track_schedule) + expect(current_path).to eq admin_conference_schedule_path(conference.short_title, self_organized_track_schedule) + visit admin_conference_program_reports_path(conference.short_title) expect(current_path).to eq admin_conference_program_reports_path(conference.short_title) diff --git a/spec/models/admin_ability_spec.rb b/spec/models/admin_ability_spec.rb index 126668fa..344f63ba 100644 --- a/spec/models/admin_ability_spec.rb +++ b/spec/models/admin_ability_spec.rb @@ -45,7 +45,7 @@ describe 'User with admin role' do let!(:my_event_schedule) { create(:event_schedule, schedule: my_schedule) } let!(:other_event_schedule) { create(:event_schedule, schedule: other_schedule) } - let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program, state: 'confirmed', cfp_active: true) } + let!(:my_self_organized_track) { create(:track, :self_organized, program: my_conference.program, state: 'confirmed') } context 'user #is_admin?' do let(:venue) { my_conference.venue } @@ -460,8 +460,12 @@ describe 'User with admin role' do let(:user) { create(:user, role_ids: [role.id]) } let(:new_track) { build(:track, program: my_conference.program) } let(:new_event) { build(:event, program: my_conference.program) } + let(:new_schedule) { build(:schedule, program: my_conference.program) } + let(:new_track_schedule) { build(:schedule, program: my_conference.program, track: new_track) } let(:my_self_organized_track_event) { create(:event, program: my_conference.program, track: my_self_organized_track) } let(:my_self_organized_track_event_commercial) { create(:commercial, commercialable: my_self_organized_track_event) } + let(:my_self_organized_track_schedule) { create(:schedule, program: my_conference.program, track: my_self_organized_track) } + let(:my_self_organized_track_event_schedule) { create(:event_schedule, event: my_self_organized_track_event, schedule: my_self_organized_track_schedule, room: my_self_organized_track.room) } it{ should_not be_able_to(:new, Conference.new) } it{ should_not be_able_to(:create, Conference.new) } @@ -532,6 +536,11 @@ describe 'User with admin role' do it{ should be_able_to(:manage, my_self_organized_track_event) } it{ should be_able_to(:manage, my_self_organized_track_event_commercial) } + it{ should be_able_to(:update, new_schedule) } + it{ should be_able_to(:new, new_track_schedule) } + it{ should be_able_to(:manage, my_self_organized_track_schedule) } + it{ should be_able_to(:manage, my_self_organized_track_event_schedule) } + it_behaves_like 'user with any role' it_behaves_like 'user with non-organizer role', 'track_organizer' end diff --git a/spec/models/event_schedule_spec.rb b/spec/models/event_schedule_spec.rb index 8e22430b..91db4b64 100644 --- a/spec/models/event_schedule_spec.rb +++ b/spec/models/event_schedule_spec.rb @@ -46,7 +46,7 @@ describe EventSchedule do end end - describe '#room_of_track' do + describe '#same_room_as_track' do before :each do conference = create(:conference) conference.venue = create(:venue) @@ -108,5 +108,39 @@ describe EventSchedule do end end end + + describe '#valid_schedule' do + before :each do + conference.venue = create(:venue) + @room = create(:room, venue: conference.venue) + track = create(:track, :self_organized, program: conference.program, room: @room, state: 'confirmed', name: 'My awesome track') + @event = create(:event, program: conference.program, track: track) + end + + context 'is valid' do + it 'when the event belongs to a self-organized track and is scheduled in one of its track\'s schedules' do + schedule = create(:schedule, program: conference.program, track: @event.track) + event_schedule = build(:event_schedule, event: @event, room: @room, schedule: schedule) + expect(event_schedule.valid?).to eq true + expect(event_schedule.errors[:schedule]).to eq [] + end + + it 'when the event doesn\'t belong to a self-organized track' do + @event.track = nil + @event.save! + event_schedule = build(:event_schedule, event: @event, room: @room) + expect(event_schedule.valid?).to eq true + expect(event_schedule.errors[:schedule]).to eq [] + end + end + + context 'is invalid' do + it 'when the event belongs to a self_organized track but isn\'t scheduled in one of its schedules' do + event_schedule = build(:event_schedule, event: @event, room: @room) + expect(event_schedule.valid?).to eq false + expect(event_schedule.errors[:schedule]).to eq ['must be one of My awesome track track\'s schedules'] + end + end + end end end diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index 3ada61ca..0a84aedd 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -97,10 +97,10 @@ describe Event do end end - describe '#acceptable_track' do + describe '#valid_track' do context 'is valid' do - it 'when the track belong to the same program, is confirmed and is included in the cfp' do - track = create(:track, state: 'confirmed', cfp_active: true, program: conference.program) + it 'when the track belongs to the same program and is confirmed' do + track = create(:track, state: 'confirmed', program: conference.program) event = build(:event, program: conference.program, track: track) expect(event.valid?).to eq true end @@ -108,26 +108,19 @@ describe Event do context 'is invalid' do it 'when the track doesn\'t have the same program' do - track = create(:track, state: 'confirmed', cfp_active: true) + track = create(:track, state: 'confirmed') event = build(:event, program: conference.program, track: track) expect(event.valid?).to eq false expect(event.errors[:track]).to eq ['is invalid'] end it 'when the track is unconfirmed' do - track = create(:track, cfp_active: true, program: conference.program) + track = create(:track, program: conference.program) allow(track).to receive(:confirmed?).and_return(false) event = build(:event, program: conference.program, track: track) expect(event.valid?).to eq false expect(event.errors[:track]).to eq ['is invalid'] end - - it 'when the track isn\'t included in the cfp' do - track = create(:track, state: 'confirmed', cfp_active: false, program: conference.program) - event = build(:event, program: conference.program, track: track) - expect(event.valid?).to eq false - expect(event.errors[:track]).to eq ['is invalid'] - end end end end @@ -382,4 +375,30 @@ describe Event do expect(other_event.week).to eq 48 end end + + describe '#selected_schedule_id' do + before :each do + conference.program.selected_schedule = create(:schedule, program: conference.program) + end + + context 'returns the program\'s selected_schedule_id' do + it 'when it doesn\'t have a track' do + create(:event_schedule, event: event, schedule: conference.program.selected_schedule) + expect(event.send(:selected_schedule_id)).to eq conference.program.selected_schedule_id + end + + it 'when it belongs to a regular track' do + event.track = create(:track, program: conference.program) + expect(event.send(:selected_schedule_id)).to eq conference.program.selected_schedule_id + end + end + + context 'returns the track\'s selected_schedule_id' do + it 'when it belongs to a self-organized track' do + event.track = create(:track, :self_organized, program: conference.program, state: 'confirmed') + event.track.selected_schedule = create(:schedule, program: conference.program, track: event.track) + expect(event.send(:selected_schedule_id)).to eq event.track.selected_schedule_id + end + end + end end diff --git a/spec/models/schedule_spec.rb b/spec/models/schedule_spec.rb index 6d1f7346..2dc1b826 100644 --- a/spec/models/schedule_spec.rb +++ b/spec/models/schedule_spec.rb @@ -4,6 +4,7 @@ describe Schedule do describe 'association' do it { should belong_to(:program) } + it { should belong_to(:track) } it { should have_many(:event_schedules).dependent(:destroy) } it { should have_many(:events).through(:event_schedules) } end diff --git a/spec/models/track_spec.rb b/spec/models/track_spec.rb index f9c53653..d356a2c7 100644 --- a/spec/models/track_spec.rb +++ b/spec/models/track_spec.rb @@ -9,7 +9,9 @@ describe Track do it { is_expected.to belong_to(:program) } it { is_expected.to belong_to(:submitter).class_name('User') } it { is_expected.to belong_to(:room) } + it { is_expected.to belong_to(:selected_schedule).class_name('Schedule') } it { is_expected.to have_many(:events) } + it { is_expected.to have_many(:schedules) } end describe 'validation' do @@ -145,20 +147,20 @@ describe Track do end context 'is valid' do - it 'when the tracks are in different rooms' do + it 'when the tracks are in different rooms at the same time' do other_room = create(:room, venue: @conference.venue) create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: other_room, start_date: Date.current, end_date: Date.current) track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) expect(track.valid?).to eq true end - it 'when it ends before the other tracks' do + it 'when it ends before the other tracks in the same room' do create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current - 1.day, end_date: Date.current - 1.day) expect(track.valid?).to eq true end - it 'when it starts after the other tracks' do + it 'when it starts after the other tracks in the same room' do create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current + 1.day, end_date: Date.current + 1.day) expect(track.valid?).to eq true @@ -166,7 +168,7 @@ describe Track do end context 'is invalid' do - it 'when it starts or ends with another track in the same room' do + it 'when it starts and/or ends with another track in the same room' do create(:track, :self_organized, state: 'confirmed', program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) track = build(:track, :self_organized, program: @conference.program, room: @room, start_date: Date.current, end_date: Date.current) expect(track.valid?).to eq false @@ -264,6 +266,24 @@ describe Track do expect(@program.tracks.cfp_active.include?(@non_cfp_active_track)).to eq false end end + + describe '#self_organized' do + before :each do + @program = create(:program) + track.program = @program + track.save! + self_organized_track.program = @program + self_organized_track.save! + end + + it 'includes self-organized tracks' do + expect(@program.tracks.self_organized.include?(self_organized_track)).to eq true + end + + it 'excludes regular tracks' do + expect(@program.tracks.self_organized.include?(track)).to eq false + end + end end describe '#self_organized?' do @@ -334,7 +354,8 @@ describe Track do self_organized_track.cfp_active = true self_organized_track.save! @a_track_organizer.add_role 'track_organizer', self_organized_track - @an_event_of_the_track = create(:event, program: self_organized_track.program, track: self_organized_track) + @event_of_self_organized_track = create(:event, program: self_organized_track.program, track: self_organized_track, state: 'confirmed') + @schedule_of_self_organized_track = create(:schedule, program: self_organized_track.program, track: self_organized_track) end it 'revokes the role of the track organizer' do @@ -343,11 +364,24 @@ describe Track do expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false end - it 'removes the track from the events that have it set' do - expect(@an_event_of_the_track.track).to eq self_organized_track + it 'destroys the track\'s schedules' do + expect(Schedule.find(@schedule_of_self_organized_track.id)).to eq @schedule_of_self_organized_track self_organized_track.revoke_role_and_cleanup - @an_event_of_the_track.reload - expect(@an_event_of_the_track.track).to eq nil + expect(Schedule.find_by(id: @schedule_of_self_organized_track.id)).to eq nil + end + + it 'removes the track from the events that have it set' do + expect(@event_of_self_organized_track.track).to eq self_organized_track + self_organized_track.revoke_role_and_cleanup + @event_of_self_organized_track.reload + expect(@event_of_self_organized_track.track).to eq nil + end + + it 'sets the state of the track\'s events to new' do + expect(@event_of_self_organized_track.state).to eq 'confirmed' + self_organized_track.revoke_role_and_cleanup + @event_of_self_organized_track.reload + expect(@event_of_self_organized_track.state).to eq 'new' end it 'is executed when the track is canceled' do @@ -355,15 +389,15 @@ describe Track do self_organized_track.save! self_organized_track.cancel expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false - @an_event_of_the_track.reload - expect(@an_event_of_the_track.track).to eq nil + @event_of_self_organized_track.reload + expect(@event_of_self_organized_track.track).to eq nil end it 'is executed when the track is withdrawn' do self_organized_track.withdraw expect(@a_track_organizer.has_role?(:track_organizer, self_organized_track)).to eq false - @an_event_of_the_track.reload - expect(@an_event_of_the_track.track).to eq nil + @event_of_self_organized_track.reload + expect(@event_of_self_organized_track.track).to eq nil end end From 9c4892bfc80ea1b92371cfd4e7c85e5eeadc385b Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 22 Aug 2017 22:22:31 +0530 Subject: [PATCH 191/237] Change room size to capacity --- app/views/admin/rooms/_form.html.haml | 2 +- app/views/admin/rooms/index.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/rooms/_form.html.haml b/app/views/admin/rooms/_form.html.haml index 8e515290..eec272cd 100644 --- a/app/views/admin/rooms/_form.html.haml +++ b/app/views/admin/rooms/_form.html.haml @@ -10,6 +10,6 @@ .col-md-8 = semantic_form_for(@room, url: (@room.new_record? ? admin_conference_venue_rooms_path : admin_conference_venue_room_path(@conference.short_title, @room))) do |f| = f.input :name, input_html: { autofocus: true} - = f.input :size, input_html: {size: 5} + = f.input :size, label: 'Capacity', input_html: {size: 5} %p.text-right = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/admin/rooms/index.html.haml b/app/views/admin/rooms/index.html.haml index 8bf682c8..2d1545f6 100644 --- a/app/views/admin/rooms/index.html.haml +++ b/app/views/admin/rooms/index.html.haml @@ -11,7 +11,7 @@ %table.table.table-hover#rooms %thead %th Name - %th Size + %th Capacity %th Actions %tbody - @rooms.each_with_index do |room, index| From 27fa79a8267916a57215456ce04647df4549c35a Mon Sep 17 00:00:00 2001 From: AEtherC0r3 Date: Thu, 17 Aug 2017 13:36:46 +0300 Subject: [PATCH 192/237] Track related refactoring Add roles as nested routes to track (for the track organizer role) Allow transition from to_accept to to_reject and backwards Split Track#valid_dates validation to many independent ones Show all the confirmed tracks in the conference's splashpage Add comment in admin/Tracks#toggle_cfp_inclusion Rewrite admin/TracksController#accept spec Add feature spec for track requests Change 'In' to 'Room' in Tracks#index Rewrite Track#overlapping Refactor code in ProposalsController Fix typos --- app/controllers/admin/programs_controller.rb | 2 +- app/controllers/admin/roles_controller.rb | 10 +- app/controllers/admin/schedules_controller.rb | 3 +- app/controllers/admin/tracks_controller.rb | 2 +- app/controllers/proposals_controller.rb | 6 +- app/helpers/events_helper.rb | 4 +- app/models/track.rb | 60 ++++----- app/views/admin/roles/index.html.haml | 8 +- app/views/admin/roles/show.html.haml | 3 +- app/views/admin/tracks/index.html.haml | 4 +- .../admin/tracks/toggle_cfp_inclusion.js.erb | 5 + .../conferences/_conference_details.html.haml | 6 +- .../_schedule_splashpage.html.haml | 2 +- app/views/conferences/show.html.haml | 8 +- app/views/tracks/_form.html.haml | 2 +- app/views/tracks/index.html.haml | 21 +-- config/routes.rb | 13 +- .../admin/tracks_controller_spec.rb | 87 ++++++++---- spec/features/tracks_spec.rb | 126 +++++++++++++++--- spec/models/cfp_spec.rb | 4 +- spec/models/track_spec.rb | 47 ++++--- 21 files changed, 279 insertions(+), 144 deletions(-) diff --git a/app/controllers/admin/programs_controller.rb b/app/controllers/admin/programs_controller.rb index fe401078..3d9f66d8 100644 --- a/app/controllers/admin/programs_controller.rb +++ b/app/controllers/admin/programs_controller.rb @@ -30,7 +30,7 @@ module Admin flash.now[:error] = "Updating program failed. #{@program.errors.to_a.join('. ')}." render :new end - format.js { render json: { errors: "The selected schedule couldn't been updated #{@program.errors.to_a.join('. ')}" }, status: 422 } + format.js { render json: { errors: "The selected schedule couldn't be updated #{@program.errors.to_a.join('. ')}" }, status: 422 } end end end diff --git a/app/controllers/admin/roles_controller.rb b/app/controllers/admin/roles_controller.rb index e4b83241..7ddb7953 100644 --- a/app/controllers/admin/roles_controller.rb +++ b/app/controllers/admin/roles_controller.rb @@ -15,7 +15,7 @@ module Admin def show @url = if @track - toggle_user_track_admin_conference_role_path(@conference.short_title, @role.name, @track) + toggle_user_admin_conference_program_track_role_path(@conference.short_title, @track, @role.name) else toggle_user_admin_conference_role_path(@conference.short_title, @role.name) end @@ -24,7 +24,7 @@ module Admin def edit @url = if @track - track_admin_conference_role_path(@conference.short_title, @role.name, @track) + admin_conference_program_track_role_path(@conference.short_title, @track, @role.name) else admin_conference_role_path(@conference.short_title, @role.name) end @@ -36,7 +36,7 @@ module Admin if @role.update_attributes(role_params) url = if @track - track_admin_conference_role_path(@conference.short_title, @role.name, @track) + admin_conference_program_track_role_path(@conference.short_title, @track, @role.name) else admin_conference_role_path(@conference.short_title, @role.name) end @@ -55,7 +55,7 @@ module Admin state = user_params[:state] url = if @track - track_admin_conference_role_path(@conference.short_title, @role.name, @track) + admin_conference_program_track_role_path(@conference.short_title, @track, @role.name) else admin_conference_role_path(@conference.short_title, @role.name) end @@ -108,7 +108,7 @@ module Admin @selection = params[:id] ? params[:id].parameterize.underscore : 'organizer' if @selection == 'track_organizer' - @track = @conference.program.tracks.find_by(short_name: params[:track_name]) + @track = @conference.program.tracks.find_by(short_name: params[:track_id]) @role = Role.find_by(name: @selection, resource: @track) else @role = Role.find_by(name: @selection, resource: @conference) diff --git a/app/controllers/admin/schedules_controller.rb b/app/controllers/admin/schedules_controller.rb index 00ef9a1d..9f6c222b 100644 --- a/app/controllers/admin/schedules_controller.rb +++ b/app/controllers/admin/schedules_controller.rb @@ -43,7 +43,8 @@ module Admin self_organized_tracks_events = @program.tracks.self_organized.confirmed.map do |t| t.events.confirmed end - @unscheduled_events = @program.events.confirmed - @schedule.events - self_organized_tracks_events.flatten.compact + self_organized_tracks_events.flatten.compact! + @unscheduled_events = @program.events.confirmed - @schedule.events - self_organized_tracks_events @dates = @conference.start_date..@conference.end_date @rooms = @conference.venue.rooms if @conference.venue end diff --git a/app/controllers/admin/tracks_controller.rb b/app/controllers/admin/tracks_controller.rb index 03f26448..7352ee35 100644 --- a/app/controllers/admin/tracks_controller.rb +++ b/app/controllers/admin/tracks_controller.rb @@ -108,7 +108,7 @@ module Admin end else respond_to do |format| - format.js { render json: { errors: "The selected schedule couldn't been updated #{@track.errors.to_a.join('. ')}" }, status: 422 } + format.js { render json: { errors: "The selected schedule couldn't be updated #{@track.errors.to_a.join('. ')}" }, status: 422 } end end end diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index b75f648e..66052310 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -50,7 +50,8 @@ class ProposalsController < ApplicationController @event.speakers = [current_user] @event.submitter = current_user - if Track.find_by(id: params[:event][:track_id]).try(:cfp_active) == false + track = Track.find_by(id: params[:event][:track_id]) + if track && !track.cfp_active flash.now[:error] = 'You have selected a track that doesn\'t accept proposals' render action: 'new' return @@ -68,7 +69,8 @@ class ProposalsController < ApplicationController def update @url = conference_program_proposal_path(@conference.short_title, params[:id]) - if Track.find_by(id: params[:event][:track_id]).try(:cfp_active) == false + track = Track.find_by(id: params[:event][:track_id]) + if track && !track.cfp_active flash.now[:error] = 'You have selected a track that doesn\'t accept proposals' render action: 'edit' return diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index dbc609ac..e8f295d5 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -41,9 +41,9 @@ module EventsHelper end def track_selector_input(form) - if @program.tracks.any? + if @program.tracks.confirmed.cfp_active.any? form.input :track_id, as: :select, - collection: @program.tracks.where(state: 'confirmed', cfp_active: true).pluck(:name, :id), + collection: @program.tracks.confirmed.cfp_active.pluck(:name, :id), include_blank: true end end diff --git a/app/models/track.rb b/app/models/track.rb index c3d02950..02d49f8c 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -31,8 +31,9 @@ class Track < ActiveRecord::Base validates :room, presence: true, if: :self_organized_and_accepted_or_confirmed? validates :relevance, presence: true, if: :self_organized? validates :description, presence: true, if: :self_organized? - validate :valid_dates - validate :valid_room, if: :self_organized_and_accepted_or_confirmed? + validate :dates_within_conference_dates + validate :start_date_before_end_date + validate :valid_room validate :overlapping before_validation :capitalize_color @@ -56,7 +57,7 @@ class Track < ActiveRecord::Base transitions to: :new, from: [:rejected, :withdrawn, :canceled] end event :to_accept do - transitions to: :to_accept, from: [:new] + transitions to: :to_accept, from: [:new, :to_reject] end event :accept do transitions to: :accepted, from: [:new, :to_accept], on_transition: :create_organizer_role @@ -65,7 +66,7 @@ class Track < ActiveRecord::Base transitions to: :confirmed, from: [:accepted], on_transition: :assign_role_to_submitter end event :to_reject do - transitions to: :to_reject, from: [:new] + transitions to: :to_reject, from: [:new, :to_accept] end event :reject do transitions to: :rejected, from: [:new, :to_reject] @@ -194,46 +195,41 @@ class Track < ActiveRecord::Base Role.where(name: 'track_organizer', resource: self).first_or_create(description: 'For the organizers of the Track') end - def valid_dates - if start_date && program && program.conference && program.conference.start_date && (start_date < program.conference.start_date) - errors.add(:start_date, "can't be before the conference start date (#{program.conference.start_date})") - end + ## + # Verify that the track's dates are between the conference's dates + # + def dates_within_conference_dates + return unless start_date && end_date && program.try(:conference).try(:start_date) && program.try(:conference).try(:end_date) + errors.add(:start_date, "can't be outside of the conference's dates (#{program.conference.start_date}-#{program.conference.end_date})") unless (program.conference.start_date..program.conference.end_date).cover?(start_date) + errors.add(:end_date, "can't be outside of the conference's dates (#{program.conference.start_date}-#{program.conference.end_date})") unless (program.conference.start_date..program.conference.end_date).cover?(end_date) + end - if end_date && program && program.conference && program.conference.start_date && (end_date < program.conference.start_date) - errors.add(:end_date, "can't be before the conference start date (#{program.conference.start_date})") - end - - if start_date && program && program.conference && program.conference.end_date && (start_date > program.conference.end_date) - errors.add(:start_date, "can't be after the conference end date (#{program.conference.end_date})") - end - - if end_date && program && program.conference && program.conference.end_date && (end_date > program.conference.end_date) - errors.add(:end_date, "can't be after the conference end date (#{program.conference.end_date})") - end - - if start_date && end_date && (start_date > end_date) - errors.add(:start_date, 'can\'t be after the end date') - end + ## + # Verify that the start date isn't after the end date + # + def start_date_before_end_date + return unless start_date && end_date + errors.add(:start_date, 'can\'t be after the end date') if start_date > end_date end ## # Verify that the room is a room of the conference + # def valid_room - if room && room.venue && room.venue.conference && program && program.conference && (program.conference != room.venue.conference) - errors.add(:room, "must be a room of #{program.conference.venue.name}") - end + return unless room.try(:venue).try(:conference) && program.try(:conference) + errors.add(:room, "must be a room of #{program.conference.venue.name}") unless room.venue.conference == program.conference end ## # Check that there is no other track in the same room with overlapping dates + # def overlapping return unless start_date && end_date && room && program.try(:tracks) - (program.tracks.accepted + program.tracks.confirmed - [self]).each do |other_track| - if other_track.room == room && - other_track.start_date && other_track.end_date && - (other_track.start_date <= start_date && other_track.end_date >= start_date || - other_track.start_date <= end_date && other_track.end_date >= end_date || - start_date <= other_track.start_date && other_track.end_date <= end_date) + (program.tracks.accepted + program.tracks.confirmed - [self]).each do |existing_track| + next unless existing_track.room == room && existing_track.start_date && existing_track.end_date + if start_date >= existing_track.start_date && start_date <= existing_track.end_date || + end_date >= existing_track.start_date && end_date <= existing_track.end_date || + start_date <= existing_track.start_date && end_date >= existing_track.end_date errors.add(:track, 'has overlapping dates with a confirmed or accepted track in the same room') break end diff --git a/app/views/admin/roles/index.html.haml b/app/views/admin/roles/index.html.haml index 4a100025..4990673e 100644 --- a/app/views/admin/roles/index.html.haml +++ b/app/views/admin/roles/index.html.haml @@ -27,15 +27,17 @@ = role.users.pluck(:name).first(5).join ', ' - if role.users.count > 5 - if role.resource_type == 'Track' - = link_to '...', track_admin_conference_role_path(@conference.short_title, role.name, role.resource) + = link_to '...', admin_conference_program_track_role_path(@conference.short_title, role.resource, role.name) - else = link_to '...', admin_conference_role_path(@conference.short_title, role.name) %td .btn-group - if role.resource_type == 'Track' - = link_to 'Users', track_admin_conference_role_path(@conference.short_title, role.name, role.resource), class: 'btn btn-success' + = link_to 'Users', admin_conference_program_track_role_path(@conference.short_title, role.resource, role.name), + class: 'btn btn-success' - if can? :edit, role - = link_to 'Edit', track_edit_admin_conference_role_path(@conference.short_title, role.name, role.resource), class: 'btn btn-primary' + = link_to 'Edit', edit_admin_conference_program_track_role_path(@conference.short_title, role.resource, role.name), + class: 'btn btn-primary' - else = link_to 'Users', admin_conference_role_path(@conference.short_title, role.name), class: 'btn btn-success' - if can? :edit, role diff --git a/app/views/admin/roles/show.html.haml b/app/views/admin/roles/show.html.haml index ee249975..b264bc5f 100644 --- a/app/views/admin/roles/show.html.haml +++ b/app/views/admin/roles/show.html.haml @@ -7,7 +7,8 @@ = @role.name.titleize - if can? :edit, @role - if @track - = link_to 'Edit', track_edit_admin_conference_role_path(@conference.short_title, @role.name, @track), class: 'btn btn-primary pull-right' + = link_to 'Edit', edit_admin_conference_program_track_role_path(@conference.short_title, @track, @role.name), + class: 'btn btn-primary pull-right' - else = link_to 'Edit', edit_admin_conference_role_path(@conference.short_title, @role.name), class: 'btn btn-primary pull-right' .text-muted diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 48c0d1b3..6ac42003 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -24,7 +24,7 @@ %tr %td = track.id - %td{style: "padding: 15px 0px 0px 10px;"} + %td{ style: 'padding: 15px 0px 0px 10px;' } = link_to admin_conference_program_track_path(@conference.short_title, track), class: 'btn' do %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} = track.name @@ -60,7 +60,7 @@ - else = track.state.humanize %td - .btn-group{role: "group"} + .btn-group{ role: 'group' } - if can? :edit, track = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-primary' - special_style = true diff --git a/app/views/admin/tracks/toggle_cfp_inclusion.js.erb b/app/views/admin/tracks/toggle_cfp_inclusion.js.erb index 6ee83003..84ddd69a 100644 --- a/app/views/admin/tracks/toggle_cfp_inclusion.js.erb +++ b/app/views/admin/tracks/toggle_cfp_inclusion.js.erb @@ -5,4 +5,9 @@ track_cfp_td = $('#cfp_switch_' + track_id); track_cfp_value = <%= @track.cfp_active %>; track_cfp_td.attr('data-order', track_cfp_value); + +/* +* The updated data-order attribute isn't taken into account +* until we invalidate the cell +*/ $('#tracks').DataTable().cell(track_cfp_td).invalidate(); diff --git a/app/views/conferences/_conference_details.html.haml b/app/views/conferences/_conference_details.html.haml index f4ec7101..ebf80ef6 100644 --- a/app/views/conferences/_conference_details.html.haml +++ b/app/views/conferences/_conference_details.html.haml @@ -30,10 +30,10 @@ = link_to "Register", new_conference_conference_registration_path(conference.short_title), class: "btn btn-default", disabled: cannot?(:new, Registration.new(conference_id: conference.id)) - if cannot?(:new, Registration.new(conference_id: conference.id)) && conference.registration_limit_exceeded? Sorry, no places left - - if !current_user.nil? && current_user.tracks.where(program: conference.program).length > 0 - = link_to "My Track Requests", conference_program_tracks_path(conference.short_title), class: 'btn btn-default' + - if current_user && current_user.tracks.where(program: conference.program).length > 0 + = link_to 'My Track Requests', conference_program_tracks_path(conference.short_title), class: 'btn btn-default' - elsif can? :new, conference.program.tracks.new - = link_to "Submit Track Request", new_conference_program_track_path(conference.short_title), class: 'btn btn-default' + = link_to 'Submit Track Request', new_conference_program_track_path(conference.short_title), class: 'btn btn-default' - if !current_user.nil? && current_user.proposal_count(conference) > 0 = link_to "My Proposals", conference_program_proposals_path(conference.short_title), class: 'btn btn-default' - elsif can? :new, conference.program.events.new diff --git a/app/views/conferences/_schedule_splashpage.html.haml b/app/views/conferences/_schedule_splashpage.html.haml index defd3e4d..790582cb 100644 --- a/app/views/conferences/_schedule_splashpage.html.haml +++ b/app/views/conferences/_schedule_splashpage.html.haml @@ -10,7 +10,7 @@ - if @conference.splashpage and @conference.program.tracks.any? and @conference.splashpage.include_tracks See rock-star speakers cover the topics of - if @conference.splashpage and @conference.splashpage.include_tracks - - @conference.program.tracks.confirmed.cfp_active.each_slice(3) do |slice| + - @conference.program.tracks.confirmed.each_slice(3) do |slice| .row.row-centered - slice.each do |track| .col-md-4.col-sm-4.col-centered.col-top.track diff --git a/app/views/conferences/show.html.haml b/app/views/conferences/show.html.haml index afda1516..f94b8ee4 100644 --- a/app/views/conferences/show.html.haml +++ b/app/views/conferences/show.html.haml @@ -45,14 +45,14 @@ %section#program = render 'schedule_splashpage' - - if @conference.program.cfps.for_tracks.try(:open?) && @conference.splashpage.include_cfp - %section#callfortracks - = render 'call_for_tracks' - - if @conference.program.cfp_open? and @conference.splashpage.include_cfp %section#callforpapers = render 'call_for_paper' + - if @conference.program.cfps.for_tracks.try(:open?) && @conference.splashpage.include_cfp + %section#callfortracks + = render 'call_for_tracks' + - if @conference.venue and @conference.splashpage.include_venue %section#venue = render 'venue' diff --git a/app/views/tracks/_form.html.haml b/app/views/tracks/_form.html.haml index ab693dc5..42832e80 100644 --- a/app/views/tracks/_form.html.haml +++ b/app/views/tracks/_form.html.haml @@ -16,5 +16,5 @@ = f.input :start_date, as: :string, input_html: { id: 'registration-period-start-datepicker', start_date: @conference.start_date, end_date: @conference.end_date, readonly: 'readonly' } = f.input :end_date, as: :string, input_html: { id: 'registration-period-end-datepicker', readonly: 'readonly' } = f.input :description, input_html: {rows: 2, data: { provide: 'markdown-editable' } }, required: true, hint: "This will be public #{markdown_hint}".html_safe - = f.input :relevance, input_html: {rows: 5, data: { provide: 'markdown-editable' } }, required: true, hint: "Please explain here how this track relates to the conference, how you are related to it's content and why we should accept it. #{markdown_hint}".html_safe + = f.input :relevance, input_html: {rows: 5, data: { provide: 'markdown-editable' } }, required: true, hint: "Please explain here how this track relates to the conference, how you are related to its content and why we should accept it. #{markdown_hint}".html_safe = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/tracks/index.html.haml b/app/views/tracks/index.html.haml index d17ee766..b20a3ca9 100644 --- a/app/views/tracks/index.html.haml +++ b/app/views/tracks/index.html.haml @@ -19,7 +19,7 @@ If you submit a track request, the conference organizers will review it and either accept or reject it. %br If your track request is accepted, the conference organizers expect you to confirm that you will be able to hold it. - Then you will gain the Track organizer role. + Then you will be assigned the Track organizer role. %br If your track request is rejected, you can either live with that or adapt it and resubmit it for review again. %br @@ -29,6 +29,13 @@ .row .col-md-12 %table.table.table-striped#tracks + %th + %th + %th + %th From + %th To + %th Room + %th - @tracks.each do |track| %tr %td{style: "padding:15px 0px 0px 8px;"} @@ -47,17 +54,11 @@ %td = markdown(truncate(track.description)) %td - - if track.start_date - From: - = track.start_date.strftime('%A, %B %-d. %Y') + = track.start_date.strftime('%A, %B %-d. %Y') if track.start_date %td - - if track.end_date - To: - = track.end_date.strftime('%A, %B %-d. %Y') + = track.end_date.strftime('%A, %B %-d. %Y') if track.end_date %td - - if track.room - In: - = track.room.name + = track.try(:room).try(:name) %td .pull-right - if track.transition_possible? :confirm diff --git a/config/routes.rb b/config/routes.rb index 0e1cad2e..0d7e7aec 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -90,6 +90,11 @@ Osem::Application.routes.draw do patch :cancel patch :update_selected_schedule end + resources :roles, only: [:show, :edit, :update] do + member do + post :toggle_user + end + end end resources :event_types resources :difficulty_levels @@ -118,15 +123,9 @@ Osem::Application.routes.draw do resources :campaigns, except: [:show] resources :emails, only: [:show, :update, :index] resources :physical_ticket, only: [:index] - resources :roles, only: [:edit] - resources :roles, except: [ :new, :create, :edit ] do + resources :roles, except: [:new, :create] do member do post :toggle_user - get ':track_name' => 'roles#show', as: 'track' - get ':track_name/edit' => 'roles#edit', as: 'track_edit' - patch ':track_name' => 'roles#update' - put ':track_name' => 'roles#update' - post ':track_name/toggle_user' => 'roles#toggle_user', as: 'toggle_user_track' end end diff --git a/spec/controllers/admin/tracks_controller_spec.rb b/spec/controllers/admin/tracks_controller_spec.rb index 795906aa..03511ce1 100644 --- a/spec/controllers/admin/tracks_controller_spec.rb +++ b/spec/controllers/admin/tracks_controller_spec.rb @@ -3,9 +3,11 @@ require 'spec_helper' describe Admin::TracksController do let(:admin) { create(:admin) } - let(:conference) { create(:conference) } + let(:conference) { create(:conference, start_date: Date.current - 1.day) } + let(:venue) { create(:venue, conference: conference) } + let(:room) { create(:room, venue: venue) } let!(:track) { create(:track, program: conference.program, color: '#800080') } - let!(:self_organized_track) { create(:track, :self_organized, program: conference.program, name: 'My awesome track') } + let!(:self_organized_track) { create(:track, :self_organized, program: conference.program, name: 'My awesome track', start_date: Date.current, end_date: Date.current, room: room) } before :each do sign_in(admin) @@ -81,7 +83,7 @@ describe Admin::TracksController do expect(Track.find(assigns(:track).id)).to be_a Track end - it 'the new tracks has the correct attributes' do + it 'the new track has the correct attributes' do expect(assigns(:track).state).to eq 'confirmed' expect(assigns(:track).cfp_active).to eq true end @@ -358,20 +360,13 @@ describe Admin::TracksController do end describe 'PATCH #accept' do - shared_examples 'fails to accept' do |start_date, end_date, room| + shared_examples 'fails to accept' do before :each do - self_organized_track.start_date = start_date ? Date.today : nil - self_organized_track.end_date = end_date ? Date.today : nil - if room - conference.venue = create(:venue) - self_organized_track.room = create(:room, venue: conference.venue) - else - self_organized_track.room = nil - end - self_organized_track.save! - patch :accept, conference_id: conference.short_title, id: self_organized_track.short_name - self_organized_track.reload + end + + it 'assigns the correct track' do + expect(assigns(:track)).to eq self_organized_track end it 'redirects to Tracks#edit' do @@ -385,12 +380,6 @@ describe Admin::TracksController do context 'has start_date, end_date and room' do before :each do - self_organized_track.start_date = Date.today - self_organized_track.end_date = Date.today - conference.venue = create(:venue) - self_organized_track.room = create(:room, venue: conference.venue) - self_organized_track.save! - patch :accept, conference_id: conference.short_title, id: self_organized_track.short_name self_organized_track.reload end @@ -409,31 +398,71 @@ describe Admin::TracksController do end context 'has start_date and end_date' do - it_behaves_like 'fails to accept', true, true, false + before :each do + self_organized_track.room = nil + self_organized_track.save! + end + + it_behaves_like 'fails to accept' end context 'has start_date and room' do - it_behaves_like 'fails to accept', true, false, true + before :each do + self_organized_track.end_date = nil + self_organized_track.save! + end + + it_behaves_like 'fails to accept' end context 'has start_date' do - it_behaves_like 'fails to accept', true, false, false + before :each do + self_organized_track.end_date = nil + self_organized_track.room = nil + self_organized_track.save! + end + + it_behaves_like 'fails to accept' end context 'has end_date and room' do - it_behaves_like 'fails to accept', false, true, true + before :each do + self_organized_track.start_date = nil + self_organized_track.save! + end + + it_behaves_like 'fails to accept' end context 'has end_date' do - it_behaves_like 'fails to accept', false, true, false + before :each do + self_organized_track.start_date = nil + self_organized_track.room = nil + self_organized_track.save! + end + + it_behaves_like 'fails to accept' end context 'has room' do - it_behaves_like 'fails to accept', false, false, true + before :each do + self_organized_track.start_date = nil + self_organized_track.end_date = nil + self_organized_track.save! + end + + it_behaves_like 'fails to accept' end - context 'has non of start_date, end_date, room' do - it_behaves_like 'fails to accept', false, false, false + context 'has none of start_date, end_date, room' do + before :each do + self_organized_track.start_date = nil + self_organized_track.end_date = nil + self_organized_track.room = nil + self_organized_track.save! + end + + it_behaves_like 'fails to accept' end end diff --git a/spec/features/tracks_spec.rb b/spec/features/tracks_spec.rb index 91e90ee9..0819c650 100644 --- a/spec/features/tracks_spec.rb +++ b/spec/features/tracks_spec.rb @@ -4,26 +4,29 @@ feature Track do let!(:conference) { create(:conference) } let!(:organizer_role) { Role.find_by(name: 'organizer', resource: conference) } let!(:organizer) { create(:user, role_ids: [organizer_role.id]) } + let(:user) { create(:user) } - shared_examples 'tracks' do + shared_examples 'admin tracks' do scenario 'adds a track', feature: true, js: true do sign_in organizer - visit admin_conference_program_tracks_path(conference_id: conference.short_title) - click_link 'New Track' + expected = expect do + visit admin_conference_program_tracks_path(conference_id: conference.short_title) + click_link 'New Track' - fill_in 'track_name', with: 'Distribution' - fill_in 'track_short_name', with: 'Distribution' - page.find('#track_color').set('#B94D4D') - fill_in 'track_description', with: 'Events about our Linux distribution' - click_button 'Create Track' + fill_in 'track_name', with: 'Distribution' + fill_in 'track_short_name', with: 'Distribution' + page.find('#track_color').set('#B94D4D') + fill_in 'track_description', with: 'Events about our Linux distribution' + click_button 'Create Track' + end + expected.to change { Track.count }.by 1 expect(flash).to eq('Track successfully created.') within('table#tracks') do expect(page.has_content?('Distribution')).to be true expect(page.has_content?('Events about our Linux')).to be true - expect(page.assert_selector('tr', count: 2)).to be true end end @@ -31,15 +34,17 @@ feature Track do track = create(:track, program_id: conference.program.id) sign_in organizer - visit admin_conference_program_tracks_path(conference_id: conference.short_title) + expected = expect do + visit admin_conference_program_tracks_path(conference_id: conference.short_title) - click_link 'Delete' + click_link 'Delete' + end + expected.to change { Track.count }.by(-1) expect(flash).to eq('Track successfully deleted.') within('table#tracks') do expect(page.has_content?(track.name)).to be false expect(page.has_content?(track.description)).to be false - expect(page.has_content?('No data available in table')).to eq true end end @@ -47,25 +52,104 @@ feature Track do create(:track, program_id: conference.program.id) sign_in organizer - visit admin_conference_program_tracks_path(conference_id: conference.short_title) - click_link 'Edit' + expected = expect do + visit admin_conference_program_tracks_path(conference_id: conference.short_title) + click_link 'Edit' - fill_in 'track_name', with: 'Distribution' - fill_in 'track_short_name', with: 'Distribution' - page.find('#track_color').set('#B94D4D') - fill_in 'track_description', with: 'Events about our Linux distribution' - click_button 'Update Track' + fill_in 'track_name', with: 'Distribution' + fill_in 'track_short_name', with: 'Distribution' + page.find('#track_color').set('#B94D4D') + fill_in 'track_description', with: 'Events about our Linux distribution' + click_button 'Update Track' + end + expected.to_not(change { Track.count }) expect(flash).to eq('Track successfully updated.') within('table#tracks') do expect(page.has_content?('Distribution')).to be true expect(page.has_content?('Events about our Linux')).to be true - expect(page.assert_selector('tr', count: 2)).to be true + end + end + end + + shared_examples 'non admin tracks' do + scenario 'adds a track', feature: true, js: true do + + sign_in user + + expected = expect do + visit conference_program_tracks_path(conference_id: conference.short_title) + click_link 'New Track request' + + fill_in 'track_name', with: 'Distribution' + fill_in 'track_short_name', with: 'Distribution' + page.find('#track_color').set('#B94D4D') + fill_in 'track_description', with: 'Events about our Linux distribution' + fill_in 'track_relevance', with: 'Maintainer of super awesome distribution' + click_button 'Create Track' + end + + expected.to change { Track.count }.by 1 + expect(flash).to eq('Track request successfully created.') + within('table#tracks') do + expect(page.has_content?('Distribution')).to eq true + expect(page.has_content?('Events about our Linux dist...')).to eq true + end + end + + scenario 'withdraws a track', feature: true, js: true do + track = create(:track, :self_organized, program_id: conference.program.id, submitter: user) + sign_in user + + expected = expect do + visit conference_program_tracks_path(conference_id: conference.short_title) + + accept_confirm do + click_link 'Withdraw' + end + end + + expected.to_not(change { Track.count }) + expect(flash).to eq("Track #{track.name} withdrawn.") + within('table#tracks') do + expect(page.has_content?(track.name)).to eq true + expect(page.has_link?('Re-Submit')).to eq true + end + end + + scenario 'updates a track', feature: true, js: true do + create(:track, :self_organized, program_id: conference.program.id, submitter: user) + sign_in user + + expected = expect do + visit conference_program_tracks_path(conference_id: conference.short_title) + click_link 'Edit' + + fill_in 'track_name', with: 'Distribution' + fill_in 'track_short_name', with: 'Distribution' + page.find('#track_color').set('#B94D4D') + fill_in 'track_description', with: 'Events about our Linux distribution' + click_button 'Update Track' + end + + expected.to_not(change { Track.count }) + expect(flash).to eq('Track request successfully updated.') + within('table#tracks') do + expect(page.has_content?('Distribution')).to eq true + expect(page.has_content?('Events about our Linux dist...')).to eq true end end end describe 'organizer' do - it_behaves_like 'tracks' + it_behaves_like 'admin tracks' + end + + describe 'signed in user' do + before :each do + create(:cfp, cfp_type: 'tracks', program: conference.program) + end + + it_behaves_like 'non admin tracks' end end diff --git a/spec/models/cfp_spec.rb b/spec/models/cfp_spec.rb index 95607491..6c437d35 100644 --- a/spec/models/cfp_spec.rb +++ b/spec/models/cfp_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Cfp do subject { create(:cfp) } let!(:conference) { create(:conference, end_date: Date.today) } - let!(:cfp) { create(:cfp, start_date: Date.today - 2, end_date: Date.today - 1, program_id: conference.program.id) } + let!(:cfp) { create(:cfp, cfp_type: 'events', start_date: Date.today - 2, end_date: Date.today - 1, program_id: conference.program.id) } describe 'validations' do it { is_expected.to validate_presence_of(:cfp_type) } @@ -18,7 +18,7 @@ describe Cfp do end it 'returns nil when the cfp for events doesn\'t exist' do - conference.program.cfp.destroy + cfp.destroy! expect(conference.program.cfps.for_events).to eq nil end end diff --git a/spec/models/track_spec.rb b/spec/models/track_spec.rb index d356a2c7..8f53c732 100644 --- a/spec/models/track_spec.rb +++ b/spec/models/track_spec.rb @@ -68,14 +68,14 @@ describe Track do it { is_expected.to_not validate_presence_of(:description) } end - describe '#valid_dates' do + describe '#dates_within_conference_dates' do before :each do @conference = create(:conference, start_date: 1.day.ago, end_date: 2.days.from_now) end context 'is valid' do - it 'when the track\'s start date is before it\'s end date and between the conference start/end dates' do - track = build(:track, start_date: Date.today, end_date: Date.tomorrow, program: @conference.program) + it 'when the track\'s dates are between the conference\'s dates' do + track = build(:track, start_date: @conference.start_date, end_date: @conference.end_date, program: @conference.program) expect(track.valid?).to eq true end end @@ -84,27 +84,42 @@ describe Track do it 'when the track\'s start date is before the conference\'s start date' do track = build(:track, start_date: 2.days.ago, end_date: Date.tomorrow, program: @conference.program) expect(track.valid?).to eq false - expect(track.errors[:start_date]).to eq ["can't be before the conference start date (#{1.day.ago.to_date})"] - end - - it 'when the track\'s end date is before the conference\'s start date' do - track = build(:track, start_date: 3.days.ago, end_date: 2.days.ago, program: @conference.program) - expect(track.valid?).to eq false - expect(track.errors[:end_date]).to eq ["can't be before the conference start date (#{1.day.ago.to_date})"] + expect(track.errors[:start_date]).to eq ["can't be outside of the conference's dates (#{1.day.ago.to_date}-#{2.days.from_now.to_date})"] end it 'when the track\'s start date is after the conference\'s end date' do track = build(:track, start_date: 3.days.from_now, end_date: 4.days.from_now, program: @conference.program) expect(track.valid?).to eq false - expect(track.errors[:start_date]).to eq ["can't be after the conference end date (#{2.days.from_now.to_date})"] + expect(track.errors[:start_date]).to eq ["can't be outside of the conference's dates (#{1.day.ago.to_date}-#{2.days.from_now.to_date})"] + end + + it 'when the track\'s end date is before the conference\'s start date' do + track = build(:track, start_date: 3.days.ago, end_date: 2.days.ago, program: @conference.program) + expect(track.valid?).to eq false + expect(track.errors[:end_date]).to eq ["can't be outside of the conference's dates (#{1.day.ago.to_date}-#{2.days.from_now.to_date})"] end it 'when the track\'s end date is after the conference\'s end date' do track = build(:track, start_date: Date.today, end_date: 3.days.from_now, program: @conference.program) expect(track.valid?).to eq false - expect(track.errors[:end_date]).to eq ["can't be after the conference end date (#{2.days.from_now.to_date})"] + expect(track.errors[:end_date]).to eq ["can't be outside of the conference's dates (#{1.day.ago.to_date}-#{2.days.from_now.to_date})"] end + end + end + describe '#start_date_before_end_date' do + before :each do + @conference = create(:conference, start_date: 1.day.ago, end_date: 2.days.from_now) + end + + context 'is valid' do + it 'when the track\'s start date is before its end date' do + track = build(:track, start_date: Date.today, end_date: Date.tomorrow, program: @conference.program) + expect(track.valid?).to eq true + end + end + + context 'is invalid' do it 'when the track\'s start date is after it\'s end date' do track = build(:track, start_date: 1.day.from_now, end_date: 1.day.ago) expect(track.valid?).to eq false @@ -235,7 +250,7 @@ describe Track do end context 'includes' do - it 'when track is confirmed' do + it 'tracks with state \'confirmed\'' do confirmed_track = create(:track, state: 'confirmed', program: @program) expect(@program.tracks.confirmed.include?(confirmed_track)).to eq true end @@ -243,7 +258,7 @@ describe Track do context 'excludes' do %w[new to_accept accepted to_reject rejected canceled withdrawn].each do |state| - it "when track is #{state.humanize}" do + it "tracks with state '#{state}'" do unconfirmed_track = create(:track, state: state, program: @program) expect(@program.tracks.confirmed.include?(unconfirmed_track)).to eq false end @@ -310,10 +325,10 @@ describe Track do transitions = [:restart, :to_accept, :accept, :confirm, :to_reject, :reject, :cancel, :withdraw] states_transitions = { new: { restart: false, to_accept: true, accept: true, confirm: false, to_reject: true, reject: true, cancel: false, withdraw: true }, - to_accept: { restart: false, to_accept: false, accept: true, confirm: false, to_reject: false, reject: false, cancel: true, withdraw: true }, + to_accept: { restart: false, to_accept: false, accept: true, confirm: false, to_reject: true, reject: false, cancel: true, withdraw: true }, accepted: { restart: false, to_accept: false, accept: false, confirm: true, to_reject: false, reject: false, cancel: true, withdraw: true }, confirmed: { restart: false, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: true, withdraw: true }, - to_reject: { restart: false, to_accept: false, accept: false, confirm: false, to_reject: false, reject: true, cancel: true, withdraw: true }, + to_reject: { restart: false, to_accept: true, accept: false, confirm: false, to_reject: false, reject: true, cancel: true, withdraw: true }, rejected: { restart: true, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: false, withdraw: false }, canceled: { restart: true, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: false, withdraw: false }, withdrawn: { restart: true, to_accept: false, accept: false, confirm: false, to_reject: false, reject: false, cancel: false, withdraw: false } } From ac87656f463d4e825387d851e7604af430733f71 Mon Sep 17 00:00:00 2001 From: rahul Date: Sat, 26 Aug 2017 00:12:18 +0530 Subject: [PATCH 193/237] Add hint to responsibles --- app/helpers/application_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e4a0e230..6174500e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -147,7 +147,8 @@ module ApplicationHelper users = User.active.pluck(:id, :name, :username, :email).map { |user| [user[0], user[1].blank? ? user[2] : user[1], user[2], user[3]] }.sort_by { |user| user[1].downcase } form.input :responsibles, as: :select, collection: options_for_select(users.map {|user| ["#{user[1]} (#{user[2]}) #{user[3]}", user[0]]}, @booth.responsibles.map(&:id)), - include_blank: false, label: 'Responsibles', input_html: { class: 'select-help-toggle', multiple: 'true' } + include_blank: false, label: 'Responsibles', input_html: { class: 'select-help-toggle', multiple: 'true' }, + hint: 'The people responsible for the booth. You can only select existing users.' end def event_types(conference) From b7901e54d664998def94cfcbfa4a0834c68ec025 Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 28 Aug 2017 21:44:39 +0530 Subject: [PATCH 194/237] Fix layout for booths and tracks --- app/views/admin/booths/index.html.haml | 7 ++++--- app/views/admin/tracks/index.html.haml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/admin/booths/index.html.haml b/app/views/admin/booths/index.html.haml index fc3f3ba3..9eef8f96 100644 --- a/app/views/admin/booths/index.html.haml +++ b/app/views/admin/booths/index.html.haml @@ -4,9 +4,6 @@ %h1 Booths = "(#{@booths.length})" if @booths.any? - .pull-right - - if can? :create, Booth - = link_to 'Add Booth', new_admin_conference_booth_path(@conference.short_title), class: 'button btn btn-primary' %p.text-muted All the booth requests @@ -74,3 +71,7 @@ %td = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id), class: 'btn btn-primary' +.row + .col-md-12.text-right + - if can? :create, Booth + = link_to 'New Booth', new_admin_conference_booth_path(@conference.short_title), class: 'button btn btn-primary' diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 6ac42003..95eafcb3 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -78,4 +78,4 @@ style: ('border-top-left-radius: 0; border-bottom-left-radius: 0;' if special_style), params: { 'schedule[track_id]' => track.id } .row .col-md-12.text-right - = link_to 'New Track', new_admin_conference_program_track_path(@conference.short_title), class: 'btn btn-success' + = link_to 'New Track', new_admin_conference_program_track_path(@conference.short_title), class: 'btn btn-primary' From 89509519eff3c791ba81dea92b53ddc4dc43a283 Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 28 Aug 2017 22:31:24 +0530 Subject: [PATCH 195/237] Replace flash with flash.now --- app/controllers/admin/booths_controller.rb | 4 ++-- app/controllers/admin/events_controller.rb | 2 +- app/controllers/booths_controller.rb | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/admin/booths_controller.rb b/app/controllers/admin/booths_controller.rb index a65de090..102eb10b 100644 --- a/app/controllers/admin/booths_controller.rb +++ b/app/controllers/admin/booths_controller.rb @@ -22,7 +22,7 @@ module Admin redirect_to admin_conference_booths_path, notice: 'Booth successfully created.' else - flash[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}." render :new end end @@ -40,7 +40,7 @@ module Admin redirect_to admin_conference_booths_path, notice: "Successfully updated booth for #{@booth.title}." else - flash[:error] = "An error prohibited the Booth for #{@booth.title} "\ + flash.now[:error] = "An error prohibited the Booth for #{@booth.title} "\ "#{@booth.errors.full_messages.join('. ')}." render :edit end diff --git a/app/controllers/admin/events_controller.rb b/app/controllers/admin/events_controller.rb index bb23dac9..accfb281 100644 --- a/app/controllers/admin/events_controller.rb +++ b/app/controllers/admin/events_controller.rb @@ -102,7 +102,7 @@ module Admin ahoy.track 'Event submission', title: 'New submission' redirect_to admin_conference_program_events_path(@conference.short_title), notice: 'Event was successfully submitted.' else - flash[:error] = "Could not submit proposal: #{@event.errors.full_messages.join(', ')}" + flash.now[:error] = "Could not submit proposal: #{@event.errors.full_messages.join(', ')}" render action: 'new' end end diff --git a/app/controllers/booths_controller.rb b/app/controllers/booths_controller.rb index 99fde3bc..f0457b88 100644 --- a/app/controllers/booths_controller.rb +++ b/app/controllers/booths_controller.rb @@ -23,7 +23,7 @@ class BoothsController < ApplicationController redirect_to conference_booths_path, notice: 'Booth successfully created.' else - flash[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}." render :new end end @@ -40,7 +40,7 @@ class BoothsController < ApplicationController redirect_to conference_booths_path, notice: 'Booth successfully updated!' else - flash[:error] = "Booth could not be updated. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Booth could not be updated. #{@booth.errors.full_messages.to_sentence}." end end @@ -56,7 +56,7 @@ class BoothsController < ApplicationController redirect_to conference_booths_path, notice: 'Booth successfully withdrawn' else - flash[:error] = "Booth could not be withdrawn. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Booth could not be withdrawn. #{@booth.errors.full_messages.to_sentence}." end end @@ -70,7 +70,7 @@ class BoothsController < ApplicationController redirect_to conference_booths_path, notice: 'Booth successfully confirmed' else - flash[:error] = "Booth could not be confirmed. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Booth could not be confirmed. #{@booth.errors.full_messages.to_sentence}." end end @@ -84,7 +84,7 @@ class BoothsController < ApplicationController redirect_to conference_booths_path, notice: 'Booth successfully re-submitted' else - flash[:error] = "Booth could not be re-submitted. #{@booth.errors.full_messages.to_sentence}." + flash.now[:error] = "Booth could not be re-submitted. #{@booth.errors.full_messages.to_sentence}." end end From f14d5926e1f54596e89300db633697e78a1be6af Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 29 Aug 2017 09:06:51 +0200 Subject: [PATCH 196/237] explicitely set log_level for production Without this setting there is a warning displayed: DEPRECATION WARNING: You did not specify a `log_level` in `production.rb` --- config/environments/production.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environments/production.rb b/config/environments/production.rb index cb3a5d67..4e2c2e79 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -36,7 +36,7 @@ Osem::Application.configure do # config.force_ssl = true # See everything in the log (default is :info) - # config.log_level = :debug + config.log_level = :info # Prepend all log lines with the following tags # config.log_tags = [ :subdomain, :uuid ] From fbd11a1402a83e3b05b3d3d13c128ccc61d3468c Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 28 Aug 2017 21:55:31 +0530 Subject: [PATCH 197/237] Remove datatables if there is no data --- app/views/admin/booths/index.html.haml | 83 +++++++-------- app/views/admin/tracks/index.html.haml | 135 +++++++++++++------------ spec/features/tracks_spec.rb | 7 +- 3 files changed, 113 insertions(+), 112 deletions(-) diff --git a/app/views/admin/booths/index.html.haml b/app/views/admin/booths/index.html.haml index 9eef8f96..428895e5 100644 --- a/app/views/admin/booths/index.html.haml +++ b/app/views/admin/booths/index.html.haml @@ -29,48 +29,49 @@ ( = link_to "#{@conference.booth_limit} booths", edit_admin_conference_path(@conference.short_title) ) - %table.table.table-striped.table-bordered.table-hover.datatable - %thead - %th - %b ID - %th - %b Logo - %th - %b Title - %th - %b Submitter - %th - %b Responsibles - %th - %b State - %th - %b Actions - - @booths.each do |booth| - %tr - %td - = booth.id - %td - - if booth.logo_link - = image_tag(booth.picture.thumb.url, width: '20%') - %td - = link_to booth.title, admin_conference_booth_path(@conference.short_title, booth) - %td - = link_to booth.submitter.name, admin_user_path(booth.submitter) if booth.submitter - %td - .responsibles - - booth.responsibles.each_with_index do |responsible, i| - = link_to responsible.name, admin_user_path(responsible) - = ", " unless i == booth.responsibles.length - 1 - %td - .btn-group - %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } - = booth.state.humanize - %span.caret - %ul.dropdown-menu{ role: 'menu' } - = render 'change_state_dropdown', booth: booth + - if @booths.any? + %table.table.table-striped.table-bordered.table-hover.datatable + %thead + %th + %b ID + %th + %b Logo + %th + %b Title + %th + %b Submitter + %th + %b Responsibles + %th + %b State + %th + %b Actions + - @booths.each do |booth| + %tr %td - = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id), - class: 'btn btn-primary' + = booth.id + %td + - if booth.logo_link + = image_tag(booth.picture.thumb.url, width: '20%') + %td + = link_to booth.title, admin_conference_booth_path(@conference.short_title, booth) + %td + = link_to booth.submitter.name, admin_user_path(booth.submitter) if booth.submitter + %td + .responsibles + - booth.responsibles.each_with_index do |responsible, i| + = link_to responsible.name, admin_user_path(responsible) + = ", " unless i == booth.responsibles.length - 1 + %td + .btn-group + %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } + = booth.state.humanize + %span.caret + %ul.dropdown-menu{ role: 'menu' } + = render 'change_state_dropdown', booth: booth + %td + = link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id), + class: 'btn btn-primary' .row .col-md-12.text-right - if can? :create, Booth diff --git a/app/views/admin/tracks/index.html.haml b/app/views/admin/tracks/index.html.haml index 95eafcb3..b814ac8e 100644 --- a/app/views/admin/tracks/index.html.haml +++ b/app/views/admin/tracks/index.html.haml @@ -7,75 +7,76 @@ Categorize events in your conference .row .col-md-12 - %table.table.table-hover.table-striped.table-bordered.datatable#tracks - %thead - %th ID - %th Name - %th Description - %th Room - %th Start Date - %th End Date - %th Submitter - %th Included in Cfp - %th State - %th Actions - %tbody - - @tracks.each do |track| - %tr - %td - = track.id - %td{ style: 'padding: 15px 0px 0px 10px;' } - = link_to admin_conference_program_track_path(@conference.short_title, track), class: 'btn' do - %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} - = track.name - %td - %p - = markdown(truncate(track.description)) - %td - = track.room.try(:name) - %td - = track.start_date.strftime('%A, %B %-d. %Y') if track.start_date - %td - = track.end_date.strftime('%A, %B %-d. %Y') if track.end_date - %td - = link_to track.submitter.name, admin_user_path(track.submitter) if track.self_organized? - %td.text-center{ 'id' => "cfp_switch_#{track.id}", 'data-order' => track.cfp_active.to_s } - = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, - class: 'switch-checkbox', method: :patch, - url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.short_name)+"?included=", - data: { size: 'small', - on_color: 'success', - off_color: 'warning', - on_text: 'Yes', - off_text: 'No' } + - if @tracks.any? + %table.table.table-hover.table-striped.table-bordered.datatable#tracks + %thead + %th ID + %th Name + %th Description + %th Room + %th Start Date + %th End Date + %th Submitter + %th Included in Cfp + %th State + %th Actions + %tbody + - @tracks.each do |track| + %tr + %td + = track.id + %td{ style: 'padding: 15px 0px 0px 10px;' } + = link_to admin_conference_program_track_path(@conference.short_title, track), class: 'btn' do + %span.label{style: "background-color: #{track.color}; color: #{ contrast_color(track.color) }"} + = track.name + %td + %p + = markdown(truncate(track.description)) + %td + = track.room.try(:name) + %td + = track.start_date.strftime('%A, %B %-d. %Y') if track.start_date + %td + = track.end_date.strftime('%A, %B %-d. %Y') if track.end_date + %td + = link_to track.submitter.name, admin_user_path(track.submitter) if track.self_organized? + %td.text-center{ 'id' => "cfp_switch_#{track.id}", 'data-order' => track.cfp_active.to_s } + = check_box_tag "#{@conference.short_title}_#{track.short_name}", track.id, track.cfp_active, + class: 'switch-checkbox', method: :patch, + url: toggle_cfp_inclusion_admin_conference_program_track_path(@conference.short_title, id: track.short_name)+"?included=", + data: { size: 'small', + on_color: 'success', + off_color: 'warning', + on_text: 'Yes', + off_text: 'No' } - %td.text-center - - if track.self_organized? - .btn-group - %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } - = track.state.humanize - %span.caret - %ul.dropdown-menu{ role: 'menu' } - = render 'change_state_dropdown', track: track - - else - = track.state.humanize - %td - .btn-group{ role: 'group' } - - if can? :edit, track - = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-primary' - - special_style = true - - if can? :destroy, track - = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), method: :delete, class: 'btn btn-danger', - data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } + %td.text-center - if track.self_organized? - - if track.selected_schedule - - if can? :show, track.selected_schedule - = link_to 'Show Schedule', admin_conference_schedule_path(@conference.short_title, track.selected_schedule), - class: 'btn btn-default' - - elsif can? :create, @program.schedules.build(track: track) - = button_to 'Create Schedule', admin_conference_schedules_path(@conference.short_title), - form: { class: 'btn', style: 'padding: 0px 0px; margin-top: -1px;' }, class: 'btn btn-default', - style: ('border-top-left-radius: 0; border-bottom-left-radius: 0;' if special_style), params: { 'schedule[track_id]' => track.id } + .btn-group + %button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' } + = track.state.humanize + %span.caret + %ul.dropdown-menu{ role: 'menu' } + = render 'change_state_dropdown', track: track + - else + = track.state.humanize + %td + .btn-group{ role: 'group' } + - if can? :edit, track + = link_to 'Edit', edit_admin_conference_program_track_path(@conference.short_title, track), class: 'btn btn-primary' + - special_style = true + - if can? :destroy, track + = link_to 'Delete', admin_conference_program_track_path(@conference.short_title, track), method: :delete, class: 'btn btn-danger', + data: { confirm: "Do you really want to delete #{track.name}? Attention: This track will be removed from all Events that have it set" } + - if track.self_organized? + - if track.selected_schedule + - if can? :show, track.selected_schedule + = link_to 'Show Schedule', admin_conference_schedule_path(@conference.short_title, track.selected_schedule), + class: 'btn btn-default' + - elsif can? :create, @program.schedules.build(track: track) + = button_to 'Create Schedule', admin_conference_schedules_path(@conference.short_title), + form: { class: 'btn', style: 'padding: 0px 0px; margin-top: -1px;' }, class: 'btn btn-default', + style: ('border-top-left-radius: 0; border-bottom-left-radius: 0;' if special_style), params: { 'schedule[track_id]' => track.id } .row .col-md-12.text-right = link_to 'New Track', new_admin_conference_program_track_path(@conference.short_title), class: 'btn btn-primary' diff --git a/spec/features/tracks_spec.rb b/spec/features/tracks_spec.rb index 0819c650..934f28ba 100644 --- a/spec/features/tracks_spec.rb +++ b/spec/features/tracks_spec.rb @@ -42,10 +42,9 @@ feature Track do expected.to change { Track.count }.by(-1) expect(flash).to eq('Track successfully deleted.') - within('table#tracks') do - expect(page.has_content?(track.name)).to be false - expect(page.has_content?(track.description)).to be false - end + expect(page.has_css?('table#tracks')).to be false + expect(page.has_content?(track.name)).to be false + expect(page.has_content?(track.description)).to be false end scenario 'updates a track', feature: true, js: true do From 27bf79996d237a09a19b148b64d1057be6f864a2 Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Sat, 12 Aug 2017 03:01:36 +0530 Subject: [PATCH 198/237] One user one registration ticket A user cannot have more than one registration ticket per conference. --- .../ticket_purchases_controller.rb | 2 +- app/models/ticket_purchase.rb | 48 ++++++++++++++----- app/models/user.rb | 6 ++- .../conference_registrations/show.html.haml | 2 +- app/views/tickets/_ticket.html.haml | 11 +++-- app/views/tickets/index.html.haml | 4 +- spec/features/ticket_purchases_spec.rb | 36 +++++++++++++- spec/models/ticket_purchase_spec.rb | 16 +++++++ 8 files changed, 104 insertions(+), 21 deletions(-) diff --git a/app/controllers/ticket_purchases_controller.rb b/app/controllers/ticket_purchases_controller.rb index f15fc993..a53a3cf5 100644 --- a/app/controllers/ticket_purchases_controller.rb +++ b/app/controllers/ticket_purchases_controller.rb @@ -19,7 +19,7 @@ class TicketPurchasesController < ApplicationController error: 'Please get at least one ticket to continue.' end else - redirect_to conference_conference_registration_path(@conference.short_title), + redirect_to conference_tickets_path(@conference.short_title), error: "Oops, something went wrong with your purchase! #{message}" end end diff --git a/app/models/ticket_purchase.rb b/app/models/ticket_purchase.rb index a2ed2747..97fa9957 100644 --- a/app/models/ticket_purchase.rb +++ b/app/models/ticket_purchase.rb @@ -5,7 +5,8 @@ class TicketPurchase < ActiveRecord::Base belongs_to :payment validates :ticket_id, :user_id, :conference_id, :quantity, presence: true - + validate :one_registration_ticket_per_user + validate :registration_ticket_already_purchased, on: :create validates :quantity, numericality: { greater_than: 0 } delegate :title, to: :ticket @@ -25,18 +26,21 @@ class TicketPurchase < ActiveRecord::Base def self.purchase(conference, user, purchases) errors = [] - ActiveRecord::Base.transaction do - conference.tickets.each do |ticket| - quantity = purchases[ticket.id.to_s].to_i - # if the user bought the ticket and is still unpaid, just update the quantity - purchase = if ticket.bought?(user) && ticket.unpaid?(user) - update_quantity(conference, quantity, ticket, user) - else - purchase_ticket(conference, quantity, ticket, user) - end - - if purchase && !purchase.save - errors.push(purchase.errors.full_messages) + if count_purchased_registration_tickets(conference, purchases) > 1 + errors.push('You cannot buy more than one registration tickets.') + else + ActiveRecord::Base.transaction do + conference.tickets.each do |ticket| + quantity = purchases[ticket.id.to_s].to_i + # if the user bought the ticket and is still unpaid, just update the quantity + purchase = if ticket.bought?(user) && ticket.unpaid?(user) + update_quantity(conference, quantity, ticket, user) + else + purchase_ticket(conference, quantity, ticket, user) + end + if purchase && !purchase.save + errors.push(purchase.errors.full_messages) + end end end end @@ -71,6 +75,18 @@ class TicketPurchase < ActiveRecord::Base end Mailbot.ticket_confirmation_mail(self).deliver_later end + + def one_registration_ticket_per_user + if ticket.try(:registration_ticket?) && quantity != 1 + errors.add(:quantity, 'cannot be greater than one for registration tickets.') + end + end + + def registration_ticket_already_purchased + if ticket.try(:registration_ticket?) && user.tickets.for_registration(conference).present? + errors.add(:quantity, 'cannot be greater than one for registration tickets.') + end + end end private @@ -79,3 +95,9 @@ def set_week self.week = created_at.strftime('%W') save! end + +def count_purchased_registration_tickets(conference, purchases) + conference.tickets.for_registration.inject(0) do |sum, registration_ticket| + sum + purchases[registration_ticket.id.to_s].to_i + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 793db609..ccdb488d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -51,7 +51,11 @@ class User < ActiveRecord::Base has_many :events_registrations, through: :registrations has_many :ticket_purchases, dependent: :destroy has_many :payments, dependent: :destroy - has_many :tickets, through: :ticket_purchases, source: :ticket + has_many :tickets, through: :ticket_purchases, source: :ticket do + def for_registration conference + where(conference: conference, registration_ticket: true).first + end + end has_many :votes, dependent: :destroy has_many :voted_events, through: :votes, source: :events has_many :subscriptions, dependent: :destroy diff --git a/app/views/conference_registrations/show.html.haml b/app/views/conference_registrations/show.html.haml index c510a263..83d6d89c 100644 --- a/app/views/conference_registrations/show.html.haml +++ b/app/views/conference_registrations/show.html.haml @@ -109,7 +109,7 @@ You haven't bought any tickets. = link_to 'Please get some tickets to support us!', conference_tickets_path(@conference.short_title) %p - (Your participation won't be valid without getting a ticket) + (Your participation won't be valid without getting a registration ticket) .row .col-md-12 diff --git a/app/views/tickets/_ticket.html.haml b/app/views/tickets/_ticket.html.haml index e3985773..8f5fc82b 100644 --- a/app/views/tickets/_ticket.html.haml +++ b/app/views/tickets/_ticket.html.haml @@ -1,5 +1,5 @@ %tr - %td.col-sm-8.col-md-6 + %td.col-sm-8.col-md-4 .media .media-body %h4.media-heading @@ -7,9 +7,14 @@ %h5.media-heading - unless ticket.description.blank? = markdown(ticket.description) + %td.col-sm-1.col-md-2.text-center + = ticket.registration_ticket? ? 'Yes' : 'No' %td.col-sm-1.col-md-1 - = text_field_tag("tickets[][#{ticket.id}]", 0, - type: 'number', min: 0, class: "form-control quantity", 'data-id' => ticket.id) + - options = { type: 'number', min: 0, class: "form-control quantity", 'data-id' => ticket.id } + - if ticket.registration_ticket? + - options[:max] = 1 + - options[:disabled] = current_user.tickets.for_registration(ticket.conference).present? + = text_field_tag("tickets[][#{ticket.id}]", 0, options) %td.col-sm-1.col-md-1.text-center = ticket.price.symbol %span{id: "price_#{ticket.id}"} diff --git a/app/views/tickets/index.html.haml b/app/views/tickets/index.html.haml index dc67f529..cba13ea5 100644 --- a/app/views/tickets/index.html.haml +++ b/app/views/tickets/index.html.haml @@ -14,6 +14,7 @@ %thead %tr %th Ticket + %th Registration Ticket %th Quantity %th Price %th Total @@ -21,6 +22,7 @@ - @conference.tickets.each do |ticket| = render partial: 'ticket', f: f, locals: {ticket: ticket} %tr + %td %td %td %td.col-sm-1.col-md-1.text-center @@ -46,4 +48,4 @@ .col-md-13 %p.text-muted.text-center %small - * Getting a ticket is mandatory. Your participation will not be valid until you get a ticket. + * Getting a registration ticket is mandatory. Your participation will not be valid until you get a registration ticket. diff --git a/spec/features/ticket_purchases_spec.rb b/spec/features/ticket_purchases_spec.rb index 958ae645..c76b84a6 100644 --- a/spec/features/ticket_purchases_spec.rb +++ b/spec/features/ticket_purchases_spec.rb @@ -3,7 +3,9 @@ require 'spec_helper' feature Registration do let!(:ticket) { create(:ticket) } let!(:free_ticket) { create(:ticket, price_cents: 0) } - let!(:conference) { create(:conference, title: 'ExampleCon', tickets: [ticket, free_ticket], registration_period: create(:registration_period, start_date: 3.days.ago)) } + let!(:first_registration_ticket) { create(:registration_ticket, price_cents: 0) } + let!(:second_registration_ticket) { create(:registration_ticket, price_cents: 0) } + let!(:conference) { create(:conference, title: 'ExampleCon', tickets: [ticket, free_ticket, first_registration_ticket, second_registration_ticket], registration_period: create(:registration_period, start_date: 3.days.ago)) } let!(:participant) { create(:user) } context 'as a participant' do @@ -106,6 +108,38 @@ feature Registration do expect(purchase.quantity).to eq(5) expect(purchase.paid).to be true end + + scenario 'purchases more than one registration tickets of a single type' do + visit root_path + click_link 'Register' + + expect(current_path).to eq(new_conference_conference_registration_path(conference.short_title)) + click_button 'Register' + + fill_in "tickets__#{first_registration_ticket.id}", with: '5' + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + + click_button 'Continue' + + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + end + + scenario 'purchases one registration ticket of a different types' do + visit root_path + click_link 'Register' + + expect(current_path).to eq(new_conference_conference_registration_path(conference.short_title)) + click_button 'Register' + + fill_in "tickets__#{first_registration_ticket.id}", with: '1' + fill_in "tickets__#{second_registration_ticket.id}", with: '1' + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + + click_button 'Continue' + + expect(flash).to eq('Oops, something went wrong with your purchase! You cannot buy more than one registration tickets.') + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + end end context 'who is registered' do diff --git a/spec/models/ticket_purchase_spec.rb b/spec/models/ticket_purchase_spec.rb index 3ef9a861..bfca5efc 100644 --- a/spec/models/ticket_purchase_spec.rb +++ b/spec/models/ticket_purchase_spec.rb @@ -34,6 +34,22 @@ describe TicketPurchase do it 'is valid with a quantity greater than zero' do should allow_value(1).for(:quantity) end + + describe 'one_registration_ticket_per_user' do + let(:registration_ticket) { create(:registration_ticket) } + let(:ticket_purchase) { build(:ticket_purchase, ticket: registration_ticket, quantity: 1) } + + it 'it is valid, if quantity for registration tickets is less than or equal to one' do + expect(ticket_purchase.valid?).to eq true + end + + it 'it is not valid, if quantity for registration tickets is greater than to one' do + ticket_purchase.quantity = 4 + + expect(ticket_purchase.valid?).to eq false + expect(ticket_purchase.errors[:quantity]).to eq ['cannot be greater than one for registration tickets.'] + end + end end describe 'self#purchase' do From b4d376e7bed5fa320724f9fc0de277a721528242 Mon Sep 17 00:00:00 2001 From: namangupta01 <01namangupta@gmail.com> Date: Tue, 5 Sep 2017 17:40:46 +0530 Subject: [PATCH 199/237] expected_string_default_error is fixed --- Gemfile | 2 ++ Gemfile.lock | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 08170e30..7f25aa46 100644 --- a/Gemfile +++ b/Gemfile @@ -83,6 +83,8 @@ gem 'jquery-ui-rails', '~> 4.2.1' # for languages validation gem 'iso-639' +gem 'thor', '0.19.1' + # frontend javascripts source 'https://rails-assets.org' do # for placeholder images diff --git a/Gemfile.lock b/Gemfile.lock index faaa8246..d6d8eb3b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -511,7 +511,7 @@ GEM sysexits (1.2.0) term-ansicolor (1.3.2) tins (~> 1.0) - thor (0.19.4) + thor (0.19.1) thread_safe (0.3.6) tilt (1.4.1) timecop (0.7.1) @@ -651,6 +651,7 @@ DEPENDENCIES sqlite3 stripe stripe-ruby-mock + thor (= 0.19.1) timecop transitions turbolinks From 9f8836732dffcbfcb81256f12a8d4118abb680b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=20Mar=C3=ADa=20Mart=C3=ADnez=20G=C3=B3mez?= Date: Tue, 12 Sep 2017 11:54:06 +0200 Subject: [PATCH 200/237] Update mariadb to 10.2 to solve Travis failures Our test suite is failing in Travis as it complains about not finding `libmysqlclient-dev` which is needed for mysql2. But installing `libmysqlclient-dev` conflicts with MariaDB 10.1. So I updated MariaDB to 10.2 and mysql to the last version as the old one is not compatible with MariaDB 10.2. The missed `libmysqlclient-dev` is not needed any more. --- .travis.yml | 2 +- Gemfile.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9191bbd7..6650fbf9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_install: - "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc" - "echo `phantomjs -v`" addons: - mariadb: '10.1' + mariadb: '10.2' notifications: email: on_success: change diff --git a/Gemfile.lock b/Gemfile.lock index d6d8eb3b..c6b4faa8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -287,7 +287,7 @@ GEM multi_json (1.12.1) multi_xml (0.5.5) multipart-post (2.0.0) - mysql2 (0.4.2) + mysql2 (0.4.9) nenv (0.3.0) netrc (0.11.0) nokogiri (1.8.0) From cceb11c73a6007fb6b538eefabacf6dcd667dedc Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 12 Sep 2017 19:35:53 +0530 Subject: [PATCH 201/237] Add missing argument In version/object_desc_and_link line 108, the fourth argument was missing that is added in this commit. Closes https://github.com/opensuse/osem/issues/1689 --- app/views/admin/versions/_object_desc_and_link.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index 12f9dbbc..a924a4cf 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -106,7 +106,8 @@ = 'booth' - booth = current_or_last_object_state(version.item_type, version.item_id) = link_if_alive version, booth.title, - admin_conference_booth_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id ) + admin_conference_booth_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id ), + conference - when 'Program' = link_if_alive version, 'program', From 69e30e7ba941fe316da76e846f6b95a2a54f3bdb Mon Sep 17 00:00:00 2001 From: siddhantbajaj Date: Tue, 22 Aug 2017 14:57:42 +0530 Subject: [PATCH 202/237] Improving check-in process mark user as present for the conference when user's registration ticket for that conference is scanned --- app/models/ticket_scanning.rb | 10 ++++++++++ app/models/user.rb | 12 ++++++++++- .../admin/ticket_scannings_controller_spec.rb | 4 +++- spec/factories/ticket_scanning.rb | 5 +++++ spec/models/ticket_scanning_spec.rb | 20 +++++++++++++++++++ 5 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 spec/factories/ticket_scanning.rb create mode 100644 spec/models/ticket_scanning_spec.rb diff --git a/app/models/ticket_scanning.rb b/app/models/ticket_scanning.rb index 6ce9d00c..350d4f9b 100644 --- a/app/models/ticket_scanning.rb +++ b/app/models/ticket_scanning.rb @@ -1,3 +1,13 @@ class TicketScanning < ActiveRecord::Base belongs_to :physical_ticket + + before_create :mark_user_present + + private + + def mark_user_present + if physical_ticket.ticket.registration_ticket? + physical_ticket.user.mark_attendance_for_conference(physical_ticket.conference) + end + end end diff --git a/app/models/user.rb b/app/models/user.rb index ccdb488d..231e1c11 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -47,7 +47,11 @@ class User < ActiveRecord::Base has_many :event_users, dependent: :destroy has_many :events, -> { uniq }, through: :event_users has_many :presented_events, -> { joins(:event_users).where(event_users: {event_role: 'speaker'}).uniq }, through: :event_users, source: :event - has_many :registrations, dependent: :destroy + has_many :registrations, dependent: :destroy do + def for_conference conference + where(conference: conference).first + end + end has_many :events_registrations, through: :registrations has_many :ticket_purchases, dependent: :destroy has_many :payments, dependent: :destroy @@ -93,6 +97,12 @@ class User < ActiveRecord::Base event_registration.attended end + def mark_attendance_for_conference conference + registration = registrations.for_conference(conference) + registration.attended = true + registration.save + end + def name self[:name].blank? ? username : self[:name] end diff --git a/spec/controllers/admin/ticket_scannings_controller_spec.rb b/spec/controllers/admin/ticket_scannings_controller_spec.rb index 245bd885..2eb2e4ed 100644 --- a/spec/controllers/admin/ticket_scannings_controller_spec.rb +++ b/spec/controllers/admin/ticket_scannings_controller_spec.rb @@ -4,7 +4,9 @@ describe Admin::TicketScanningsController do let(:admin) { create(:admin) } let(:conference) { create(:conference) } let(:user) { create(:user) } - let(:paid_ticket_purchase) { create(:ticket_purchase, conference: conference, user: user) } + let!(:registration) { create(:registration, conference: conference, user: user) } + let(:registration_ticket) { create(:registration_ticket, conference: conference) } + let(:paid_ticket_purchase) { create(:ticket_purchase, conference: conference, user: user, ticket: registration_ticket, quantity: 1) } let(:physical_ticket) { create(:physical_ticket, ticket_purchase: paid_ticket_purchase) } context 'logged in as user with no role' do diff --git a/spec/factories/ticket_scanning.rb b/spec/factories/ticket_scanning.rb new file mode 100644 index 00000000..540d1fd0 --- /dev/null +++ b/spec/factories/ticket_scanning.rb @@ -0,0 +1,5 @@ +FactoryGirl.define do + factory :ticket_scanning do + physical_ticket + end +end diff --git a/spec/models/ticket_scanning_spec.rb b/spec/models/ticket_scanning_spec.rb new file mode 100644 index 00000000..3d978f4f --- /dev/null +++ b/spec/models/ticket_scanning_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe TicketScanning do + let(:conference) { create(:conference) } + let(:user) { create(:user) } + let(:registration) { create(:registration, conference: conference, user: user) } + let(:registration_ticket) { create(:registration_ticket, conference: conference) } + let(:paid_ticket_purchase) { create(:ticket_purchase, conference: conference, user: user, ticket: registration_ticket, quantity: 1) } + let(:physical_ticket) { create(:physical_ticket, ticket_purchase: paid_ticket_purchase) } + let(:ticket_scanning) { create(:ticket_scanning, physical_ticket: physical_ticket) } + + describe 'before_create' do + it 'marks user as present' do + expect(registration.attended).to eq(false) + ticket_scanning + registration.reload + expect(registration.attended).to eq(true) + end + end +end From c317565ec7d22edb8e818cba81b7502403b6aabc Mon Sep 17 00:00:00 2001 From: namangupta01 <01namangupta@gmail.com> Date: Thu, 7 Sep 2017 23:44:27 +0530 Subject: [PATCH 203/237] proposals#edit form text in track field is added --- app/helpers/events_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index e8f295d5..8f620e62 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -44,7 +44,7 @@ module EventsHelper if @program.tracks.confirmed.cfp_active.any? form.input :track_id, as: :select, collection: @program.tracks.confirmed.cfp_active.pluck(:name, :id), - include_blank: true + include_blank: '(Please select)' end end end From ec8fbb21d72648f65de99500ad1db0f5c3b887d9 Mon Sep 17 00:00:00 2001 From: namangupta01 <01namangupta@gmail.com> Date: Thu, 31 Aug 2017 13:43:08 +0530 Subject: [PATCH 204/237] Showing of tracks when there are no tracks in proposals is fixed Closes #1668 --- app/views/proposals/_encouragement_text.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/proposals/_encouragement_text.html.haml b/app/views/proposals/_encouragement_text.html.haml index c6d574d6..48fcd045 100644 --- a/app/views/proposals/_encouragement_text.html.haml +++ b/app/views/proposals/_encouragement_text.html.haml @@ -2,7 +2,7 @@ - if @program.event_types.any? You can submit proposals for = "#{event_types(@conference)}." - - if @program.tracks.any? + - if @program.tracks.confirmed.cfp_active.any? Proposals should fit in one of the = "#{pluralize(@program.tracks.confirmed.cfp_active.count, 'track')}:" = "#{tracks(@conference)}." From c929d8e68b0b238fe1f65ed5ba674e331d7262bb Mon Sep 17 00:00:00 2001 From: ViditChitkara Date: Fri, 15 Sep 2017 15:13:55 +0530 Subject: [PATCH 205/237] fixed schedule-page error closes #1693 --- app/controllers/schedules_controller.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb index eeb272e0..eb145730 100644 --- a/app/controllers/schedules_controller.rb +++ b/app/controllers/schedules_controller.rb @@ -21,10 +21,10 @@ class SchedulesController < ApplicationController # the schedule takes you to today if it is a date of the schedule @current_day = @conference.current_conference_day @day = @current_day.present? ? @current_day : @dates.first - return unless @current_day - # the schedule takes you to the current time if it is beetween the start and the end time. - @hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour) - + unless @current_day + # the schedule takes you to the current time if it is beetween the start and the end time. + @hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour) + end # Ids of the schedules of confrmed self_organized tracks along with the selected_schedule_id @selected_schedules_ids = [@conference.program.selected_schedule_id] @conference.program.tracks.self_organized.confirmed.each do |track| From c9b70c22edd18bc832bc3d8b61a683bac2710bef Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 15 Sep 2017 22:42:14 +0200 Subject: [PATCH 206/237] add CHF currency --- app/views/admin/tickets/_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/tickets/_form.html.haml b/app/views/admin/tickets/_form.html.haml index 11aff78d..319f7996 100644 --- a/app/views/admin/tickets/_form.html.haml +++ b/app/views/admin/tickets/_form.html.haml @@ -12,7 +12,7 @@ = f.input :title = f.input :description, input_html: { rows: 5, data: { provide: "markdown-editable" } } = f.input :price - = f.input :price_currency, as: :select, class: 'form-control', collection: ['USD', 'EUR', 'GBP', 'INR', 'CNY'], include_blank: false + = f.input :price_currency, as: :select, class: 'form-control', collection: ['USD', 'EUR', 'GBP', 'INR', 'CNY', 'CHF'], include_blank: false = f.input :registration_ticket, hint: 'A registration ticket is with which user register for the conference.' %p.text-right = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } From 82b5f9083abdee4e954d0197a3c80621a0df9554 Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 18 Sep 2017 19:07:13 +0530 Subject: [PATCH 207/237] Fix total price for tickets While buying the ticket, user was only able to see the integer part in total.So in javascript parseInt was replaced with parseFloat to show the decimal part too Fixes https://github.com/openSUSE/osem/issues/1702 --- app/assets/javascripts/osem-tickets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/osem-tickets.js b/app/assets/javascripts/osem-tickets.js index ea99a349..3c915f03 100644 --- a/app/assets/javascripts/osem-tickets.js +++ b/app/assets/javascripts/osem-tickets.js @@ -9,7 +9,7 @@ function update_price($this){ // Calculate total price var total = 0; $('.total_row').each(function( index ) { - total += parseInt($(this).text()); + total += parseFloat($(this).text()); }); $('#total_price').text(total); } From a07df4bdb0692fc289d2b89e8e1a634bddb5153d Mon Sep 17 00:00:00 2001 From: rahul Date: Wed, 20 Sep 2017 21:38:34 +0530 Subject: [PATCH 208/237] Fix decimal numbers limit to 2 while calculating the row total, javascript was called and on some quantity, a number with a big decimal part was appearing.In this PR it is fixed Fixes https://github.com/opensuse/osem/issues/1709 --- app/assets/javascripts/osem-tickets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/osem-tickets.js b/app/assets/javascripts/osem-tickets.js index 3c915f03..51881055 100644 --- a/app/assets/javascripts/osem-tickets.js +++ b/app/assets/javascripts/osem-tickets.js @@ -4,7 +4,7 @@ function update_price($this){ // Calculate price for row var value = $this.val(); var price = $('#price_' + id).text(); - $('#total_row_' + id).text(value * price); + $('#total_row_' + id).text((value * price).toFixed(2)); // Calculate total price var total = 0; From 2247231d6eb6a74c9a4f62738d3a3b69bdf0662f Mon Sep 17 00:00:00 2001 From: rishabhptr Date: Mon, 25 Sep 2017 21:30:46 +0530 Subject: [PATCH 209/237] Added amount check for payments#new --- app/controllers/payments_controller.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/controllers/payments_controller.rb b/app/controllers/payments_controller.rb index b5e2c193..bee58f6c 100644 --- a/app/controllers/payments_controller.rb +++ b/app/controllers/payments_controller.rb @@ -3,6 +3,7 @@ class PaymentsController < ApplicationController load_and_authorize_resource load_resource :conference, find_by: :short_title authorize_resource :conference_registrations, class: Registration + before_action :check_amount, only: [:new] def index @payments = current_user.payments @@ -28,6 +29,11 @@ class PaymentsController < ApplicationController end end + def check_amount + @total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false) + redirect_to root_path if @total_amount_to_pay.zero? + end + private def payment_params From 568d89b6202c0ae1f377ff4290f6b7a5dc1cca7a Mon Sep 17 00:00:00 2001 From: rishabhptr Date: Tue, 26 Sep 2017 21:43:18 +0530 Subject: [PATCH 210/237] Changed physical_ticket to plural --- ...al_ticket_controller.rb => physical_tickets_controller.rb} | 2 +- app/controllers/payments_controller.rb | 2 +- ...al_ticket_controller.rb => physical_tickets_controller.rb} | 2 +- app/controllers/ticket_purchases_controller.rb | 2 +- .../{physical_ticket => physical_tickets}/index.html.haml | 0 app/views/admin/tickets/index.html.haml | 2 +- app/views/conferences/_conference_details.html.haml | 2 +- .../{physical_ticket => physical_tickets}/index.html.haml | 0 .../{physical_ticket => physical_tickets}/show.html.haml | 0 config/routes.rb | 4 ++-- spec/controllers/physical_ticket_controller_spec.rb | 2 +- spec/features/ticket_purchases_spec.rb | 2 +- 12 files changed, 10 insertions(+), 10 deletions(-) rename app/controllers/admin/{physical_ticket_controller.rb => physical_tickets_controller.rb} (88%) rename app/controllers/{physical_ticket_controller.rb => physical_tickets_controller.rb} (94%) rename app/views/admin/{physical_ticket => physical_tickets}/index.html.haml (100%) rename app/views/{physical_ticket => physical_tickets}/index.html.haml (100%) rename app/views/{physical_ticket => physical_tickets}/show.html.haml (100%) diff --git a/app/controllers/admin/physical_ticket_controller.rb b/app/controllers/admin/physical_tickets_controller.rb similarity index 88% rename from app/controllers/admin/physical_ticket_controller.rb rename to app/controllers/admin/physical_tickets_controller.rb index d43c5c33..0fb26ad8 100644 --- a/app/controllers/admin/physical_ticket_controller.rb +++ b/app/controllers/admin/physical_tickets_controller.rb @@ -1,5 +1,5 @@ module Admin - class PhysicalTicketController < Admin::BaseController + class PhysicalTicketsController < Admin::BaseController before_action :authenticate_user! load_resource :conference, find_by: :short_title load_and_authorize_resource diff --git a/app/controllers/payments_controller.rb b/app/controllers/payments_controller.rb index bee58f6c..8faebef7 100644 --- a/app/controllers/payments_controller.rb +++ b/app/controllers/payments_controller.rb @@ -19,7 +19,7 @@ class PaymentsController < ApplicationController if @payment.purchase && @payment.save update_purchased_ticket_purchases - redirect_to conference_physical_ticket_index_path, + redirect_to conference_physical_tickets_path, notice: 'Thanks! Your ticket is booked successfully.' else @total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false) diff --git a/app/controllers/physical_ticket_controller.rb b/app/controllers/physical_tickets_controller.rb similarity index 94% rename from app/controllers/physical_ticket_controller.rb rename to app/controllers/physical_tickets_controller.rb index af02155c..2f6f18ec 100644 --- a/app/controllers/physical_ticket_controller.rb +++ b/app/controllers/physical_tickets_controller.rb @@ -1,4 +1,4 @@ -class PhysicalTicketController < ApplicationController +class PhysicalTicketsController < ApplicationController before_action :authenticate_user! load_resource :conference, find_by: :short_title load_and_authorize_resource find_by: :token diff --git a/app/controllers/ticket_purchases_controller.rb b/app/controllers/ticket_purchases_controller.rb index a53a3cf5..3eb8b68d 100644 --- a/app/controllers/ticket_purchases_controller.rb +++ b/app/controllers/ticket_purchases_controller.rb @@ -12,7 +12,7 @@ class TicketPurchasesController < ApplicationController redirect_to new_conference_payment_path, notice: 'Please pay here to get tickets.' elsif current_user.ticket_purchases.by_conference(@conference).paid.any? - redirect_to conference_physical_ticket_index_path, + redirect_to conference_physical_tickets_path, notice: 'You have free tickets for the conference.' else redirect_to conference_tickets_path(@conference.short_title), diff --git a/app/views/admin/physical_ticket/index.html.haml b/app/views/admin/physical_tickets/index.html.haml similarity index 100% rename from app/views/admin/physical_ticket/index.html.haml rename to app/views/admin/physical_tickets/index.html.haml diff --git a/app/views/admin/tickets/index.html.haml b/app/views/admin/tickets/index.html.haml index b8cdb505..42154ae7 100644 --- a/app/views/admin/tickets/index.html.haml +++ b/app/views/admin/tickets/index.html.haml @@ -40,4 +40,4 @@ .row .col-md-12 = link_to 'Add Ticket', new_admin_conference_ticket_path, class: 'btn btn-success pull-right' - = link_to 'Tickets Sold', admin_conference_physical_ticket_index_path, class: 'button btn btn-default btn-info pull-right' + = link_to 'Tickets Sold', admin_conference_physical_tickets_path, class: 'button btn btn-default btn-info pull-right' diff --git a/app/views/conferences/_conference_details.html.haml b/app/views/conferences/_conference_details.html.haml index ebf80ef6..84a87303 100644 --- a/app/views/conferences/_conference_details.html.haml +++ b/app/views/conferences/_conference_details.html.haml @@ -47,4 +47,4 @@ - else = link_to 'Unsubscribe', conference_subscriptions_path(conference.short_title), method: :delete, class: 'btn btn-default' - if current_user && current_user.physical_tickets.by_conference(conference).any? - = link_to "My Tickets", conference_physical_ticket_index_path(conference.short_title), class: 'btn btn-default' + = link_to "My Tickets", conference_physical_tickets_path(conference.short_title), class: 'btn btn-default' diff --git a/app/views/physical_ticket/index.html.haml b/app/views/physical_tickets/index.html.haml similarity index 100% rename from app/views/physical_ticket/index.html.haml rename to app/views/physical_tickets/index.html.haml diff --git a/app/views/physical_ticket/show.html.haml b/app/views/physical_tickets/show.html.haml similarity index 100% rename from app/views/physical_ticket/show.html.haml rename to app/views/physical_tickets/show.html.haml diff --git a/config/routes.rb b/config/routes.rb index 0d7e7aec..99f716e4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -122,7 +122,7 @@ Osem::Application.routes.draw do resources :targets, except: [:show] resources :campaigns, except: [:show] resources :emails, only: [:show, :update, :index] - resources :physical_ticket, only: [:index] + resources :physical_tickets, only: [:index] resources :roles, except: [:new, :create] do member do post :toggle_user @@ -184,7 +184,7 @@ Osem::Application.routes.draw do resources :tickets, only: [:index] resources :ticket_purchases, only: [:create, :destroy, :index] resources :payments, only: [:index, :new, :create] - resources :physical_ticket, only: [:index, :show] + resources :physical_tickets, only: [:index, :show] resource :subscriptions, only: [:create, :destroy] resource :schedule, only: [:show] do member do diff --git a/spec/controllers/physical_ticket_controller_spec.rb b/spec/controllers/physical_ticket_controller_spec.rb index 863e27af..476a1717 100644 --- a/spec/controllers/physical_ticket_controller_spec.rb +++ b/spec/controllers/physical_ticket_controller_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe PhysicalTicketController do +describe PhysicalTicketsController do let(:conference) { create(:conference) } let(:user) { create(:user) } let(:paid_ticket_purchase) { create(:ticket_purchase, conference: conference, user: user) } diff --git a/spec/features/ticket_purchases_spec.rb b/spec/features/ticket_purchases_spec.rb index c76b84a6..9cace981 100644 --- a/spec/features/ticket_purchases_spec.rb +++ b/spec/features/ticket_purchases_spec.rb @@ -103,7 +103,7 @@ feature Registration do click_button 'Continue' - expect(current_path).to eq(conference_physical_ticket_index_path(conference.short_title)) + expect(current_path).to eq(conference_physical_tickets_path(conference.short_title)) purchase = TicketPurchase.where(user_id: participant.id, ticket_id: free_ticket.id).first expect(purchase.quantity).to eq(5) expect(purchase.paid).to be true From 407b1838cfa49a0430f30ecceaec2a21741cce31 Mon Sep 17 00:00:00 2001 From: rahul Date: Sat, 9 Sep 2017 16:13:17 +0530 Subject: [PATCH 211/237] Add cfp type in admin/cfp#show @cfp.cfp_type is added to booths, events & tracks to show the cfp type. Closes https://github.com/openSUSE/osem/issues/1679 --- app/views/admin/cfps/_booths_cfp.html.haml | 4 ++++ app/views/admin/cfps/_events_cfp.html.haml | 4 ++++ app/views/admin/cfps/_tracks_cfp.html.haml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/app/views/admin/cfps/_booths_cfp.html.haml b/app/views/admin/cfps/_booths_cfp.html.haml index 89012336..98943cec 100644 --- a/app/views/admin/cfps/_booths_cfp.html.haml +++ b/app/views/admin/cfps/_booths_cfp.html.haml @@ -1,3 +1,7 @@ +%dt + Type +%dd + = @cfp.cfp_type.capitalize %dt Start Date %dd diff --git a/app/views/admin/cfps/_events_cfp.html.haml b/app/views/admin/cfps/_events_cfp.html.haml index 51bc2079..572ffb2d 100644 --- a/app/views/admin/cfps/_events_cfp.html.haml +++ b/app/views/admin/cfps/_events_cfp.html.haml @@ -1,3 +1,7 @@ +%dt + Type: +%dd + = @cfp.cfp_type.capitalize %dt Start Date: %dd#start_date diff --git a/app/views/admin/cfps/_tracks_cfp.html.haml b/app/views/admin/cfps/_tracks_cfp.html.haml index e381df96..bcc2df43 100644 --- a/app/views/admin/cfps/_tracks_cfp.html.haml +++ b/app/views/admin/cfps/_tracks_cfp.html.haml @@ -1,3 +1,7 @@ +%dt + Type: +%dd + = @cfp.cfp_type.capitalize %dt Start Date: %dd#start_date From be6bfb6aaddc5f2926f5b01ce3d8c2c5675e0fe2 Mon Sep 17 00:00:00 2001 From: rahul Date: Sun, 10 Sep 2017 20:03:18 +0530 Subject: [PATCH 212/237] Add missing : to booths and events_cfp --- app/views/admin/cfps/_booths_cfp.html.haml | 8 ++++---- app/views/admin/cfps/_events_cfp.html.haml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/admin/cfps/_booths_cfp.html.haml b/app/views/admin/cfps/_booths_cfp.html.haml index 98943cec..7cdc6db4 100644 --- a/app/views/admin/cfps/_booths_cfp.html.haml +++ b/app/views/admin/cfps/_booths_cfp.html.haml @@ -1,16 +1,16 @@ %dt - Type + Type: %dd = @cfp.cfp_type.capitalize %dt - Start Date + Start Date: %dd = @cfp.start_date.strftime('%A, %B %e. %Y') %dt - End Date + End Date: %dd = @cfp.end_date.strftime('%A, %B %e. %Y') %dt - Days Left + Days Left: %dd = pluralize(@cfp.remaining_days, 'day') diff --git a/app/views/admin/cfps/_events_cfp.html.haml b/app/views/admin/cfps/_events_cfp.html.haml index 572ffb2d..f06aa6ca 100644 --- a/app/views/admin/cfps/_events_cfp.html.haml +++ b/app/views/admin/cfps/_events_cfp.html.haml @@ -23,7 +23,7 @@ %dd = tracks(@conference) %dt - Public Schedule + Public Schedule: %dd#schedule_public - if @program.schedule_public Yes @@ -37,6 +37,6 @@ - else No %dt - Rating Levels + Rating Levels: %dd#rating = @program.rating From ec91db86f90f4706c36573f1ff3ce9814ff40032 Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 11 Sep 2017 23:01:28 +0530 Subject: [PATCH 213/237] Fix error while generating pdf when venue is nil Error in generating pdf for ticket when venue is not set is fixed.Showing venue in pdf only if venue exist. Closes https://github.com/opensuse/osem/issues/1683 --- app/pdfs/ticket_pdf.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/pdfs/ticket_pdf.rb b/app/pdfs/ticket_pdf.rb index ecb4cd2c..48f26fe3 100644 --- a/app/pdfs/ticket_pdf.rb +++ b/app/pdfs/ticket_pdf.rb @@ -51,7 +51,9 @@ class TicketPdf < Prawn::Document move_down 70 draw_text @conference.title.to_s, at: [@mid_horizontal + 30, cursor - 30], size: 12 draw_text @conference.organization.name.to_s, at: [@mid_horizontal + 30, cursor - 50], size: 12 - draw_text @conference.venue.name.to_s, at: [@mid_horizontal + 30, cursor - 70] + if @conference.venue + draw_text @conference.venue.name.to_s, at: [@mid_horizontal + 30, cursor - 70] + end move_up 130 move_down @mid_vertical end From 8dd5a14b237a6957fb70e9fb077fccf930a16a4a Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 12 Sep 2017 17:52:01 +0530 Subject: [PATCH 214/237] Remove to_s from conference.venue.name name is already a string so to_s in not required --- app/pdfs/ticket_pdf.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pdfs/ticket_pdf.rb b/app/pdfs/ticket_pdf.rb index 48f26fe3..41af54ef 100644 --- a/app/pdfs/ticket_pdf.rb +++ b/app/pdfs/ticket_pdf.rb @@ -52,7 +52,7 @@ class TicketPdf < Prawn::Document draw_text @conference.title.to_s, at: [@mid_horizontal + 30, cursor - 30], size: 12 draw_text @conference.organization.name.to_s, at: [@mid_horizontal + 30, cursor - 50], size: 12 if @conference.venue - draw_text @conference.venue.name.to_s, at: [@mid_horizontal + 30, cursor - 70] + draw_text @conference.venue.name, at: [@mid_horizontal + 30, cursor - 70] end move_up 130 move_down @mid_vertical From 99e5af32174c4fe0294d622b8de1099aa8d59f00 Mon Sep 17 00:00:00 2001 From: rahul Date: Tue, 12 Sep 2017 18:10:16 +0530 Subject: [PATCH 215/237] Add full address to the ticket Full address is added to the ticket as earlier it was showing venue name only --- app/pdfs/ticket_pdf.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/pdfs/ticket_pdf.rb b/app/pdfs/ticket_pdf.rb index 41af54ef..3691fb04 100644 --- a/app/pdfs/ticket_pdf.rb +++ b/app/pdfs/ticket_pdf.rb @@ -53,6 +53,8 @@ class TicketPdf < Prawn::Document draw_text @conference.organization.name.to_s, at: [@mid_horizontal + 30, cursor - 50], size: 12 if @conference.venue draw_text @conference.venue.name, at: [@mid_horizontal + 30, cursor - 70] + draw_text @conference.venue.street, at: [@mid_horizontal + 30, cursor - 90] + draw_text @conference.venue.city, at: [@mid_horizontal + 30, cursor - 110] end move_up 130 move_down @mid_vertical From d6c7e8d97fbc7989a14d53cf431740ea845fa005 Mon Sep 17 00:00:00 2001 From: ViditChitkara Date: Tue, 26 Sep 2017 18:30:36 +0530 Subject: [PATCH 216/237] Fixed email overflow bug in tickets pdf closes #1691 minor changes --- app/pdfs/ticket_pdf.rb | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/app/pdfs/ticket_pdf.rb b/app/pdfs/ticket_pdf.rb index 3691fb04..9a09f9fe 100644 --- a/app/pdfs/ticket_pdf.rb +++ b/app/pdfs/ticket_pdf.rb @@ -25,20 +25,23 @@ class TicketPdf < Prawn::Document move_up @mid_vertical draw_text 'TICKET HOLDER', at: [@x, cursor - 30], size: 17 dash(2, space: 0) - stroke_rectangle [@x, cursor - 50], 230, 150 - move_down 80 - draw_text 'NAME', at: [@x + 10, cursor], size: 13 - fill_color '808080' - draw_text @user.name.to_s, at: [@x + 10, cursor - 25], size: 20 - fill_color '000000' - draw_text 'EMAIL', at: [@x + 10, cursor - 50], size: 13 - fill_color '808080' - draw_text @user.email.to_s, at: [@x + 10, cursor - 75], size: 20 - fill_color '000000' - move_up 20 + bounding_box [@x, cursor - 50], width: 230, height: 150 do + pad(15) do + text_box 'NAME', at: [@x + 10, cursor], size: 13 + fill_color '808080' + text_box @user.name.to_s, at: [@x + 10, cursor - 20], size: 18 + fill_color '000000' + text_box 'EMAIL', at: [@x + 10, cursor - 60], size: 13 + fill_color '808080' + text_box @user.email.to_s, at: [@x + 10, cursor - 80], size: 18, overflow: :shrink_to_fit + fill_color '000000' + end + stroke_bounds + end end def draw_second_square + move_up 150 if @conference.picture? if 7 * @conference.picture.image[:width] > 12 * @conference.picture.image[:height] image "#{Rails.root}/public#{@conference.picture_url}", at: [@mid_horizontal + 30, cursor], width: 120 From f4a084ec541f503d9807c7a5201208077ea91aa7 Mon Sep 17 00:00:00 2001 From: ViditChitkara Date: Mon, 2 Oct 2017 22:11:23 +0530 Subject: [PATCH 217/237] added byebug_history to gitignore closes #1736 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 75a1bdc6..5c08fcff 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ pickle-email-*.html .env.local docker-compose.env docker-compose.yml +.byebug_history From 72afae6f2f374a48d933ecb98b08462e1b74b0ed Mon Sep 17 00:00:00 2001 From: ViditChitkara Date: Sat, 7 Oct 2017 02:34:46 +0530 Subject: [PATCH 218/237] fixed error in nested comments closes #1738 --- app/views/admin/events/_nested_comments.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/events/_nested_comments.html.haml b/app/views/admin/events/_nested_comments.html.haml index 8ab3cabb..0bfb440c 100644 --- a/app/views/admin/events/_nested_comments.html.haml +++ b/app/views/admin/events/_nested_comments.html.haml @@ -6,9 +6,9 @@ %div %a.pull-right.comment-reply-link{ href: '#' } Reply .comment-reply - = semantic_form_for :comment, url: '#{comment_admin_conference_program_event_path(@conference.short_title, comment.commentable_id)}', method: :post do |f| + = semantic_form_for :comment, url: comment_admin_conference_program_event_path(@conference.short_title, comment.commentable_id), method: :post do |f| = f.input :body - %input{ name: 'parent', type: 'hidden', value: '#{comment.id}' } + %input{ name: 'parent', type: 'hidden', value: comment.id } %input{ name: 'authenticity_token', type: 'hidden', value: '#{form_authenticity_token}' } %button.btn.btn-primary.pull-right{ name: 'button', type: 'submit' } Add Reply - comment.children.each do |child| From 3b27a2a8fbded28ef9d173f932ee294c6aa0bb42 Mon Sep 17 00:00:00 2001 From: rishabhptr Date: Mon, 2 Oct 2017 20:08:30 +0530 Subject: [PATCH 219/237] Added amount check for payments#new --- app/controllers/payments_controller.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/controllers/payments_controller.rb b/app/controllers/payments_controller.rb index 8faebef7..322ed397 100644 --- a/app/controllers/payments_controller.rb +++ b/app/controllers/payments_controller.rb @@ -3,7 +3,6 @@ class PaymentsController < ApplicationController load_and_authorize_resource load_resource :conference, find_by: :short_title authorize_resource :conference_registrations, class: Registration - before_action :check_amount, only: [:new] def index @payments = current_user.payments @@ -11,6 +10,9 @@ class PaymentsController < ApplicationController def new @total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false) + if @total_amount_to_pay.zero? + raise CanCan::AccessDenied.new('Nothing to pay for!', :new, Payment) + end @unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference) end @@ -29,11 +31,6 @@ class PaymentsController < ApplicationController end end - def check_amount - @total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false) - redirect_to root_path if @total_amount_to_pay.zero? - end - private def payment_params From 78eb58c93eb766505dd12319d0502c10b40a811f Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 8 Oct 2017 20:06:06 +0530 Subject: [PATCH 220/237] event export options are grouped --- app/views/admin/events/index.html.haml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/views/admin/events/index.html.haml b/app/views/admin/events/index.html.haml index 50d7acd5..f8b58b63 100644 --- a/app/views/admin/events/index.html.haml +++ b/app/views/admin/events/index.html.haml @@ -9,13 +9,14 @@ =link_to 'Add Event', new_admin_conference_program_event_path(@conference.short_title), class: 'button btn btn-default btn-info' - if can? :read, Event .btn-group - %button.btn.btn-default.dropdown-toggle{ 'data-toggle' => 'dropdown', type: 'button', class: 'btn btn-success' } - Export PDF - %span.caret - %ul.dropdown-menu{ role: 'menu' } - %li= link_to 'All Events', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'all') - %li= link_to 'Confirmed Events', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'confirmed') - %li= link_to 'All Events with Comments', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'all_with_comments') + .btn-group + %button.btn.btn-default.dropdown-toggle{ 'data-toggle' => 'dropdown', type: 'button', class: 'btn btn-success' } + Export PDF + %span.caret + %ul.dropdown-menu{ role: 'menu' } + %li= link_to 'All Events', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'all') + %li= link_to 'Confirmed Events', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'confirmed') + %li= link_to 'All Events with Comments', admin_conference_program_events_path(@conference.short_title, format: :pdf, event_export_option: 'all_with_comments') .btn-group %button.btn.btn-default.dropdown-toggle{ 'data-toggle' => 'dropdown', type: 'button', class: 'btn btn-success' } Export CSV From e9109614ed1fc07ec8fe7c9dd4c8df8e766e8b59 Mon Sep 17 00:00:00 2001 From: Your Name <01namangupta@gmail.com> Date: Mon, 9 Oct 2017 18:24:36 +0530 Subject: [PATCH 221/237] error opening revision history is removed --- .../versions/_object_desc_and_link.html.haml | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index a924a4cf..ad4ac2e9 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -12,10 +12,13 @@ - role = Role.find_by(id: users_role.role_id) if users_role role - if role.name == 'organization_admin' - -# organization_admin belongs to organization and not conferences - - organization = Organization.find(version.conference_id) - = link_if_alive version, role.name, + - if Organization.find_by(id: version.conference_id) + -# organization_admin belongs to organization and not conferences + - organization = Organization.find_by(id: version.conference_id) + = link_if_alive version, role.name, admins_admin_organization_path(organization), organization + - else + (Deleted Organization) - else - conference = Conference.find_by(id: version.conference_id) - conference_short_title = conference.try(:short_title) || current_or_last_object_state('Conference', version.conference_id).try(:short_title) || ' ' @@ -140,10 +143,13 @@ - role = current_or_last_object_state(version.item_type, version.item_id) - role_name = role.try(:name) || PaperTrail::Version.where(item_type: 'Role', item_id: version.item_id).last.changeset[:name].second - if role_name == 'organization_admin' - -# organization_admin belongs to organization and not conferences - - organization = Organization.find(version.conference_id) - = link_if_alive version, role_name, + - if Organization.find_by(id: version.conference_id) + -# organization_admin belongs to organization and not conferences + - organization = Organization.find_by(id: version.conference_id) + = link_if_alive version, role.name, admins_admin_organization_path(organization), organization + - else + (Role Deleted) - else - conference = Conference.find_by(id: version.conference_id) - conference_short_title = conference.try(:short_title) || current_or_last_object_state('Conference', version.conference_id).try(:short_title) || ' ' @@ -224,7 +230,13 @@ - unless %w(Conference Subscription Registration User Organization).include?(version.item_type) - if (version.item_type == 'Role' && role_name == 'organization_admin') || (version.item_type == 'UsersRole' && role.name == 'organization_admin') in organization - = link_to_organization(version.conference_id) + - if Organization.find_by(id: version.conference_id) + -# organization_admin belongs to organization and not conferences + - organization = Organization.find_by(id: version.conference_id) + = link_if_alive version, role.name, + admins_admin_organization_path(organization), organization + - else + (Organization Deleted) - else in conference = link_to_conference(version.conference_id) From 36133a995a611638e3f954125264c97b1ff992df Mon Sep 17 00:00:00 2001 From: Your Name <01namangupta@gmail.com> Date: Mon, 9 Oct 2017 18:37:45 +0530 Subject: [PATCH 222/237] DS_Store file is added into the gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 75a1bdc6..20614643 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ pickle-email-*.html .env.local docker-compose.env docker-compose.yml +.DS_Store From d95a786d9f4aedf6ce7e22fdbcfbd77f780c4171 Mon Sep 17 00:00:00 2001 From: James Mason Date: Tue, 10 Oct 2017 20:23:54 -0700 Subject: [PATCH 223/237] Fix intermittent failures in track tests Boostrap's off-screen rendering was interfering with finding links in the page layout. The included approach should be bulletproof. --- spec/features/tracks_spec.rb | 11 ++++++++--- spec/spec_helper.rb | 10 +++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/spec/features/tracks_spec.rb b/spec/features/tracks_spec.rb index 934f28ba..f753abc2 100644 --- a/spec/features/tracks_spec.rb +++ b/spec/features/tracks_spec.rb @@ -36,8 +36,11 @@ feature Track do expected = expect do visit admin_conference_program_tracks_path(conference_id: conference.short_title) - - click_link 'Delete' + within('#tracks', visible: true) do + page.accept_confirm do + find_link('Delete').click + end + end end expected.to change { Track.count }.by(-1) @@ -53,7 +56,9 @@ feature Track do expected = expect do visit admin_conference_program_tracks_path(conference_id: conference.short_title) - click_link 'Edit' + within('#tracks', visible: true) do + find_link('Edit').trigger('click') + end fill_in 'track_name', with: 'Distribution' fill_in 'track_short_name', with: 'Distribution' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fc56e829..d9283117 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -59,7 +59,7 @@ RSpec.configure do |config| Capybara.javascript_driver = :poltergeist Capybara.register_driver :poltergeist do |app| - Capybara::Poltergeist::Driver.new(app, phantomjs: Phantomjs.path, js_errors: false) + Capybara::Poltergeist::Driver.new(app, phantomjs: Phantomjs.path, js_errors: false, window_size: [1920, 1080]) end # Includes helpers and connect them to specific types of tests @@ -82,6 +82,14 @@ RSpec.configure do |config| # Types of tests (controller, feature, model) will # be inferred from subfolder name config.infer_spec_type_from_file_location! + + # Enable this if you like to see what you're debugging + # config.after(:example) do |example| + # if example.exception + # save_and_open_screenshot + # save_and_open_page + # end + # end end OmniAuth.config.test_mode = true From fc48769abb78f6470382e551719bf22c30c65ce1 Mon Sep 17 00:00:00 2001 From: Akshit Ahluwalia Date: Thu, 12 Oct 2017 04:40:57 +0530 Subject: [PATCH 224/237] fixed hakiri xss warnings. Fixed Hakiri XSS Warnings. --- app/views/conferences/_venue.html.haml | 2 +- app/views/conferences/_venue_map.html.haml | 6 +++--- app/views/conferences/show.html.haml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/conferences/_venue.html.haml b/app/views/conferences/_venue.html.haml index 62af90c7..4436b0fe 100644 --- a/app/views/conferences/_venue.html.haml +++ b/app/views/conferences/_venue.html.haml @@ -32,4 +32,4 @@ = @conference.venue.country_name - if @conference.venue.website %br - =link_to @conference.venue.website, @conference.venue.website + =link_to(h(@conference.venue.website), h(@conference.venue.website)).html_safe diff --git a/app/views/conferences/_venue_map.html.haml b/app/views/conferences/_venue_map.html.haml index b58b3053..717069d5 100644 --- a/app/views/conferences/_venue_map.html.haml +++ b/app/views/conferences/_venue_map.html.haml @@ -3,15 +3,15 @@ - content_for(:script_body) do :javascript // create a map in the "map" div, set the view to a given place and zoom - var map = L.map('map', { scrollWheelZoom: false }).setView([#{@conference.venue.latitude}, #{@conference.venue.longitude}], 11); + var map = L.map('map', { scrollWheelZoom: false }).setView([#{h(@conference.venue.latitude)}, #{h(@conference.venue.longitude)}], 11); // add an OpenStreetMap tile layer L.tileLayer('//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox', maxZoom: 18 }).addTo(map); // add a marker in the given location, attach some popup content to it and open the popup - L.marker([#{@conference.venue.latitude}, #{@conference.venue.longitude}]).addTo(map) - .bindPopup("#{popup}") + L.marker([#{h(@conference.venue.latitude)}, #{h(@conference.venue.longitude)}]).addTo(map) + .bindPopup("#{h(popup)}") .openPopup(); // Turn scrollwheel on when user clicks map.on('focus', function(e) { diff --git a/app/views/conferences/show.html.haml b/app/views/conferences/show.html.haml index f94b8ee4..dd6b2d62 100644 --- a/app/views/conferences/show.html.haml +++ b/app/views/conferences/show.html.haml @@ -82,7 +82,7 @@ - content_for :script_head do :javascript - var triangle_tcs = tinycolor("#{@conference.color}").monochromatic(); + var triangle_tcs = tinycolor("#{h(@conference.color)}").monochromatic(); var triangle_colors = triangle_tcs.map(function(t) { return t.toHexString(); }); $(function () { $(document).ready(function() { From 49503444e119f016f2905640fb668e10e753825c Mon Sep 17 00:00:00 2001 From: rishabhptr Date: Thu, 12 Oct 2017 21:17:23 +0530 Subject: [PATCH 225/237] Fixed roles link in revision_history --- app/views/admin/versions/_object_desc_and_link.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index a924a4cf..8c717900 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -19,7 +19,7 @@ - else - conference = Conference.find_by(id: version.conference_id) - conference_short_title = conference.try(:short_title) || current_or_last_object_state('Conference', version.conference_id).try(:short_title) || ' ' - = link_if_alive version, role.try(:name), admin_conference_role_path(role.try(:name) || ' ', conference_short_title), conference + = link_if_alive version, role.try(:name), admin_conference_role_path(conference_short_title,role.try(:name) || ' '), conference = version.event == 'create' ? 'to' : 'from' user From f2b5c2627cb0f3f1b9690c6102e504ee2126fc18 Mon Sep 17 00:00:00 2001 From: James Mason Date: Tue, 10 Oct 2017 10:34:16 -0700 Subject: [PATCH 226/237] Require a version of nokogiri with known vulnerabilities resolved re: https://hakiri.io/github/openSUSE/osem/master/78eb58c93eb766505dd12319d0502c10b40a811f/warnings/b532fbd10b687d --- Gemfile | 5 +++++ Gemfile.lock | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 7f25aa46..22dc5f6e 100644 --- a/Gemfile +++ b/Gemfile @@ -200,6 +200,11 @@ gem 'sprockets-rails' # for multiple speakers select on proposal/event forms gem 'selectize-rails' +# Nokogiri < 1.8.1 is subject to: +# CVE-2017-0663, CVE-2017-7375, CVE-2017-7376, CVE-2017-9047, CVE-2017-9048, +# CVE-2017-9049, CVE-2017-9050 +gem 'nokogiri', '>= 1.8.1' + # Use guard and spring for testing in development group :development do # to launch specs when files are modified diff --git a/Gemfile.lock b/Gemfile.lock index c6b4faa8..dc730e82 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -270,7 +270,7 @@ GEM open4 (~> 1.3.4) rake mini_magick (4.5.1) - mini_portile2 (2.2.0) + mini_portile2 (2.3.0) minitest (5.10.2) momentjs-rails (2.8.1) railties (>= 3.1) @@ -290,8 +290,8 @@ GEM mysql2 (0.4.9) nenv (0.3.0) netrc (0.11.0) - nokogiri (1.8.0) - mini_portile2 (~> 2.2.0) + nokogiri (1.8.1) + mini_portile2 (~> 2.3.0) notiffany (0.1.1) nenv (~> 0.1) shellany (~> 0.0) @@ -609,6 +609,7 @@ DEPENDENCIES mini_magick money-rails mysql2 + nokogiri (>= 1.8.1) omniauth omniauth-facebook omniauth-github @@ -662,4 +663,4 @@ DEPENDENCIES whenever BUNDLED WITH - 1.15.1 + 1.15.4 From fc64542202e370fad180f68508d7151ed80d5d70 Mon Sep 17 00:00:00 2001 From: James Mason Date: Thu, 12 Oct 2017 14:06:02 -0700 Subject: [PATCH 227/237] Stabilizing a randomly failing test --- spec/features/sponsor_spec.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/features/sponsor_spec.rb b/spec/features/sponsor_spec.rb index c6b5009e..b12ee90d 100644 --- a/spec/features/sponsor_spec.rb +++ b/spec/features/sponsor_spec.rb @@ -36,7 +36,14 @@ feature Sponsor do end # Remove sponsor - click_link 'Delete' + visit admin_conference_sponsors_path( + conference_id: conference.short_title + ) + within('table#sponsors') do + page.accept_confirm do + click_link 'Delete' + end + end expect(flash).to eq('Sponsor successfully deleted.') expect(page).to_not have_selector('table#sponsors') end From 33bfb3d3c2383e0ed34b0317c20ce5258d923cfb Mon Sep 17 00:00:00 2001 From: rahul Date: Sat, 14 Oct 2017 20:41:41 +0530 Subject: [PATCH 228/237] Add link to venue when venue is not set Link to create rooms is removed from schedules#show when venue is not set as creating room without venue will show error Closes https://github.com/openSUSE/osem/issues/1729 --- app/views/admin/schedules/show.html.haml | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/app/views/admin/schedules/show.html.haml b/app/views/admin/schedules/show.html.haml index 9009fcbb..258b4d87 100644 --- a/app/views/admin/schedules/show.html.haml +++ b/app/views/admin/schedules/show.html.haml @@ -40,11 +40,23 @@ .tab-pane{ class: "#{ (@dates.first == date) ? 'active' : '' }", id: "#{date}" } = render partial: 'day_tab', locals: { date: date } - else - .h3 - No Rooms! - %small - = link_to 'Create rooms', admin_conference_venue_rooms_path - before creating the schedule. + - if @venue.try(:rooms).present? + .text-right + - if can? :create, @program.schedules.new + = link_to 'Add Schedule', admin_conference_schedules_path(@conference.short_title), + method: :post, class: 'btn btn-primary' + - elsif @venue + .h3 + No Rooms! + %small + = link_to 'Create rooms', admin_conference_venue_rooms_path + before creating the schedule. + - else + .h3 + No Venue! + %small + = link_to 'Create a venue with rooms', new_admin_conference_venue_path + before creating the schedule. :javascript $(document).ready( function() { From 3f3cdef52002884d005ab5749dd1be5e48754f6a Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 25 Sep 2017 00:34:53 +0530 Subject: [PATCH 229/237] Fix decimal limit of total to 2 Decimal limit is fixed to 2 as earlier at some values the decimal limit were crossing this limit --- app/assets/javascripts/osem-tickets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/osem-tickets.js b/app/assets/javascripts/osem-tickets.js index 51881055..3f559c38 100644 --- a/app/assets/javascripts/osem-tickets.js +++ b/app/assets/javascripts/osem-tickets.js @@ -11,7 +11,7 @@ function update_price($this){ $('.total_row').each(function( index ) { total += parseFloat($(this).text()); }); - $('#total_price').text(total); + $('#total_price').text(total.toFixed(2)); } $( document ).ready(function() { From b761e83b45e51e34f5b676504863fe3db04fc5b2 Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 25 Sep 2017 00:38:20 +0530 Subject: [PATCH 230/237] Add amount paid Amount paid colum is added to ticket purchase to keep the record of money paid by the user. It is added to physical_ticket#index to show admin, price paid by each user for each ticket. --- app/models/ticket_purchase.rb | 3 ++- .../_physical_ticket.html.haml | 16 ++++++++++++++++ .../admin/physical_tickets/index.html.haml | 18 +++--------------- ...0528_add_amount_paid_to_ticket_purchases.rb | 5 +++++ db/schema.rb | 3 ++- 5 files changed, 28 insertions(+), 17 deletions(-) create mode 100644 app/views/admin/physical_tickets/_physical_ticket.html.haml create mode 100644 db/migrate/20170924190528_add_amount_paid_to_ticket_purchases.rb diff --git a/app/models/ticket_purchase.rb b/app/models/ticket_purchase.rb index 97fa9957..71b44d18 100644 --- a/app/models/ticket_purchase.rb +++ b/app/models/ticket_purchase.rb @@ -52,7 +52,8 @@ class TicketPurchase < ActiveRecord::Base purchase = new(ticket_id: ticket.id, conference_id: conference.id, user_id: user.id, - quantity: quantity) + quantity: quantity, + amount_paid: ticket.price) purchase.pay(nil) if ticket.price_cents.zero? end purchase diff --git a/app/views/admin/physical_tickets/_physical_ticket.html.haml b/app/views/admin/physical_tickets/_physical_ticket.html.haml new file mode 100644 index 00000000..ff4dd185 --- /dev/null +++ b/app/views/admin/physical_tickets/_physical_ticket.html.haml @@ -0,0 +1,16 @@ +%tr + %td= physical_ticket.id + %td= physical_ticket.ticket.title + %td= physical_ticket.user.email + %td= humanized_money_with_symbol physical_ticket.ticket_purchase.amount_paid + %td + .btn-group + = link_to 'Show', + conference_physical_ticket_path(conference.short_title, + physical_ticket.token), + class: 'btn btn-primary' + = link_to 'Generate PDF', + conference_physical_ticket_path(conference.short_title, + physical_ticket.token, + format: :pdf), + class: 'button btn btn-default btn-info' diff --git a/app/views/admin/physical_tickets/index.html.haml b/app/views/admin/physical_tickets/index.html.haml index 96c5911f..8b26a965 100644 --- a/app/views/admin/physical_tickets/index.html.haml +++ b/app/views/admin/physical_tickets/index.html.haml @@ -21,23 +21,11 @@ %th ID %th Type %th User + %th Paid %th Actions %tbody - @physical_tickets.each do |physical_ticket| - %tr - %td= physical_ticket.id - %td= physical_ticket.ticket.title - %td= physical_ticket.user.email - %td - .btn-group - = link_to 'Show', - conference_physical_ticket_path(@conference.short_title, - physical_ticket.token), - class: 'btn btn-primary' - = link_to 'Generate PDF', - conference_physical_ticket_path(@conference.short_title, - physical_ticket.token, - format: :pdf), - class: 'button btn btn-default btn-info' + = render "physical_ticket", physical_ticket: physical_ticket, + conference: @conference - else %h5 No Tickets sold! diff --git a/db/migrate/20170924190528_add_amount_paid_to_ticket_purchases.rb b/db/migrate/20170924190528_add_amount_paid_to_ticket_purchases.rb new file mode 100644 index 00000000..5e732d4c --- /dev/null +++ b/db/migrate/20170924190528_add_amount_paid_to_ticket_purchases.rb @@ -0,0 +1,5 @@ +class AddAmountPaidToTicketPurchases < ActiveRecord::Migration + def change + add_column :ticket_purchases, :amount_paid, :float, default: 0 + end +end diff --git a/db/schema.rb b/db/schema.rb index 82f5923d..6c6531c1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170816203325) do +ActiveRecord::Schema.define(version: 20170924190528) do create_table "ahoy_events", force: :cascade do |t| t.uuid "visit_id", limit: 16 @@ -504,6 +504,7 @@ ActiveRecord::Schema.define(version: 20170816203325) do t.integer "user_id" t.integer "payment_id" t.integer "week" + t.float "amount_paid" end create_table "ticket_scannings", force: :cascade do |t| From 0d70832f5bd6d5c60bf0bd7049c718fe00c17433 Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 25 Sep 2017 00:52:13 +0530 Subject: [PATCH 231/237] Add total amount spent by user User can see the total amount that he paid for the tickets and total amount spent by him on each ticket --- app/controllers/conference_registrations_controller.rb | 3 ++- app/models/ticket.rb | 5 +++++ app/views/conference_registrations/show.html.haml | 2 +- spec/controllers/conference_registration_controller_spec.rb | 4 ++-- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/controllers/conference_registrations_controller.rb b/app/controllers/conference_registrations_controller.rb index c2037318..e8809b28 100644 --- a/app/controllers/conference_registrations_controller.rb +++ b/app/controllers/conference_registrations_controller.rb @@ -27,8 +27,9 @@ class ConferenceRegistrationsController < ApplicationController end def show - @total_price = Ticket.total_price(@conference, current_user, paid: true) + @total_price = Ticket.total_price_user(@conference, current_user, paid: true) @tickets = current_user.ticket_purchases.by_conference(@conference).paid + @total_price_per_ticket = @tickets.group(:ticket_id).sum('amount_paid * quantity') @ticket_payments = @tickets.group_by(&:ticket_id) @total_quantity = @tickets.group(:ticket_id).sum(:quantity) end diff --git a/app/models/ticket.rb b/app/models/ticket.rb index ce527472..ac1d1927 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -55,6 +55,11 @@ class Ticket < ActiveRecord::Base result ? result : Money.new(0, 'USD') end + def self.total_price_user(conference, user, paid: false) + tickets = TicketPurchase.where(conference: conference, user: user, paid: paid) + tickets.inject(0){ |sum, ticket| sum + (ticket.amount_paid * ticket.quantity) } + end + def tickets_sold ticket_purchases.paid.sum(:quantity) end diff --git a/app/views/conference_registrations/show.html.haml b/app/views/conference_registrations/show.html.haml index 83d6d89c..a50cf198 100644 --- a/app/views/conference_registrations/show.html.haml +++ b/app/views/conference_registrations/show.html.haml @@ -101,7 +101,7 @@ = word_pluralize(@total_quantity[ticket_id], 'Ticket') for = tickets.first.price.symbol - = humanized_money tickets.first.price + = humanized_money @total_price_per_ticket[ticket_id] %br - if @tickets.any? = link_to 'Get more tickets', conference_tickets_path(@conference.short_title), class: "btn btn-default" diff --git a/spec/controllers/conference_registration_controller_spec.rb b/spec/controllers/conference_registration_controller_spec.rb index 9afaaed8..a6f1503c 100644 --- a/spec/controllers/conference_registration_controller_spec.rb +++ b/spec/controllers/conference_registration_controller_spec.rb @@ -252,7 +252,7 @@ describe ConferenceRegistrationsController, type: :controller do end it 'does not assign price of purchased tickets to total_price and purchased tickets to tickets without payment' do - expect(assigns(:total_price)).to eq Money.new(0, 'USD') + expect(assigns(:total_price)).to eq 0 end end @@ -262,7 +262,7 @@ describe ConferenceRegistrationsController, type: :controller do end it 'assigns 0 dollars to total_price and empty array to tickets variables' do - expect(assigns(:total_price)).to eq Money.new(0, 'USD') + expect(assigns(:total_price)).to eq 0 expect(assigns(:tickets)).to match_array [] end end From 03c9f7deb116d673ca3cf0662850df2a33b9b409 Mon Sep 17 00:00:00 2001 From: rahul Date: Mon, 25 Sep 2017 00:55:09 +0530 Subject: [PATCH 232/237] Add turnover for admin Admin can see the turnover amount for each ticket type. --- app/models/conference.rb | 2 +- app/models/ticket.rb | 9 +++++---- app/views/admin/tickets/index.html.haml | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/models/conference.rb b/app/models/conference.rb index 034e755b..c56161f2 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -496,7 +496,7 @@ class Conference < ActiveRecord::Base if tickets && ticket_purchases tickets.each do |ticket| result[ticket.title] = { - 'value' => ApplicationController.helpers.humanized_money(ticket.tickets_turnover).delete(',').to_i, + 'value' => ApplicationController.helpers.humanized_money(ticket.tickets_turnover_total(ticket.id)).delete(',').to_i, 'color' => "\##{Digest::MD5.hexdigest(ticket.title)[0..5]}" } end diff --git a/app/models/ticket.rb b/app/models/ticket.rb index ac1d1927..13646c9f 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -60,12 +60,13 @@ class Ticket < ActiveRecord::Base tickets.inject(0){ |sum, ticket| sum + (ticket.amount_paid * ticket.quantity) } end - def tickets_sold - ticket_purchases.paid.sum(:quantity) + def tickets_turnover_total(id) + tickets = TicketPurchase.where(ticket_id: id) + tickets.inject(0){ |sum, ticket| sum + (ticket.amount_paid * ticket.quantity) } end - def tickets_turnover - tickets_sold * price + def tickets_sold + ticket_purchases.paid.sum(:quantity) end private diff --git a/app/views/admin/tickets/index.html.haml b/app/views/admin/tickets/index.html.haml index 42154ae7..71698bb2 100644 --- a/app/views/admin/tickets/index.html.haml +++ b/app/views/admin/tickets/index.html.haml @@ -27,7 +27,7 @@ %td = ticket.tickets_sold %td - = humanized_money_with_symbol ticket.tickets_turnover + = humanized_money_with_symbol ticket.tickets_turnover_total(ticket.id) %td = ticket.registration_ticket? ? 'Yes' : 'No' %td From 8ddcd695f02bd6ad23058bdce437306e72e155bb Mon Sep 17 00:00:00 2001 From: James Mason Date: Wed, 11 Oct 2017 16:47:51 -0700 Subject: [PATCH 233/237] Add vendor picture interface; include in splash Vendor has a picture atrribute, and was displayed in one form of the splashpage, but it wasn't exposed in the vendor editing form, nor was it included in the "map view" on the splash page. Additionally, the map popup was rendered inline. This commit: * Adds a from input for editing Venue#picture, consistent with other form elements * Displays the picture on the splash page in either style (map or static) * Moves the splash page map popup from inline HTML to it's own partial --- app/views/admin/venues/_form.html.haml | 6 ++++++ app/views/conferences/_venue_map.html.haml | 5 ++--- app/views/conferences/_venue_map_marker.html.haml | 13 +++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 app/views/conferences/_venue_map_marker.html.haml diff --git a/app/views/admin/venues/_form.html.haml b/app/views/admin/venues/_form.html.haml index 7dd08a2c..6674305b 100644 --- a/app/views/admin/venues/_form.html.haml +++ b/app/views/admin/venues/_form.html.haml @@ -15,6 +15,12 @@ = semantic_form_for(@venue, url: admin_conference_venue_path(@conference.short_title)) do |f| = f.inputs :name, :website = f.input :description, input_html: { rows: 5, cols: 20, data: { provide: 'markdown-editable' } }, hint: markdown_hint + = f.label 'Venue Logo' + %br + - if @venue.picture? + = image_tag @venue.picture.thumb.url + = f.input :picture, label: false, hint: 'This will be displayed on the venue are of the splash page.' + = f.hidden_field :picture_cache = f.inputs :street, :postalcode, :city, :country, :latitude, :longitude = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } diff --git a/app/views/conferences/_venue_map.html.haml b/app/views/conferences/_venue_map.html.haml index 717069d5..9f34117f 100644 --- a/app/views/conferences/_venue_map.html.haml +++ b/app/views/conferences/_venue_map.html.haml @@ -1,5 +1,4 @@ #map{style: "height: 500px;" } -- popup = "

#{@conference.venue.name}


#{@conference.venue.street}
#{@conference.venue.city}
#{@conference.venue.country_name}" - content_for(:script_body) do :javascript // create a map in the "map" div, set the view to a given place and zoom @@ -10,8 +9,8 @@ maxZoom: 18 }).addTo(map); // add a marker in the given location, attach some popup content to it and open the popup - L.marker([#{h(@conference.venue.latitude)}, #{h(@conference.venue.longitude)}]).addTo(map) - .bindPopup("#{h(popup)}") + L.marker([#{h @conference.venue.latitude}, #{h @conference.venue.longitude}]).addTo(map) + .bindPopup("#{escape_javascript(render '/conferences/venue_map_marker', venue: @conference.venue)}") .openPopup(); // Turn scrollwheel on when user clicks map.on('focus', function(e) { diff --git a/app/views/conferences/_venue_map_marker.html.haml b/app/views/conferences/_venue_map_marker.html.haml new file mode 100644 index 00000000..c5f78345 --- /dev/null +++ b/app/views/conferences/_venue_map_marker.html.haml @@ -0,0 +1,13 @@ +- if venue.picture? + = image_tag venue.picture.thumb.url, + alt: venue.name, + class: 'img-responsive pull-right' +%h3= venue.name +%p + = venue.street + %br + = venue.city + %br + = venue.country_name +- if venue.website + %p.text-center.clearfix= sanitize(link_to venue.website, venue.website) From e96a5338e2030b4094152d103b9f744a043bec09 Mon Sep 17 00:00:00 2001 From: James Mason Date: Fri, 13 Oct 2017 10:39:10 -0700 Subject: [PATCH 234/237] Attempting to stabilize another flaky test. --- app/views/proposals/index.html.haml | 2 +- spec/features/versions_spec.rb | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/views/proposals/index.html.haml b/app/views/proposals/index.html.haml index 06154d47..5ed332dc 100644 --- a/app/views/proposals/index.html.haml +++ b/app/views/proposals/index.html.haml @@ -55,7 +55,7 @@ %p Knowing the number of visitors for the conference helps the organizers plan better. - %table.table.table-striped + %table.table.table-striped#events - @events.each do |event| %tr %td{style: "padding:20px 8px 20px 8px;"} diff --git a/spec/features/versions_spec.rb b/spec/features/versions_spec.rb index 0db2d1f9..1bf114a0 100644 --- a/spec/features/versions_spec.rb +++ b/spec/features/versions_spec.rb @@ -193,7 +193,9 @@ feature 'Version' do click_link 'Reject event' visit conference_program_proposals_path(conference_id: conference.short_title) - click_link 'Re-Submit' + within('#events') do + click_link 'Re-Submit' + end visit admin_conference_program_events_path(conference.short_title) click_button 'New' From f44e6e5ca5d683de4678c395d0c9edca8a86c342 Mon Sep 17 00:00:00 2001 From: ViditChitkara Date: Fri, 13 Oct 2017 22:30:08 +0530 Subject: [PATCH 235/237] fixed openid username closes #1747 minor changes for styling issue --- app/controllers/users/omniauth_callbacks_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index cf6eb6a8..ed7ce011 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -11,13 +11,13 @@ module Users def handle(provider) auth_hash = request.env['omniauth.auth'] - uid = auth_hash[:uid] + username = auth_hash.info.email.split('@')[0] openid = Openid.find_for_oauth(auth_hash) # Get or create openid # If openid exists and is associated with a user, sign in with associated user, # even if the email of the associated user and the email of the provided openid are different unless (user = openid.user) user = User.find_for_auth(auth_hash, current_user) # Get or create users - user.username = "#{uid}@#{provider}" if user.username.blank? + user.username = "#{username}@#{provider}" if user.username.blank? end begin From 3d8b32d90bb6aa55fe54f8519097f2ec9f7e4dfc Mon Sep 17 00:00:00 2001 From: Udit Jindal Date: Thu, 19 Oct 2017 01:41:40 +0530 Subject: [PATCH 236/237] fixed doubly typed route --- config/routes.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 0d7e7aec..fcee2564 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -165,7 +165,6 @@ Osem::Application.routes.draw do member do get :registrations patch '/withdraw' => 'proposals#withdraw' - get :registrations patch '/confirm' => 'proposals#confirm' patch '/restart' => 'proposals#restart' end From aaa34c64afa1754cbd7dc18ab65461b0aab0d624 Mon Sep 17 00:00:00 2001 From: Naman Gupta <01namangupta@gmail.com> Date: Fri, 20 Oct 2017 23:38:59 +0530 Subject: [PATCH 237/237] link is corrected --- app/views/admin/versions/_object_desc_and_link.html.haml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/admin/versions/_object_desc_and_link.html.haml b/app/views/admin/versions/_object_desc_and_link.html.haml index 1651fed4..4852a50f 100644 --- a/app/views/admin/versions/_object_desc_and_link.html.haml +++ b/app/views/admin/versions/_object_desc_and_link.html.haml @@ -233,8 +233,7 @@ - if Organization.find_by(id: version.conference_id) -# organization_admin belongs to organization and not conferences - organization = Organization.find_by(id: version.conference_id) - = link_if_alive version, role.name, - admins_admin_organization_path(organization), organization + = link_to_organization(version.conference_id) - else (Organization Deleted) - else