diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index a4542c19..e4754e1e 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -300,7 +300,7 @@ Lint/UnusedBlockArgument: # Offense count: 136 Metrics/AbcSize: - Max: 86 + Max: 98 # Offense count: 258 # Configuration parameters: CountComments, ExcludedMethods. @@ -320,7 +320,7 @@ Metrics/LineLength: # Offense count: 133 # Configuration parameters: CountComments. Metrics/MethodLength: - Max: 56 + Max: 63 # Offense count: 4 # Configuration parameters: CountComments. diff --git a/Gemfile b/Gemfile index e624a1f7..9be883a3 100644 --- a/Gemfile +++ b/Gemfile @@ -209,6 +209,9 @@ gem 'sprockets-rails' # for multiple speakers select on proposal/event forms gem 'selectize-rails' +# For collecting performance data +gem 'skylight' + # 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 diff --git a/Gemfile.lock b/Gemfile.lock index 0f64b0e8..9e07eb20 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -297,7 +297,7 @@ GEM nenv (0.3.0) netrc (0.11.0) nio4r (2.1.0) - nokogiri (1.8.1) + nokogiri (1.8.2) mini_portile2 (~> 2.3.0) notiffany (0.1.1) nenv (~> 0.1) @@ -505,6 +505,8 @@ GEM simplecov-html (~> 0.10.0) simplecov-html (0.10.0) sixarm_ruby_unaccent (1.1.1) + skylight (1.5.1) + activesupport (>= 3.0.0) slop (3.6.0) sort_alphabetical (1.0.2) unicode_utils (>= 1.2.2) @@ -668,6 +670,7 @@ DEPENDENCIES sass-rails (>= 4.0.2) selectize-rails shoulda-matchers + skylight spring-commands-rspec sprockets-rails sqlite3 diff --git a/INSTALL.md b/INSTALL.md index ea47fd93..f07b198f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -78,35 +78,6 @@ You should not directly expose the web server port unless you have a good reason ## Configure There are a couple of environment variables you can set to configure OSEM. Check out the *dotenv.example* file. -| Variable | Content | Purpose | -|---------- |--------- |--------- | -| OSEM_NAME | openSUSE Events | The name of your page | -| OSEM_HOSTNAME | events.opensuse.org | The host this OSEM instance runs on | -| OSEM_EMAIL_ADDRESS | events@opensuse.org | The address OSEM uses for sending mails | -| OSEM_ICHAIN_ENABLED | true/false | Enable the usage of [devise_ichain_authenticatable](https://github.com/openSUSE/devise_ichain_authenticatable) | -| OSEM_TRANSIFEX_APIKEY | *string* | Use this api key for [transifex](https://www.transifex.com/). See TRANSLATION.md for details. | -| OSEM_ERRBIT_HOST | errbit.opensuse.org | The [errbit](https://github.com/errbit/errbit) host to post exceptions to | -| OSEM_ERRBIT_APIKEY | *string* | The api key for the errbit host | -| OSEM_FACTORY_LINT | *boolean* (true/false) | Setting this to false will disable linting of factories before running spec -| OSEM_GOOGLE_KEY | *string* | OMNIAUTH Developer Key for GOOGLE -| OSEM_GOOGLE_SECRET | *string* | OMNIAUTH Developer Secret for GOOGLE -| OSEM_FACEBOOK_KEY | *string* | OMNIAUTH Developer Key for Facebook -| OSEM_FACEBOOK_SECRET | *string* | OMNIAUTH Developer Secret for Facebook -| OSEM_GITHUB_KEY | *string* | OMNIAUTH Developer Key for GitHub -| OSEM_GITHUB_SECRET | *string* | OMNIAUTH Developer Secret for GitHub -| OSEM_SUSE_KEY | *string* | OMNIAUTH Developer Key for openSUSE -| OSEM_SUSE_SECRET | *string* | OMNIAUTH Developer Secret for openSUSE -| OSEM_SMTP_ADDRESS | smtp.opensuse.org | The smtp server to use -| OSEM_SMTP_PORT | *int* | The port on the smtp server -| OSEM_SMTP_USERNAME | *string* | The user for the smtp server -| OSEM_SMTP_PASSWORD | *string* | The password for the smtp server -| OSEM_SMTP_AUTHENTICATION | plain, login or cram_md5 | The auth method for the smtp server -| OSEM_SMTP_DOMAIN | opensuse.org | The HELO domain for the smtp server -| CLOUDINARY_URL | *string* | Configure your cloudinary.com cloud name and api key/secret -| STRIPE_PUBLISHABLE_KEY | *string* | Publishable Key for Stripe Gateway -| STRIPE_SECRET_KEY | *string* | Secret Key for Stripe Gateway -| OSEM_REDIS_URL | *string* | Redis server URL e.g. redis://localhost:6379/1 - ### Online Ticket Payments We use [Stripe](https://stripe.com) for accepting your ticket payments securely over the web. Our application uses iFrame for accepting your user's payment details without storing them, making the application PCI SAQ-A Compliant. @@ -121,8 +92,10 @@ If you would like to resize exisiting logos in your OSEM installation you can do ```shell $ bundle exec rake logo:reprocess ``` +### Ruby +OSEM is using Ruby version 2.4 -### openID +## openID In order to use [openID](http://openid.net/) logins for your OSEM installation you need to register your application with the providers ([Google](https://code.google.com/apis/console#:access), [GitHub](https://github.com/settings/applications/new) or [Facebook](https://developers.facebook.com/)) and enter their API keys in the environment variables found in your *.env* file(s). ## Recurring Jobs @@ -130,3 +103,8 @@ Open a separate terminal and go into the directory where the rails app is presen ``` bundle exec rake jobs:work ``` + +## Performance +If you are experiencing performance issues (or just curious), you may be able to [apply a free Skylight account](https://www.skylight.io/oss). +Once you have your account setup, simply set `SKYLIGHT_AUTHENTICATION` and `SKYLIGHT_PUBLIC_DASHBOARD_URL` in your `.env` file. +If you are reporting a performance issue or submiting a performance patch, it would be helpful (but not required) to link to the relevant Skylight data. diff --git a/app/assets/stylesheets/osem.scss b/app/assets/stylesheets/osem.scss index bbcabc44..7d0d0519 100644 --- a/app/assets/stylesheets/osem.scss +++ b/app/assets/stylesheets/osem.scss @@ -115,3 +115,9 @@ p.comment-body { float: right; } } + +/* omniauth btn grp */ +#openid-btn-grp{ + display: flex; + justify-content: center; +} \ No newline at end of file diff --git a/app/controllers/admin/commercials_controller.rb b/app/controllers/admin/commercials_controller.rb index 3c694246..1bc587ce 100644 --- a/app/controllers/admin/commercials_controller.rb +++ b/app/controllers/admin/commercials_controller.rb @@ -57,7 +57,9 @@ module Admin def mass_upload errors = Commercial.read_file(params[:file]) if params[:file] - if errors.all? { |_k, v| v.blank? } + if !params[:file] + flash[:error] = 'Empty file detected while adding commercials to Event' + elsif errors.all? { |_k, v| v.blank? } flash[:notice] = 'Successfully added commercials.' else errors_text = '' diff --git a/app/controllers/admin/conferences_controller.rb b/app/controllers/admin/conferences_controller.rb index 921a23d1..6342f09f 100644 --- a/app/controllers/admin/conferences_controller.rb +++ b/app/controllers/admin/conferences_controller.rb @@ -20,6 +20,10 @@ module Admin @total_submissions = Event.count @new_submissions = Event.where('created_at > ?', current_user.last_sign_in_at).count + @total_withdrawn = Event.where(state: :withdrawn).count + @new_withdrawn = Event + .where('state = ? and created_at > ?', 'withdrawn', current_user.last_sign_in_at).count + @active_conferences = Conference.get_active_conferences_for_dashboard # pending or the last two @deactive_conferences = Conference .get_conferences_without_active_for_dashboard(@active_conferences) # conferences without active @@ -116,13 +120,19 @@ module Admin @total_reg = @conference.registrations.count @new_reg = @conference.registrations.where('created_at > ?', current_user.last_sign_in_at).count - @total_submissions = @program.events.count - @new_submissions = @program.events + @all_events = @program.events + + @total_submissions = @all_events.count + @new_submissions = @all_events .where('created_at > ?', current_user.last_sign_in_at).count @program_length = @conference.current_program_hours @new_program_length = @conference.new_program_hours(current_user.last_sign_in_at) + @total_withdrawn = @all_events.where(state: :withdrawn).count + @new_withdrawn = @all_events + .where('state = "withdrawn" and created_at > ?', current_user.last_sign_in_at).count + # Step by step list @conference_progress = @conference.get_status @@ -162,13 +172,17 @@ module Admin # Doughnut charts @event_type_distribution = @conference.event_type_distribution @event_type_distribution_confirmed = @conference.event_type_distribution(:confirmed) + @event_type_distribution_withdrawn = @conference.event_type_distribution(:withdrawn) @difficulty_levels_distribution = @conference.difficulty_levels_distribution @difficulty_levels_distribution_confirmed = @conference .difficulty_levels_distribution(:confirmed) + @difficulty_levels_distribution_withdrawn = @conference + .difficulty_levels_distribution(:withdrawn) @tracks_distribution = @conference.tracks_distribution @tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed) + @tracks_distribution_withdrawn = @conference.tracks_distribution(:withdrawn) # Recent actions information @recent_events = @conference.program.events.limit(5).order(created_at: :desc) diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb index 5e907cea..1c9b37b3 100644 --- a/app/controllers/conferences_controller.rb +++ b/app/controllers/conferences_controller.rb @@ -55,6 +55,7 @@ class ConferencesController < ApplicationController @sponsorship_levels = @conference.sponsorship_levels.eager_load( :sponsors ).order('sponsorship_levels.position ASC', 'sponsors.name') + @sponsors = @conference.sponsors end end diff --git a/app/controllers/physical_tickets_controller.rb b/app/controllers/physical_tickets_controller.rb index 2f6f18ec..c3cc40cb 100644 --- a/app/controllers/physical_tickets_controller.rb +++ b/app/controllers/physical_tickets_controller.rb @@ -10,7 +10,7 @@ class PhysicalTicketsController < ApplicationController end def show - @file_name = "ticket_for_#{@conference.short_title}" + @file_name = "ticket_for_#{@conference.short_title}.pdf" @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) diff --git a/app/models/ability.rb b/app/models/ability.rb index b833b6f4..d6b3ef21 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -66,7 +66,13 @@ class Ability can [:new, :create], Registration do |registration| conference = registration.conference - conference.registration_open? && !conference.registration_limit_exceeded? || conference.program.speakers.confirmed.include?(user) + if conference.user_registered? user + false + elsif conference.program.speakers.confirmed.include?(user) && conference.registration_period + true + else + conference.registration_open? && !conference.registration_limit_exceeded? + end end can :index, Organization diff --git a/app/models/conference.rb b/app/models/conference.rb index 03402652..81e9ec32 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -1029,7 +1029,7 @@ class Conference < ApplicationRecord # * +hash+ -> object_type => {color, value} def calculate_event_distribution(group_by_id, association_symbol, state = nil) grouped = if state - program.events.select(group_by_id).where('state = ?', 'confirmed').group(group_by_id) + program.events.select(group_by_id).where('state = ?', state).group(group_by_id) else program.events.select(group_by_id).group(group_by_id) end diff --git a/app/models/organization.rb b/app/models/organization.rb index 21d0989b..1e3974de 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -7,7 +7,11 @@ class Organization < ApplicationRecord after_create :create_roles - validates :name, presence: true + validates :name, + uniqueness: { + case_sensitive: false + }, + presence: true mount_uploader :picture, PictureUploader, mount_on: :picture diff --git a/app/models/registration.rb b/app/models/registration.rb index 1198324e..45d2d55b 100644 --- a/app/models/registration.rb +++ b/app/models/registration.rb @@ -1,4 +1,5 @@ class Registration < ApplicationRecord + require 'csv' belongs_to :user belongs_to :conference diff --git a/app/views/admin/conferences/index.html.haml b/app/views/admin/conferences/index.html.haml index 02208aeb..2fde1575 100644 --- a/app/views/admin/conferences/index.html.haml +++ b/app/views/admin/conferences/index.html.haml @@ -1,5 +1,5 @@ .row - .col-sm-4.col-xs-4 + .col-sm-3.col-xs-3 .dashbox.text-center %span.fa.fa-user.fa-lg %span.fa.fa-lg @@ -11,7 +11,7 @@ %span.label.label-success{ title: "+ #{@new_user} since you last logged in!" } + = @new_user - .col-sm-4.col-xs-4 + .col-sm-3.col-xs-3 .dashbox.text-center %span.fa.fa-check-square.fa-lg %span.fa.fa-lg @@ -23,7 +23,7 @@ %span.label.label-success{ title: "+#{@new_reg} since you last logged in!" } + = @new_reg - .col-sm-4.col-xs-4 + .col-sm-3.col-xs-3 .dashbox.text-center %span.fa.fa-file-text.fa-lg %span.fa.fa-lg @@ -35,6 +35,18 @@ %span.label.label-success{ title: "+#{@new_submissions} since you last logged in!" } + = @new_submissions + .col-sm-3.col-xs-3 + .dashbox.text-center + %span.fa.fa-archive.fa-lg + %span.fa.fa-lg + = @total_withdrawn + %p + %small + #{'Withdrawn'.pluralize(@total_withdrawn)} + - if @new_withdrawn + %span.label.label-success{ title: "+#{@new_withdrawn} since you last logged in!" } + + + = @new_withdrawn .row#registrations .col-md-8 diff --git a/app/views/admin/conferences/show.html.haml b/app/views/admin/conferences/show.html.haml index cddae4c2..ca59d8d9 100644 --- a/app/views/admin/conferences/show.html.haml +++ b/app/views/admin/conferences/show.html.haml @@ -3,7 +3,7 @@ Dashboard for #{@conference.title} %hr .row - .col-sm-4.col-xs-4 + .col-sm-3.col-xs-3 .dashbox.text-center %span.fa.fa-user.fa-lg %span.fa.fa-lg @@ -16,7 +16,7 @@ + = @new_reg - .col-sm-4.col-xs-4 + .col-sm-3.col-xs-3 .dashbox.text-center %span.fa.fa-check-square.fa-lg %span.fa.fa-lg @@ -29,7 +29,7 @@ + = @new_submissions - .col-sm-4.col-xs-4 + .col-sm-3.col-xs-3 .dashbox.text-center %span.fa.fa-file-text.fa-lg %span.fa.fa-lg @@ -42,6 +42,19 @@ + = @new_program_length + .col-sm-3.col-xs-3 + .dashbox.text-center + %span.fa.fa-archive.fa-lg + %span.fa.fa-lg + = @total_withdrawn + %p + %small + #{'Withdrawn'.pluralize(@total_withdrawn)} + - if @new_withdrawn + %span.label.label-success{ title: "+#{@new_withdrawn} since you last logged in!" } + + + = @new_withdrawn + .row .col-md-12 .row @@ -91,6 +104,10 @@ %a{ href: '#distribution_confirmed', 'data-toggle' => 'tab' } %span.fa.fa-comment Confirmed + %li + %a{ href: '#distribution_withdrawn', 'data-toggle' => 'tab' } + %span.fa.fa-archive + Withdrawn .tab-content .tab-pane.active#distribution_all .row @@ -108,6 +125,14 @@ = render partial: 'doughnut_chart', locals: {title: 'Difficulty levels', data: @difficulty_levels_distribution_confirmed} .col-md-4 = render partial: 'doughnut_chart', locals: {title: 'Tracks', data: @tracks_distribution_confirmed} + .tab-pane#distribution_withdrawn + .row + .col-md-4 + = render partial: 'doughnut_chart', locals: {title: 'Event types', data: @event_type_distribution_withdrawn} + .col-md-4 + = render partial: 'doughnut_chart', locals: {title: 'Difficulty levels', data: @difficulty_levels_distribution_withdrawn} + .col-md-4 + = render partial: 'doughnut_chart', locals: {title: 'Tracks', data: @tracks_distribution_withdrawn} .row .col-md-8 diff --git a/app/views/conferences/_social_media.haml b/app/views/conferences/_social_media.haml index 32cf1b16..28a87dbc 100644 --- a/app/views/conferences/_social_media.haml +++ b/app/views/conferences/_social_media.haml @@ -15,6 +15,9 @@ - unless contact.googleplus.blank? = link_to "#{ contact.googleplus }" do %i.fa.fa-google-plus-square.fa-4x + - unless contact.mastodon.blank? + = link_to "#{ contact.mastodon }" do + %i.fa.icon-mastodon.fa-4x - unless contact.email.blank? = mail_to "#{ contact.email }" do %i.fa.fa-envelope-o.fa-4x diff --git a/app/views/conferences/_social_media.html.haml b/app/views/conferences/_social_media.html.haml deleted file mode 100644 index 49216b6c..00000000 --- a/app/views/conferences/_social_media.html.haml +++ /dev/null @@ -1,21 +0,0 @@ -.container - .row - .col-md-12.text-center - - unless @conference.contact.facebook.blank? - = link_to "#{ @conference.contact.facebook }" do - %i.fa.fa-facebook-square.fa-4x - - unless @conference.contact.twitter.blank? - = link_to "#{ @conference.contact.twitter }" do - %i.fa.fa-twitter.fa-4x - - unless @conference.contact.instagram.blank? - = link_to "#{ @conference.contact.instagram }" do - %i.fa.fa-instagram.fa-4x - - unless @conference.contact.googleplus.blank? - = link_to "#{ @conference.contact.googleplus }" do - %i.fa.fa-google-plus-square.fa-4x - - unless @conference.contact.mastodon.blank? - = link_to "#{ @conference.contact.mastodon }" do - %i.fa.icon-mastodon.fa-4x - - unless @conference.contact.email.blank? - = mail_to "#{ @conference.contact.email }" do - %i.fa.fa-envelope-o.fa-4x diff --git a/app/views/conferences/_sponsors.haml b/app/views/conferences/_sponsors.haml index 8f4d55c6..5d7bbaa9 100644 --- a/app/views/conferences/_sponsors.haml +++ b/app/views/conferences/_sponsors.haml @@ -2,7 +2,7 @@ %li %a.smoothscroll{ href: '#sponsors' } Sponsors -- cache [conference, sponsorship_levels, '#splash#sponsors'] do +- cache [conference, sponsors, sponsorship_levels, '#splash#sponsors'] do %section#sponsors .container - sponsorship_levels.each do |sponsorship_level| @@ -31,6 +31,6 @@ = link_to(sponsorship_mailto(conference)) do Contact us! -- sponsorship_levels.collect(&:sponsors).flatten.each do |sponsor| +- sponsors.each do |sponsor| - content_for :modals do = render 'modal_description', object: sponsor diff --git a/app/views/conferences/show.html.haml b/app/views/conferences/show.html.haml index ea99b419..246ccc35 100644 --- a/app/views/conferences/show.html.haml +++ b/app/views/conferences/show.html.haml @@ -43,7 +43,8 @@ -# sponsorship - if @conference.splashpage.include_sponsors = render 'sponsors', conference: @conference, - sponsorship_levels: @sponsorship_levels + sponsorship_levels: @sponsorship_levels, + sponsors: @sponsors -# footer - if @conference.splashpage.include_social_media diff --git a/app/views/devise/shared/_openid_links.html.haml b/app/views/devise/shared/_openid_links.html.haml index 8bcc96da..09c7a7ea 100644 --- a/app/views/devise/shared/_openid_links.html.haml +++ b/app/views/devise/shared/_openid_links.html.haml @@ -1,5 +1,5 @@ .text-center - .btn-group.btn-group-lg + .btn-group.btn-group-lg#openid-btn-grp - omniauth_configured.each do |provider| = link_to "user_#{provider}_omniauth_authorize".to_sym, class: "btn btn-success btn-lg", id: "omniauth-#{provider}", diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index aa155bcb..128f491a 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -37,11 +37,14 @@ %p.muted.text-center %small This tool is - =link_to "free software,", "http://www.gnu.org/philosophy/free-sw.html" + #{link_to "free software", "http://www.gnu.org/philosophy/free-sw.html"}, released under the - =link_to "MIT license.", "http://opensource.org/licenses/MIT" + #{link_to "MIT license", "http://opensource.org/licenses/MIT"}. You can run, copy, distribute, study, change and improve it. The source code and the developers are on - =link_to "github.", "https://github.com/openSUSE/osem" + #{link_to "GitHub", "https://github.com/openSUSE/osem"}. + - if ENV["SKYLIGHT_PUBLIC_DASHBOARD_URL"].present? + Performance data is available on + #{link_to "Skylight", ENV["SKYLIGHT_PUBLIC_DASHBOARD_URL"]}. = yield :script_body = piwik_tracking_tag diff --git a/dotenv.example b/dotenv.example index e0e3f519..6d8dd025 100644 --- a/dotenv.example +++ b/dotenv.example @@ -46,6 +46,10 @@ OSEM_SUSE_SECRET='' STRIPE_PUBLISHABLE_KEY='' STRIPE_SECRET_KEY='' +# (OPTIONAL) Skylight keys. See https://www.skylight.io/oss. +# SKYLIGHT_AUTHENTICATION='' +# SKYLIGHT_PUBLIC_DASHBOARD_URL='https://oss.skylight.io/app/applications/xxxxxxxxxxxx' + # Disable linting of factories in the test suite. # Speeds up turn around times of tests OSEM_FACTORY_LINT="false" diff --git a/spec/controllers/admin/conferences_controller_spec.rb b/spec/controllers/admin/conferences_controller_spec.rb index ff9d676b..984ef137 100644 --- a/spec/controllers/admin/conferences_controller_spec.rb +++ b/spec/controllers/admin/conferences_controller_spec.rb @@ -95,6 +95,75 @@ describe Admin::ConferencesController do get :show, id: conference.short_title expect(response).to render_template :show end + + it 'assigns conference withdrawn events distribution to event_type_distribution_withdrawn' do + conference + create(:event, program: conference.program) + workshop = create(:event_type, title: 'Workshop', color: '#000000', program: conference.program) + lecture = create(:event_type, title: 'Lecture', color: '#ffffff', program: conference.program) + get :show, id: conference.short_title + expect(assigns(:event_type_distribution_withdrawn)).to be_empty + create(:event, program: conference.program, state: 'withdrawn', event_type: lecture) + create(:event, program: conference.program, state: 'withdrawn', event_type: workshop) + get :show, id: conference.short_title + expect(assigns(:event_type_distribution_withdrawn)).not_to be_empty + result = {} + result['Workshop'] = { + 'value' => 1, + 'color' => '#000000' + } + result['Lecture'] = { + 'value' => 1, + 'color' => '#FFFFFF' + } + expect(assigns(:event_type_distribution_withdrawn)).to eq(result) + end + + it 'assigns conference withdrawn difficulty level distribution to difficulty_levels_distribution_withdrawn' do + conference + create(:event, program: conference.program) + get :show, id: conference.short_title + expect(assigns(:difficulty_levels_distribution_withdrawn)).to be_empty + easy = create(:difficulty_level, title: 'Easy', color: '#000000') + hard = create(:difficulty_level, title: 'Hard', color: '#ffffff') + create(:event, program: conference.program, state: 'withdrawn', difficulty_level: easy) + create(:event, program: conference.program, state: 'withdrawn', difficulty_level: hard) + get :show, id: conference.short_title + expect(assigns(:difficulty_levels_distribution_withdrawn)).not_to be_empty + result = {} + result['Easy'] = { + 'value' => 1, + 'color' => '#000000' + } + result['Hard'] = { + 'value' => 1, + 'color' => '#FFFFFF' + } + expect(assigns(:difficulty_levels_distribution_withdrawn)).to eq(result) + end + + it 'assigns conference withdrawn track distribution to tracks_distribution_withdrawn' do + conference + create(:event, program: conference.program) + get :show, id: conference.short_title + expect(assigns(:tracks_distribution_withdrawn)).to be_empty + track_one = create(:track, name: 'Track One', color: '#000000', program: conference.program) + track_two = create(:track, name: 'Track Two', color: '#FFFFFF', program: conference.program) + create(:event, program: conference.program, state: 'withdrawn', track: track_one) + create(:event, program: conference.program, state: 'withdrawn', track: track_two) + get :show, id: conference.short_title + expect(assigns(:tracks_distribution_withdrawn)).not_to be_empty + result = {} + result['Track One'] = { + 'value' => 1, + 'color' => '#000000' + } + result['Track Two'] = { + 'value' => 1, + 'color' => '#FFFFFF' + } + expect(assigns(:tracks_distribution_withdrawn)).to eq(result) + end end describe 'GET #index' do diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 214e522a..4d1c2eab 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -30,7 +30,45 @@ describe ApplicationController, type: :controller do expect(controller.after_sign_in_path_for(user)).to eq conferences_path end end - + end + + end + +end + +describe ApplicationController, type: :request do + let(:conference) { create(:conference) } + + describe 'Skylight link' do + + around do |example| + original_value = ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL'] + example.run + ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL'] = original_value + end + + context 'when SKYLIGHT_PUBLIC_DASHBOARD_URL is set' do + before do + ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL'] = 'https://oss.skylight.io/app/applications/my-osem' + end + + it 'should include a link to view performance data' do + get '/' + expect(response.body).to match(/Performance data/i) + expect(response.body).to include('https://oss.skylight.io/app/applications/my-osem') + end + end + + context 'when SKYLIGHT_PUBLIC_DASHBOARD_URL is not set' do + before do + ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL'] = nil + end + + it 'should not include a link to view performance data' do + get '/' + expect(response.body).to_not match(/performance data/i) + expect(response.body).to_not match(/skylight/i) + end end end diff --git a/spec/factories/organizations.rb b/spec/factories/organizations.rb index 0ee76554..f6331873 100644 --- a/spec/factories/organizations.rb +++ b/spec/factories/organizations.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :organization do - name { Faker::Company.name } + sequence(:name) { |n| "#{Faker::Company.name} #{n}" } description { Faker::Lorem.paragraph } # after(:create) do |organization| diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 7936ddbb..26522913 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -89,11 +89,131 @@ describe 'User' do let(:other_self_organized_track) { create(:track, :self_organized) } it{ should be_able_to(:manage, user) } - it{ should be_able_to(:manage, registration_public) } it{ should be_able_to(:manage, registration_not_public) } - it{ should_not be_able_to(:new, Registration.new(conference_id: conference_with_closed_registration.id))} - it{ should_not be_able_to(:create, Registration.new(conference_id: conference_with_closed_registration.id))} + + # Test for user can register or not + context 'when user is not a speaker with event confirmed' do + let(:conference) { create(:conference) } + + context 'when the registration is closed' do + before :each do + create(:registration_period, conference: conference, start_date: Date.current - 6.days, end_date: Date.current - 6.days) + end + + it{ should_not be_able_to(:new, Registration.new(conference: conference)) } + it{ should_not be_able_to(:create, Registration.new(conference: conference)) } + end + + context 'when the registration period is not set' do + it{ should_not be_able_to(:new, Registration.new(conference: conference)) } + it{ should_not be_able_to(:create, Registration.new(conference: conference)) } + end + + context 'when user has already registered' do + before :each do + create(:registration, conference: conference, user: user) + end + + it{ should_not be_able_to(:new, Registration.new(conference: conference)) } + it{ should_not be_able_to(:create, Registration.new(conference: conference)) } + end + + context 'when registrations are open' do + before :each do + create(:registration_period, conference: conference) + end + + it{ should be_able_to(:new, Registration.new(conference: conference)) } + it{ should be_able_to(:create, Registration.new(conference: conference)) } + + context 'when user has not registered with no registration_limit_exceeded' do + before :each do + conference.registration_limit = 1 + end + + it{ should be_able_to(:new, Registration.new(conference: conference)) } + it{ should be_able_to(:create, Registration.new(conference: conference)) } + end + + context 'when user has not registered with registration_limit_exceeded' do + before :each do + conference.registration_limit = 1 + create(:registration, conference: conference, user: user2) + end + + it{ should_not be_able_to(:new, Registration.new(conference: conference)) } + it{ should_not be_able_to(:create, Registration.new(conference: conference)) } + end + end + end + + context 'when user is a speaker with event confirmed' do + let(:conference_with_speaker_confirmed) { create(:conference) } + let(:event_with_speaker_confirmed) { create(:event, state: 'confirmed', program: conference_with_speaker_confirmed.program) } + + before :each do + event_with_speaker_confirmed.speakers << user + end + + context 'when registration period is not set' do + it{ should_not be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) } + it{ should_not be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) } + end + + context 'when speaker has already registered' do + before :each do + create(:registration, conference: conference_with_speaker_confirmed, user: user) + end + + it{ should_not be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) } + it{ should_not be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) } + end + + context 'when registration period is set' do + before :each do + create(:registration_period, conference: conference_with_speaker_confirmed) + end + + context 'when registrations are open' do + context 'when speaker has not registered' do + it{ should be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) } + it{ should be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) } + end + + context 'when registration_limit_exceeded' do + before :each do + conference_with_speaker_confirmed.registration_limit = 1 + create(:registration, conference: conference_with_speaker_confirmed, user: user2) + end + + it{ should be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) } + it{ should be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) } + end + end + + context 'when registrations are closed' do + before :each do + create(:registration_period, conference: conference_with_speaker_confirmed, start_date: Date.current - 6.days, end_date: Date.current - 6.days) + end + + context 'when speaker has not registered' do + it{ should be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) } + it{ should be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) } + end + + context 'with registration_limit_exceeded' do + before :each do + conference_with_speaker_confirmed.registration_limit = 1 + create(:registration, conference: conference_with_speaker_confirmed, user: user2) + end + + it{ should be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) } + it{ should be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) } + end + end + end + end it{ should be_able_to(:index, Ticket) } it{ should be_able_to(:manage, TicketPurchase.new(user_id: user.id)) } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 704b8e08..60e07602 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -63,7 +63,12 @@ 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, window_size: [1920, 1080]) + 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 diff --git a/spec/support/external_request.rb b/spec/support/external_request.rb index d09ebc0a..ed7da3d3 100644 --- a/spec/support/external_request.rb +++ b/spec/support/external_request.rb @@ -11,9 +11,9 @@ end def mock_commercial_request response = { author_name: 'Confreaks', - html: '', + html: '', thumbnail_width: 480, - thumbnail_url: 'https://i.ytimg.com/vi/BTTygyxuGj8/hqdefault.jpg', + thumbnail_url: '/images/rails.png', provider_name: 'YouTube', width: 459, type: 'video',