open_conference_ware 1.0.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/.autotest +14 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +21 -0
- data/.rspec +1 -0
- data/.travis.yml +18 -0
- data/CHANGES.md +280 -0
- data/CONTRIBUTORS.markdown +17 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +296 -0
- data/Guardfile +24 -0
- data/LICENSE.txt +23 -0
- data/README.markdown +173 -0
- data/Rakefile +27 -0
- data/TODO.txt +22 -0
- data/app/assets/images/open_conference_ware/accept.png +0 -0
- data/app/assets/images/open_conference_ware/arrow-left.png +0 -0
- data/app/assets/images/open_conference_ware/arrow-out.png +0 -0
- data/app/assets/images/open_conference_ware/arrow-right.png +0 -0
- data/app/assets/images/open_conference_ware/arrow-up.png +0 -0
- data/app/assets/images/open_conference_ware/arrow_refresh.png +0 -0
- data/app/assets/images/open_conference_ware/comment.png +0 -0
- data/app/assets/images/open_conference_ware/comment_edit.png +0 -0
- data/app/assets/images/open_conference_ware/delete.png +0 -0
- data/app/assets/images/open_conference_ware/disk.png +0 -0
- data/app/assets/images/open_conference_ware/document-blank.png +0 -0
- data/app/assets/images/open_conference_ware/document.png +0 -0
- data/app/assets/images/open_conference_ware/edit.png +0 -0
- data/app/assets/images/open_conference_ware/extras/001_01.png +0 -0
- data/app/assets/images/open_conference_ware/extras/001_05.png +0 -0
- data/app/assets/images/open_conference_ware/extras/001_05x16.png +0 -0
- data/app/assets/images/open_conference_ware/extras/001_21.png +0 -0
- data/app/assets/images/open_conference_ware/extras/001_23.png +0 -0
- data/app/assets/images/open_conference_ware/extras/001_24.png +0 -0
- data/app/assets/images/open_conference_ware/extras/001_29.png +0 -0
- data/app/assets/images/open_conference_ware/extras/01.png +0 -0
- data/app/assets/images/open_conference_ware/extras/05.png +0 -0
- data/app/assets/images/open_conference_ware/extras/06.png +0 -0
- data/app/assets/images/open_conference_ware/extras/1.png +0 -0
- data/app/assets/images/open_conference_ware/extras/14.png +0 -0
- data/app/assets/images/open_conference_ware/extras/16.png +0 -0
- data/app/assets/images/open_conference_ware/extras/2.png +0 -0
- data/app/assets/images/open_conference_ware/extras/21.png +0 -0
- data/app/assets/images/open_conference_ware/extras/28.png +0 -0
- data/app/assets/images/open_conference_ware/extras/3.png +0 -0
- data/app/assets/images/open_conference_ware/extras/31.png +0 -0
- data/app/assets/images/open_conference_ware/extras/32.png +0 -0
- data/app/assets/images/open_conference_ware/extras/35.png +0 -0
- data/app/assets/images/open_conference_ware/extras/36.png +0 -0
- data/app/assets/images/open_conference_ware/extras/4.png +0 -0
- data/app/assets/images/open_conference_ware/extras/44.png +0 -0
- data/app/assets/images/open_conference_ware/extras/45.png +0 -0
- data/app/assets/images/open_conference_ware/extras/46.png +0 -0
- data/app/assets/images/open_conference_ware/extras/cancel.png +0 -0
- data/app/assets/images/open_conference_ware/extras/cancelx16.png +0 -0
- data/app/assets/images/open_conference_ware/extras/icon.trashcan.gif +0 -0
- data/app/assets/images/open_conference_ware/favorite.png +0 -0
- data/app/assets/images/open_conference_ware/feed.png +0 -0
- data/app/assets/images/open_conference_ware/heart.png +0 -0
- data/app/assets/images/open_conference_ware/house.png +0 -0
- data/app/assets/images/open_conference_ware/ignite_portland_header3_clear.png +0 -0
- data/app/assets/images/open_conference_ware/ignite_portland_header3_clear_cropped.png +0 -0
- data/app/assets/images/open_conference_ware/jquery.wysiwyg.gif +0 -0
- data/app/assets/images/open_conference_ware/lock.png +0 -0
- data/app/assets/images/open_conference_ware/new_window.gif +0 -0
- data/app/assets/images/open_conference_ware/openid-icon.gif +0 -0
- data/app/assets/images/open_conference_ware/pencil.png +0 -0
- data/app/assets/images/open_conference_ware/plus.png +0 -0
- data/app/assets/images/open_conference_ware/quote.png +0 -0
- data/app/assets/images/open_conference_ware/rails.png +0 -0
- data/app/assets/images/open_conference_ware/redx.png +0 -0
- data/app/assets/images/open_conference_ware/reset-fff.png +0 -0
- data/app/assets/images/open_conference_ware/spinner-big.gif +0 -0
- data/app/assets/images/open_conference_ware/spinner.gif +0 -0
- data/app/assets/images/open_conference_ware/star.png +0 -0
- data/app/assets/images/open_conference_ware/tag_blue.png +0 -0
- data/app/assets/images/open_conference_ware/time.png +0 -0
- data/app/assets/javascripts/open_conference_ware/application.js +18 -0
- data/app/assets/javascripts/open_conference_ware/base.js +15 -0
- data/app/assets/javascripts/open_conference_ware/favorites.js +76 -0
- data/app/assets/javascripts/open_conference_ware/ie.js +2 -0
- data/app/assets/javascripts/open_conference_ware/menu.js +47 -0
- data/app/assets/javascripts/open_conference_ware/persona.js +10 -0
- data/app/assets/javascripts/open_conference_ware/proposals.js +208 -0
- data/app/assets/javascripts/open_conference_ware/schedule.js +20 -0
- data/app/assets/javascripts/open_conference_ware/spinner.js +11 -0
- data/app/assets/javascripts/open_conference_ware/util.js +23 -0
- data/app/assets/stylesheets/open_conference_ware/application.css +8 -0
- data/app/assets/stylesheets/open_conference_ware/common.css.scss +491 -0
- data/app/assets/stylesheets/open_conference_ware/custom.css.scss +1033 -0
- data/app/assets/stylesheets/open_conference_ware/scaffold.css +54 -0
- data/app/controllers/open_conference_ware/application_controller.rb +488 -0
- data/app/controllers/open_conference_ware/authentications_controller.rb +42 -0
- data/app/controllers/open_conference_ware/comments_controller.rb +86 -0
- data/app/controllers/open_conference_ware/events_controller.rb +36 -0
- data/app/controllers/open_conference_ware/manage/events_controller.rb +157 -0
- data/app/controllers/open_conference_ware/manage/snippets_controller.rb +110 -0
- data/app/controllers/open_conference_ware/proposals_controller.rb +521 -0
- data/app/controllers/open_conference_ware/rooms_controller.rb +130 -0
- data/app/controllers/open_conference_ware/schedule_items_controller.rb +128 -0
- data/app/controllers/open_conference_ware/selector_votes_controller.rb +71 -0
- data/app/controllers/open_conference_ware/session_types_controller.rb +123 -0
- data/app/controllers/open_conference_ware/tracks_controller.rb +118 -0
- data/app/controllers/open_conference_ware/user_favorites_controller.rb +68 -0
- data/app/controllers/open_conference_ware/users_controller.rb +120 -0
- data/app/helpers/open_conference_ware/application_helper.rb +167 -0
- data/app/helpers/open_conference_ware/authentications_helper.rb +25 -0
- data/app/helpers/open_conference_ware/cache_if_helper.rb +13 -0
- data/app/helpers/open_conference_ware/display_link_to_helper.rb +25 -0
- data/app/helpers/open_conference_ware/display_textile_for_helper.rb +11 -0
- data/app/helpers/open_conference_ware/field_annotation_helper.rb +11 -0
- data/app/helpers/open_conference_ware/focus_helper.rb +16 -0
- data/app/helpers/open_conference_ware/localcss_helper.rb +10 -0
- data/app/helpers/open_conference_ware/page_title_helper.rb +17 -0
- data/app/helpers/open_conference_ware/proposals_helper.rb +54 -0
- data/app/helpers/open_conference_ware/rooms_helper.rb +5 -0
- data/app/helpers/open_conference_ware/scroll_to_helper.rb +15 -0
- data/app/helpers/open_conference_ware/session_types_helper.rb +5 -0
- data/app/helpers/open_conference_ware/snippets_helper.rb +36 -0
- data/app/helpers/open_conference_ware/time_range_helper.rb +198 -0
- data/app/helpers/open_conference_ware/tracks_helper.rb +9 -0
- data/app/helpers/open_conference_ware/user_favorites_helper.rb +15 -0
- data/app/mailers/open_conference_ware/speaker_mailer.rb +51 -0
- data/app/mixins/open_conference_ware/breadcrumbs_mixin.rb +76 -0
- data/app/mixins/open_conference_ware/cache_lookups_mixin.rb +128 -0
- data/app/mixins/open_conference_ware/faux_routes_mixin.rb +83 -0
- data/app/mixins/open_conference_ware/normalize_url_mixin.rb +40 -0
- data/app/mixins/open_conference_ware/public_attributes_mixin.rb +62 -0
- data/app/mixins/open_conference_ware/schedule_overlaps_mixin.rb +12 -0
- data/app/mixins/open_conference_ware/settings_checkers_mixin.rb +50 -0
- data/app/mixins/open_conference_ware/simple_slug_mixin.rb +26 -0
- data/app/models/open_conference_ware/authentication.rb +47 -0
- data/app/models/open_conference_ware/base.rb +6 -0
- data/app/models/open_conference_ware/comment.rb +26 -0
- data/app/models/open_conference_ware/event.rb +227 -0
- data/app/models/open_conference_ware/proposal.rb +625 -0
- data/app/models/open_conference_ware/room.rb +42 -0
- data/app/models/open_conference_ware/schedule.rb +216 -0
- data/app/models/open_conference_ware/schedule_item.rb +55 -0
- data/app/models/open_conference_ware/selector_vote.rb +22 -0
- data/app/models/open_conference_ware/session_type.rb +33 -0
- data/app/models/open_conference_ware/snippet.rb +58 -0
- data/app/models/open_conference_ware/track.rb +51 -0
- data/app/models/open_conference_ware/user.rb +262 -0
- data/app/models/open_conference_ware/user_favorite.rb +42 -0
- data/app/observers/open_conference_ware/cache_watcher.rb +42 -0
- data/app/views/layouts/open_conference_ware/_header.html.erb +106 -0
- data/app/views/layouts/open_conference_ware/application.atom.erb +1 -0
- data/app/views/layouts/open_conference_ware/application.html.erb +126 -0
- data/app/views/layouts/open_conference_ware/scaffold.html.erb +21 -0
- data/app/views/open_conference_ware/404.html.erb +8 -0
- data/app/views/open_conference_ware/422.html.erb +11 -0
- data/app/views/open_conference_ware/500.html.erb +11 -0
- data/app/views/open_conference_ware/_email_link.html.erb +24 -0
- data/app/views/open_conference_ware/_google_analytics.html.erb +9 -0
- data/app/views/open_conference_ware/authentications/_developer.html.erb +7 -0
- data/app/views/open_conference_ware/authentications/_openid.html.erb +11 -0
- data/app/views/open_conference_ware/authentications/_persona.html.erb +17 -0
- data/app/views/open_conference_ware/authentications/sign_in.html.erb +12 -0
- data/app/views/open_conference_ware/comments/_list.html.erb +31 -0
- data/app/views/open_conference_ware/comments/index.atom.builder +25 -0
- data/app/views/open_conference_ware/comments/index.html.erb +3 -0
- data/app/views/open_conference_ware/events/index.html.erb +9 -0
- data/app/views/open_conference_ware/events/show.html.erb +0 -0
- data/app/views/open_conference_ware/events/speakers.html.erb +7 -0
- data/app/views/open_conference_ware/manage/events/_form.html.erb +107 -0
- data/app/views/open_conference_ware/manage/events/edit.html.erb +3 -0
- data/app/views/open_conference_ware/manage/events/index.html.erb +41 -0
- data/app/views/open_conference_ware/manage/events/new.html.erb +3 -0
- data/app/views/open_conference_ware/manage/events/proposals.html.erb +133 -0
- data/app/views/open_conference_ware/manage/events/show.html.erb +181 -0
- data/app/views/open_conference_ware/manage/snippets/_form.html.erb +30 -0
- data/app/views/open_conference_ware/manage/snippets/edit.html.erb +3 -0
- data/app/views/open_conference_ware/manage/snippets/index.html.erb +34 -0
- data/app/views/open_conference_ware/manage/snippets/new.html.erb +3 -0
- data/app/views/open_conference_ware/manage/snippets/show.html.erb +32 -0
- data/app/views/open_conference_ware/proposals/_admin_controls.html.erb +33 -0
- data/app/views/open_conference_ware/proposals/_form.html.erb +381 -0
- data/app/views/open_conference_ware/proposals/_list.html.erb +164 -0
- data/app/views/open_conference_ware/proposals/_list_concise.html.erb +93 -0
- data/app/views/open_conference_ware/proposals/_manage_speakers.html.erb +30 -0
- data/app/views/open_conference_ware/proposals/_room_control.html.erb +21 -0
- data/app/views/open_conference_ware/proposals/_schedule_block.html.erb +8 -0
- data/app/views/open_conference_ware/proposals/_schedule_control.html.erb +13 -0
- data/app/views/open_conference_ware/proposals/_search_speakers.html.erb +20 -0
- data/app/views/open_conference_ware/proposals/_sub_list.html.erb +65 -0
- data/app/views/open_conference_ware/proposals/_sub_list_for_kind.html.erb +31 -0
- data/app/views/open_conference_ware/proposals/_transition_control.html.erb +16 -0
- data/app/views/open_conference_ware/proposals/create.html.erb +29 -0
- data/app/views/open_conference_ware/proposals/edit.html.erb +7 -0
- data/app/views/open_conference_ware/proposals/index.atom.builder +63 -0
- data/app/views/open_conference_ware/proposals/index.html.erb +46 -0
- data/app/views/open_conference_ware/proposals/new.html.erb +3 -0
- data/app/views/open_conference_ware/proposals/schedule.html.erb +108 -0
- data/app/views/open_conference_ware/proposals/sessions_index_terse.html.erb +22 -0
- data/app/views/open_conference_ware/proposals/show.html.erb +316 -0
- data/app/views/open_conference_ware/proposals/stats.html.erb +72 -0
- data/app/views/open_conference_ware/rooms/_form.html.erb +36 -0
- data/app/views/open_conference_ware/rooms/edit.html.erb +3 -0
- data/app/views/open_conference_ware/rooms/index.html.erb +13 -0
- data/app/views/open_conference_ware/rooms/new.html.erb +3 -0
- data/app/views/open_conference_ware/rooms/show.html.erb +27 -0
- data/app/views/open_conference_ware/schedule_items/_form.html.erb +35 -0
- data/app/views/open_conference_ware/schedule_items/edit.html.erb +3 -0
- data/app/views/open_conference_ware/schedule_items/index.html.erb +31 -0
- data/app/views/open_conference_ware/schedule_items/new.html.erb +3 -0
- data/app/views/open_conference_ware/schedule_items/show.html.erb +30 -0
- data/app/views/open_conference_ware/selector_votes/index.html.erb +81 -0
- data/app/views/open_conference_ware/session_types/_form.html.erb +23 -0
- data/app/views/open_conference_ware/session_types/edit.html.erb +3 -0
- data/app/views/open_conference_ware/session_types/index.html.erb +18 -0
- data/app/views/open_conference_ware/session_types/new.html.erb +3 -0
- data/app/views/open_conference_ware/session_types/show.html.erb +14 -0
- data/app/views/open_conference_ware/speaker_mailer/speaker_email.text.erb +14 -0
- data/app/views/open_conference_ware/tracks/_colors.css.erb +7 -0
- data/app/views/open_conference_ware/tracks/_form.html.erb +36 -0
- data/app/views/open_conference_ware/tracks/edit.html.erb +3 -0
- data/app/views/open_conference_ware/tracks/index.html.erb +25 -0
- data/app/views/open_conference_ware/tracks/new.html.erb +3 -0
- data/app/views/open_conference_ware/tracks/show.html.erb +19 -0
- data/app/views/open_conference_ware/user_favorites/index.html.erb +12 -0
- data/app/views/open_conference_ware/users/_account_box.html.erb +10 -0
- data/app/views/open_conference_ware/users/_block.html.erb +80 -0
- data/app/views/open_conference_ware/users/_list.html.erb +17 -0
- data/app/views/open_conference_ware/users/edit.html.erb +73 -0
- data/app/views/open_conference_ware/users/index.html.erb +28 -0
- data/app/views/open_conference_ware/users/new.html.erb +7 -0
- data/app/views/open_conference_ware/users/proposals.html.erb +24 -0
- data/app/views/open_conference_ware/users/show.html.erb +5 -0
- data/app/views/open_conference_ware/welcome/test.html.haml +8 -0
- data/bin/rails +8 -0
- data/ci/Gemfile.ci +13 -0
- data/ci/copy_database_config.rb +6 -0
- data/ci/database.mysql.yml +5 -0
- data/ci/database.postgresql.yml +4 -0
- data/ci/database.sqlite.yml +5 -0
- data/config/initializers/acts_as_taggable_on.rb +2 -0
- data/config/initializers/date_time_formats.rb +9 -0
- data/config/routes.rb +74 -0
- data/db/migrate/20131203235128_create_open_conference_ware_authentications.rb +14 -0
- data/db/migrate/20131203235216_create_open_conference_ware_comments.rb +14 -0
- data/db/migrate/20131203235418_create_open_conference_ware_events.rb +27 -0
- data/db/migrate/20131203235524_create_open_conference_ware_proposals.rb +36 -0
- data/db/migrate/20131203235723_create_open_conference_ware_rooms.rb +20 -0
- data/db/migrate/20131203235831_create_open_conference_ware_schedule_items.rb +18 -0
- data/db/migrate/20131203235910_create_open_conference_ware_selector_votes.rb +10 -0
- data/db/migrate/20131203235934_create_open_conference_ware_session_types.rb +14 -0
- data/db/migrate/20131204000008_create_open_conference_ware_snippets.rb +15 -0
- data/db/migrate/20131204000048_create_open_conference_ware_taggings.rb +16 -0
- data/db/migrate/20131204000129_create_open_conference_ware_tags.rb +7 -0
- data/db/migrate/20131204000147_create_open_conference_ware_tracks.rb +15 -0
- data/db/migrate/20131204000230_create_open_conference_ware_user_favorites.rb +10 -0
- data/db/migrate/20131204000251_create_open_conference_ware_users.rb +24 -0
- data/db/migrate/20131204000355_create_proposals_users_join_table.rb +8 -0
- data/db/seeds.rb +31 -0
- data/features/comment_create.feature +9 -0
- data/features/comment_destroy.feature +22 -0
- data/features/comment_new.feature +22 -0
- data/features/step_definitions/authentication_steps.rb +22 -0
- data/features/step_definitions/comment_create_steps.rb +5 -0
- data/features/step_definitions/comment_destroy_steps.rb +13 -0
- data/features/step_definitions/comment_new_steps.rb +41 -0
- data/features/step_definitions/notification_steps.rb +3 -0
- data/features/step_definitions/web_steps.rb +263 -0
- data/features/support/env.rb +58 -0
- data/features/support/helpers.rb +17 -0
- data/features/support/paths.rb +35 -0
- data/gem-public_cert.pem +22 -0
- data/lib/defer_proxy.rb +127 -0
- data/lib/ext/color_rgb_serializer_fix.rb +18 -0
- data/lib/ext/string_possessiveize.rb +7 -0
- data/lib/ext/vpim_icalendar_extra_properties.rb +25 -0
- data/lib/generators/open_conference_ware/install/USAGE +12 -0
- data/lib/generators/open_conference_ware/install/install_generator.rb +35 -0
- data/lib/generators/open_conference_ware/install/templates/config_initializer.rb +110 -0
- data/lib/generators/open_conference_ware/install/templates/omniauth_initializer.rb +33 -0
- data/lib/open_conference_ware.rb +156 -0
- data/lib/open_conference_ware/dependencies.rb +38 -0
- data/lib/open_conference_ware/engine.rb +38 -0
- data/lib/open_conference_ware/omni_auth_builder.rb +8 -0
- data/lib/open_conference_ware/version.rb +3 -0
- data/lib/rwikibot_page_drone.rb +70 -0
- data/lib/tasks/.gitkeep +0 -0
- data/lib/tasks/audio.rake +53 -0
- data/lib/tasks/cucumber.rake +65 -0
- data/lib/tasks/export.rake +170 -0
- data/lib/tasks/mediawiki.rake +96 -0
- data/lib/tasks/open_conference_ware_tasks.rake +16 -0
- data/lib/tasks/schedule.rake +103 -0
- data/lib/tasks/snippets.rake +23 -0
- data/open_conference_ware.gemspec +67 -0
- data/original_graphics/favorite.psd +0 -0
- data/spec/controllers/open_conference_ware/application_controller_spec.rb +309 -0
- data/spec/controllers/open_conference_ware/authentications_controller_spec.rb +87 -0
- data/spec/controllers/open_conference_ware/comments_controller_spec.rb +146 -0
- data/spec/controllers/open_conference_ware/events_controller_spec.rb +102 -0
- data/spec/controllers/open_conference_ware/manage_events_controller_spec.rb +103 -0
- data/spec/controllers/open_conference_ware/proposals_controller_spec.rb +1273 -0
- data/spec/controllers/open_conference_ware/rooms_controller_spec.rb +190 -0
- data/spec/controllers/open_conference_ware/selector_votes_controller_spec.rb +263 -0
- data/spec/controllers/open_conference_ware/session_types_controller_spec.rb +190 -0
- data/spec/controllers/open_conference_ware/sessions_routing_spec.rb +13 -0
- data/spec/controllers/open_conference_ware/tracks_controller_spec.rb +190 -0
- data/spec/controllers/open_conference_ware/user_favorites_controller_spec.rb +127 -0
- data/spec/controllers/open_conference_ware/users_controller_spec.rb +166 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +30 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/01_open_conference_ware.rb +110 -0
- data/spec/dummy/config/initializers/02_omniauth.rb +17 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/schema.rb +219 -0
- data/spec/dummy/db/seeds.rb +10 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/authentication_factory.rb +16 -0
- data/spec/factories/common_factory.rb +4 -0
- data/spec/factories/event_factory.rb +26 -0
- data/spec/factories/proposal_factory.rb +57 -0
- data/spec/factories/proposal_user_factory.rb +7 -0
- data/spec/factories/room_factory.rb +11 -0
- data/spec/factories/schedule_item_factory.rb +13 -0
- data/spec/factories/session_types_factory.rb +10 -0
- data/spec/factories/snippet_factory.rb +7 -0
- data/spec/factories/track_factory.rb +12 -0
- data/spec/factories/user_factory.rb +22 -0
- data/spec/factories/user_favorite_factory.rb +7 -0
- data/spec/features/sign_in_spec.rb +11 -0
- data/spec/features/snippets_spec.rb +38 -0
- data/spec/fixtures/open_conference_ware_comments.yml +27 -0
- data/spec/fixtures/open_conference_ware_events.yml +56 -0
- data/spec/fixtures/open_conference_ware_proposals.yml +256 -0
- data/spec/fixtures/open_conference_ware_rooms.yml +13 -0
- data/spec/fixtures/open_conference_ware_schedule_items.yml +23 -0
- data/spec/fixtures/open_conference_ware_session_types.yml +19 -0
- data/spec/fixtures/open_conference_ware_snippets.yml +62 -0
- data/spec/fixtures/open_conference_ware_tracks.yml +65 -0
- data/spec/fixtures/open_conference_ware_user_favorites.yml +7 -0
- data/spec/fixtures/open_conference_ware_users.yml +87 -0
- data/spec/helpers/open_conference_ware/application_helper_spec.rb +58 -0
- data/spec/helpers/open_conference_ware/authentications_helper_spec.rb +15 -0
- data/spec/helpers/open_conference_ware/display_link_to_helper_spec.rb +52 -0
- data/spec/helpers/open_conference_ware/proposals_helper_spec.rb +32 -0
- data/spec/helpers/open_conference_ware/rooms_helper_spec.rb +11 -0
- data/spec/helpers/open_conference_ware/session_types_helper_spec.rb +15 -0
- data/spec/helpers/open_conference_ware/time_range_helper_spec.rb +56 -0
- data/spec/helpers/open_conference_ware/tracks_helper_spec.rb +11 -0
- data/spec/helpers/open_conference_ware/user_favorites_helper_spec.rb +11 -0
- data/spec/integration/open_conference_ware/cache_lookups_mixin_spec.rb +122 -0
- data/spec/mixins/open_conference_ware/normalize_url_mixin_spec.rb +65 -0
- data/spec/models/open_conference_ware/authentication_spec.rb +67 -0
- data/spec/models/open_conference_ware/event_spec.rb +211 -0
- data/spec/models/open_conference_ware/proposal_spec.rb +606 -0
- data/spec/models/open_conference_ware/room_spec.rb +14 -0
- data/spec/models/open_conference_ware/schedule_item_spec.rb +12 -0
- data/spec/models/open_conference_ware/schedule_spec.rb +358 -0
- data/spec/models/open_conference_ware/selector_vote_spec.rb +12 -0
- data/spec/models/open_conference_ware/session_type_spec.rb +15 -0
- data/spec/models/open_conference_ware/snippet_spec.rb +13 -0
- data/spec/models/open_conference_ware/speaker_mailer_spec.rb +91 -0
- data/spec/models/open_conference_ware/track_spec.rb +36 -0
- data/spec/models/open_conference_ware/user_favorite_spec.rb +41 -0
- data/spec/models/open_conference_ware/user_spec.rb +77 -0
- data/spec/ocw_config.rb +76 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/spec_helper_customizations.rb +125 -0
- data/spec/support/add_all_helpers_to_view.rb +24 -0
- data/spec/support/authenticated_test_helper.rb +27 -0
- data/spec/support/fixture_shortcuts.rb +18 -0
- data/spec/support/omniauth.rb +34 -0
- data/spec/support/valid_params_extraction.rb +15 -0
- data/spec/views/open_conference_ware/proposals/_room_control.html.erb_spec.rb +23 -0
- data/spec/views/open_conference_ware/proposals/_transition_control.html.erb_spec.rb +14 -0
- data/spec/views/open_conference_ware/proposals/show.html.erb_spec.rb +128 -0
- data/spec/views/open_conference_ware/rooms/index.html.erb_spec.rb +19 -0
- data/spec/views/open_conference_ware/rooms/show.html.erb_spec.rb +15 -0
- data/spec/views/open_conference_ware/selector_votes/index.html.erb_spec.rb +41 -0
- data/spec/views/open_conference_ware/session_types/edit.html.erb_spec.rb +25 -0
- data/spec/views/open_conference_ware/session_types/index.html.erb_spec.rb +19 -0
- data/spec/views/open_conference_ware/session_types/new.html.erb_spec.rb +24 -0
- data/spec/views/open_conference_ware/session_types/show.html.erb_spec.rb +18 -0
- data/spec/views/open_conference_ware/tracks/edit.html.erb_spec.rb +25 -0
- data/spec/views/open_conference_ware/tracks/index.html.erb_spec.rb +56 -0
- data/spec/views/open_conference_ware/tracks/new.html.erb_spec.rb +26 -0
- data/spec/views/open_conference_ware/tracks/show.html.erb_spec.rb +23 -0
- data/spec/views/open_conference_ware/user_favorites/index.html.erb_spec.rb +29 -0
- data/spec/views/open_conference_ware/users/index_spec.rb +24 -0
- data/util/add_id3_tags_to_mp3.rb +57 -0
- data/util/schedule_demo.rb +36 -0
- data/util/seed_schedule.rb +61 -0
- data/util/sessions_to_lanyrd.rb +166 -0
- data/util/transfer_schedule_items.rb +25 -0
- data/util/update_proposal_status_from_voting_spreadsheet.rb +26 -0
- data/util/user_favorites_contention_report.rb +42 -0
- data/util/user_favorites_contention_report.sh +9 -0
- data/vendor/assets/fonts/glyphicons-halflings-regular.eot +0 -0
- data/vendor/assets/fonts/glyphicons-halflings-regular.svg +228 -0
- data/vendor/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/vendor/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/vendor/assets/images/farbtastic/marker.png +0 -0
- data/vendor/assets/images/farbtastic/mask.png +0 -0
- data/vendor/assets/images/farbtastic/wheel.png +0 -0
- data/vendor/assets/images/idselector/aol.ico +0 -0
- data/vendor/assets/images/idselector/arrow.gif +0 -0
- data/vendor/assets/images/idselector/arrow_white_back.png +0 -0
- data/vendor/assets/images/idselector/arrow_white_forward.png +0 -0
- data/vendor/assets/images/idselector/blogger.ico +0 -0
- data/vendor/assets/images/idselector/claimid.ico +0 -0
- data/vendor/assets/images/idselector/flickr.ico +0 -0
- data/vendor/assets/images/idselector/google.ico +0 -0
- data/vendor/assets/images/idselector/lj.ico +0 -0
- data/vendor/assets/images/idselector/myopenid.ico +0 -0
- data/vendor/assets/images/idselector/openid.ico +0 -0
- data/vendor/assets/images/idselector/technorati.ico +0 -0
- data/vendor/assets/images/idselector/verisign.ico +0 -0
- data/vendor/assets/images/idselector/vidoop2.ico +0 -0
- data/vendor/assets/images/idselector/vox.ico +0 -0
- data/vendor/assets/images/idselector/yahoo.ico +0 -0
- data/vendor/assets/javascripts/audiojs/audio.min.js +23 -0
- data/vendor/assets/javascripts/audiojs/audiojs.swf +0 -0
- data/vendor/assets/javascripts/audiojs/player-graphics.gif +0 -0
- data/vendor/assets/javascripts/bootstrap.js +1999 -0
- data/vendor/assets/javascripts/farbtastic.js +329 -0
- data/vendor/assets/javascripts/html5shiv.js +8 -0
- data/vendor/assets/javascripts/idselector.js +538 -0
- data/vendor/assets/javascripts/idselector~original.js +532 -0
- data/vendor/assets/javascripts/jquery-migrate-1.2.1.js +521 -0
- data/vendor/assets/javascripts/jquery.localScroll.js +106 -0
- data/vendor/assets/javascripts/jquery.scrollTo.js +174 -0
- data/vendor/assets/javascripts/respond.min.js +6 -0
- data/vendor/assets/stylesheets/bootstrap-theme.css +384 -0
- data/vendor/assets/stylesheets/bootstrap.css +6805 -0
- data/vendor/assets/stylesheets/farbtastic.css.scss +38 -0
- data/vendor/assets/stylesheets/persona-buttons.css +229 -0
- data/vendor/assets/stylesheets/reset-fonts-grids.css +7 -0
- metadata +1174 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe OpenConferenceWare::AuthenticationsController do
|
|
4
|
+
routes { OpenConferenceWare::Engine.routes }
|
|
5
|
+
|
|
6
|
+
describe "GET sign_in" do
|
|
7
|
+
before { get :sign_in }
|
|
8
|
+
|
|
9
|
+
it "renders the sign_in template" do
|
|
10
|
+
expect(response).to render_template("sign_in")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "GET create" do
|
|
15
|
+
context "with no auth hash" do
|
|
16
|
+
before { get :create }
|
|
17
|
+
|
|
18
|
+
it "redirects to the sign in page" do
|
|
19
|
+
expect(response).to redirect_to(sign_in_path)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context "with an auth hash" do
|
|
24
|
+
context "matching an existing User's Authentication" do
|
|
25
|
+
let(:existing_user) { create(:user) }
|
|
26
|
+
let(:authentication) { create(:authentication,
|
|
27
|
+
provider: 'existing',
|
|
28
|
+
user: existing_user) }
|
|
29
|
+
|
|
30
|
+
before do
|
|
31
|
+
OmniAuth.config.add_mock(:existing, {uid: authentication.uid})
|
|
32
|
+
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:existing]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
shared_examples_for "signs the user in" do
|
|
36
|
+
it "signs the user in" do
|
|
37
|
+
expect(controller.current_user).to eq existing_user
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context "when not already signed in" do
|
|
42
|
+
before { get :create }
|
|
43
|
+
include_examples "signs the user in"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context "when already signed in" do
|
|
47
|
+
before { login_as(create(:user)) }
|
|
48
|
+
before { get :create }
|
|
49
|
+
include_examples "signs the user in"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "containing an unknown UID" do
|
|
54
|
+
describe "when already signed in" do
|
|
55
|
+
let(:logged_in_user) { create(:user) }
|
|
56
|
+
let(:uid) { "logged-in:#{Time.now.to_i}" }
|
|
57
|
+
|
|
58
|
+
before do
|
|
59
|
+
login_as(logged_in_user)
|
|
60
|
+
OmniAuth.config.add_mock(:logged_in, {uid: uid})
|
|
61
|
+
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:logged_in]
|
|
62
|
+
|
|
63
|
+
get :create
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "associates the new Authentication with the signed-in user" do
|
|
67
|
+
expect(logged_in_user.authentications.map(&:uid)).to include(uid)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe "when not signed in" do
|
|
72
|
+
let(:uid) { "new-user:#{Time.now.to_i}" }
|
|
73
|
+
before do
|
|
74
|
+
OmniAuth.config.add_mock(:new_user, {uid: uid})
|
|
75
|
+
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:new_user]
|
|
76
|
+
|
|
77
|
+
get :create
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "signs in as a new user" do
|
|
81
|
+
expect(controller.current_user.authentications.first.uid).to eq uid
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe OpenConferenceWare::CommentsController do
|
|
4
|
+
render_views
|
|
5
|
+
fixtures :all
|
|
6
|
+
routes { OpenConferenceWare::Engine.routes }
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
@event = events(:open)
|
|
10
|
+
@proposal = proposals(:quentin_widgets)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "index" do
|
|
14
|
+
shared_examples_for "shared forbidden index behaviors" do
|
|
15
|
+
describe "HTML" do
|
|
16
|
+
before do
|
|
17
|
+
get :index
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should get redirect" do
|
|
21
|
+
response.should be_redirect
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
shared_examples_for "shared allowed index behaviors" do
|
|
27
|
+
describe "Atom" do
|
|
28
|
+
it "should get error if not key was specified" do
|
|
29
|
+
get :index, format: "atom"
|
|
30
|
+
|
|
31
|
+
response.should_not be_success
|
|
32
|
+
response.should_not be_redirect
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should get error if key is wrong" do
|
|
36
|
+
get :index, format: "atom", secret: "MEOW"
|
|
37
|
+
|
|
38
|
+
response.should_not be_success
|
|
39
|
+
response.should_not be_redirect
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should get data if key is right" do
|
|
43
|
+
get :index, format: "atom", secret: OpenConferenceWare::CommentsController::SECRET
|
|
44
|
+
|
|
45
|
+
response.should be_success
|
|
46
|
+
comments = assigns(:comments)
|
|
47
|
+
struct = Hash.from_xml(response.body)
|
|
48
|
+
struct['feed']['entry'].size.should == comments.size
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "anonymous user" do
|
|
54
|
+
it_should_behave_like "shared forbidden index behaviors"
|
|
55
|
+
it_should_behave_like "shared allowed index behaviors"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe "mortal user" do
|
|
59
|
+
before do
|
|
60
|
+
login_as :quentin
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it_should_behave_like "shared forbidden index behaviors"
|
|
64
|
+
it_should_behave_like "shared allowed index behaviors"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe "admin user" do
|
|
68
|
+
before do
|
|
69
|
+
login_as :aaron
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
after do
|
|
73
|
+
logout
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it_should_behave_like "shared allowed index behaviors"
|
|
77
|
+
|
|
78
|
+
describe "HTML" do
|
|
79
|
+
before do
|
|
80
|
+
get :index
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "should display comments" do
|
|
84
|
+
response.should be_success
|
|
85
|
+
assigns(:comments).size.should > 0
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe "create" do
|
|
92
|
+
it "should reject comments from bots" do
|
|
93
|
+
post :create, proposal_id: @proposal.to_param, quagmire: "omg"
|
|
94
|
+
|
|
95
|
+
flash[:failure].should match(/robot/i)
|
|
96
|
+
response.should be_redirect
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "should fail on empty comment" do
|
|
100
|
+
email = "bubba@smith.com"
|
|
101
|
+
message = "Yo"
|
|
102
|
+
post :create, proposal_id: @proposal.to_param, comment: {email: "bubba@smith.com"}
|
|
103
|
+
|
|
104
|
+
flash.keys.should include(:failure)
|
|
105
|
+
assigns(:comment).should_not be_valid
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "should fail on incomplete comment" do
|
|
109
|
+
post :create, proposal_id: @proposal.to_param, comment: {email: "bubba@smith.com", message: ""}
|
|
110
|
+
|
|
111
|
+
flash.keys.should include(:failure)
|
|
112
|
+
assigns(:comment).should_not be_valid
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "should create new comment" do
|
|
116
|
+
email = "bubba@smith.com"
|
|
117
|
+
message = "Yo"
|
|
118
|
+
post :create, proposal_id: @proposal.to_param, comment: {email: email, message: message}
|
|
119
|
+
|
|
120
|
+
assigns(:comment).should be_valid
|
|
121
|
+
flash.keys.should_not include(:failure)
|
|
122
|
+
response.should redirect_to(proposal_url(@proposal, commented: true))
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "should assign email if logged in" do
|
|
126
|
+
login_as :quentin
|
|
127
|
+
post :create, proposal_id: @proposal.to_param, comment: {message: "Yo"}
|
|
128
|
+
|
|
129
|
+
comment = assigns(:comment)
|
|
130
|
+
comment.email.should == users(:quentin).email
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe "destroy" do
|
|
135
|
+
it "should destroy" do
|
|
136
|
+
login_as :aaron
|
|
137
|
+
comment = comments(:clio_chupacabras_fbi)
|
|
138
|
+
Comment.should_receive(:find).with(comment.to_param).and_return(comment)
|
|
139
|
+
comment.should_receive(:destroy)
|
|
140
|
+
delete :destroy, id: comment.to_param, format: :html
|
|
141
|
+
|
|
142
|
+
flash.keys.should include(:success)
|
|
143
|
+
# response.should be_redirect # TODO why not?
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe OpenConferenceWare::EventsController, "when displaying events" do
|
|
4
|
+
render_views
|
|
5
|
+
fixtures :all
|
|
6
|
+
routes { OpenConferenceWare::Engine.routes }
|
|
7
|
+
|
|
8
|
+
describe "index" do
|
|
9
|
+
it "should display error if there's no current event" do
|
|
10
|
+
Event.should_receive(:current).at_least(:once).and_return(nil)
|
|
11
|
+
get :index
|
|
12
|
+
|
|
13
|
+
response.should be_success
|
|
14
|
+
flash.keys.should include(:failure)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should display a list of events" do
|
|
18
|
+
get :index
|
|
19
|
+
|
|
20
|
+
response.should be_success
|
|
21
|
+
assigns(:events).should_not be_blank
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe "show" do
|
|
26
|
+
describe "non-existent event" do
|
|
27
|
+
before do
|
|
28
|
+
get :show, id: -1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should display error" do
|
|
32
|
+
flash.keys.should include(:failure)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should redirect to current event" do
|
|
36
|
+
response.should redirect_to(event_path(events(:open)))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe "extant event" do
|
|
41
|
+
before do
|
|
42
|
+
@event = events(:closed)
|
|
43
|
+
get :show, id: @event.slug
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should display event" do
|
|
47
|
+
response.should redirect_to(event_proposals_path(@event))
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe "speakers" do
|
|
53
|
+
before do
|
|
54
|
+
@event = events(:open)
|
|
55
|
+
stub_current_event!(event: @event)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe "before proposals statuses published" do
|
|
59
|
+
before do
|
|
60
|
+
@event.stub(:proposal_status_published? => false)
|
|
61
|
+
|
|
62
|
+
get :speakers, id: @event.to_param
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should redirect to event's proposals" do
|
|
66
|
+
response.should redirect_to(event_proposals_path(@event))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "should display a flash error" do
|
|
70
|
+
flash[:failure].should_not be_blank
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe "after proposals statuses published" do
|
|
76
|
+
before do
|
|
77
|
+
@event.stub(:proposal_status_published? => true)
|
|
78
|
+
@event.stub(:schedule_published? => true)
|
|
79
|
+
|
|
80
|
+
get :speakers, id: @event.to_param
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "should get a speaker's page" do
|
|
84
|
+
response.should be_success
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "should see speakers" do
|
|
88
|
+
response.body.should have_selector(".fn", text: /#{users(:quentin).fullname}/)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "should see sessions" do
|
|
92
|
+
response.body.should have_selector(".summary", text: proposals(:postgresql_session).title)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "should not see non-confirmed proposals" do
|
|
96
|
+
response.body.should_not have_selector(".summary", text: proposals(:clio_chupacabras).title)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe OpenConferenceWare::Manage::EventsController do
|
|
4
|
+
render_views
|
|
5
|
+
fixtures :all
|
|
6
|
+
routes { OpenConferenceWare::Engine.routes }
|
|
7
|
+
|
|
8
|
+
before(:each) do
|
|
9
|
+
@event = events(:open)
|
|
10
|
+
login_as users(:aaron)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should retreive event show page" do
|
|
14
|
+
get :index, id: @event.slug
|
|
15
|
+
|
|
16
|
+
response.should be_success
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should retrieve new event form" do
|
|
20
|
+
get :new, id: @event.slug
|
|
21
|
+
|
|
22
|
+
response.should be_success
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should retrieve edit event form" do
|
|
26
|
+
get :edit, id: @event.slug
|
|
27
|
+
|
|
28
|
+
response.should be_success
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should update event" do
|
|
32
|
+
stub_current_event!(event: @event)
|
|
33
|
+
attributes = { "title" => "omgwtfbbq" }
|
|
34
|
+
@event.should_receive(:assign_attributes).with(attributes)
|
|
35
|
+
|
|
36
|
+
put :update, id: @event.slug, event: attributes
|
|
37
|
+
|
|
38
|
+
response.should be_redirect
|
|
39
|
+
flash[:notice].should_not be_blank
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should create event"
|
|
43
|
+
|
|
44
|
+
it "should destroy event"
|
|
45
|
+
|
|
46
|
+
def setup_proposals(&block)
|
|
47
|
+
@proposal_ids = ""
|
|
48
|
+
@proposals = []
|
|
49
|
+
%w[aaron_aardvarks quentin_widgets].each do |slug|
|
|
50
|
+
proposal = proposals(slug)
|
|
51
|
+
block.call proposal
|
|
52
|
+
@proposal_ids << "#{proposal.id},"
|
|
53
|
+
@proposals << proposal
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def assert_notified
|
|
58
|
+
response.should be_redirect
|
|
59
|
+
flash[:success].should =~ /aaron@example.com/
|
|
60
|
+
flash[:success].should =~ /quentin@example.com/
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "should raise an error if trying to notify speakers other than accepted or rejected" do
|
|
64
|
+
setup_proposals { |proposal| proposal.accept! }
|
|
65
|
+
lambda { post :notify_speakers, { id: @event.slug, proposal_ids: @proposal_ids } }.should raise_error(ArgumentError)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "should skip proposals that don't exist" do
|
|
69
|
+
setup_proposals { |proposal| proposal.accept! }
|
|
70
|
+
post :notify_speakers, { id: @event.slug, proposal_ids: @proposal_ids+',999', proposal_status: 'accepted' }
|
|
71
|
+
|
|
72
|
+
assert_notified
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "should skip proposals that have already been notified" do
|
|
76
|
+
setup_proposals do |proposal|
|
|
77
|
+
proposal.accept!
|
|
78
|
+
proposal.notified_at = Time.now
|
|
79
|
+
proposal.save
|
|
80
|
+
end
|
|
81
|
+
post :notify_speakers, { id: @event.slug, proposal_ids: @proposal_ids, proposal_status: 'accepted' }
|
|
82
|
+
|
|
83
|
+
assert_notified
|
|
84
|
+
flash[:success].should =~ /none/
|
|
85
|
+
flash[:success].should =~ /already been notified/
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "should notify accepted speakers" do
|
|
89
|
+
setup_proposals { |proposal| proposal.accept! }
|
|
90
|
+
post :notify_speakers, { id: @event.slug, proposal_ids: @proposal_ids, proposal_status: 'accepted' }
|
|
91
|
+
|
|
92
|
+
assert_notified
|
|
93
|
+
flash[:success].should_not =~ /already been notified/
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "should notify rejected speakers" do
|
|
97
|
+
setup_proposals { |proposal| proposal.reject! }
|
|
98
|
+
post :notify_speakers, { id: @event.slug, proposal_ids: @proposal_ids, proposal_status: 'rejected' }
|
|
99
|
+
|
|
100
|
+
assert_notified
|
|
101
|
+
flash[:success].should_not =~ /already been notified/
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,1273 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe OpenConferenceWare::ProposalsController do
|
|
4
|
+
render_views
|
|
5
|
+
fixtures :all
|
|
6
|
+
routes { OpenConferenceWare::Engine.routes }
|
|
7
|
+
|
|
8
|
+
# Return an array of Proposal objects extracted from the response body.
|
|
9
|
+
def extract_proposals
|
|
10
|
+
return assert_select('.proposal_row').map{|n| Proposal.find(n.attributes['id'].gsub(/^proposal_row_/, ''))}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
before do
|
|
14
|
+
@event = events(:open)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "index" do
|
|
18
|
+
describe "when returning HTML" do
|
|
19
|
+
before do
|
|
20
|
+
get :index, event_id: @event.slug
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should be successful" do
|
|
24
|
+
response.should be_success
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should assign an event" do
|
|
28
|
+
assigns(:event).should == @event
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should assign proposals" do
|
|
32
|
+
assigns(:proposals).should_not be_blank
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe "when returning CSV" do
|
|
37
|
+
|
|
38
|
+
def get_csv_index
|
|
39
|
+
OpenConferenceWare.stub(have_user_profiles: true)
|
|
40
|
+
OpenConferenceWare.stub(have_multiple_presenters: true)
|
|
41
|
+
stub_current_event!(event: @event)
|
|
42
|
+
|
|
43
|
+
get :index, event_id: @event.to_param, format: "csv"
|
|
44
|
+
|
|
45
|
+
@rows = CSV.parse(response.body)
|
|
46
|
+
@header = @rows.shift
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
shared_examples_for "shared CSV behaviors" do
|
|
50
|
+
|
|
51
|
+
it "should return CSV" do
|
|
52
|
+
@rows.should be_a_kind_of(Array)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should see public fields" do
|
|
56
|
+
@header.should include("Title")
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
shared_examples_for "shared non-admin CSV behaviors" do
|
|
61
|
+
it "should not see private fields" do
|
|
62
|
+
@header.should_not include("Emails")
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "anonymous user" do
|
|
67
|
+
before do
|
|
68
|
+
logout
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe "with visible schedule" do
|
|
72
|
+
before do
|
|
73
|
+
@controller.stub(:schedule_visible? => true)
|
|
74
|
+
get_csv_index
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it_should_behave_like "shared CSV behaviors"
|
|
78
|
+
|
|
79
|
+
it_should_behave_like "shared non-admin CSV behaviors"
|
|
80
|
+
|
|
81
|
+
it "should see schedule fields" do
|
|
82
|
+
@header.should include("Start Time")
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe "without visible schedule" do
|
|
87
|
+
before do
|
|
88
|
+
@controller.stub(:schedule_visible? => false)
|
|
89
|
+
get_csv_index
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it_should_behave_like "shared CSV behaviors"
|
|
93
|
+
|
|
94
|
+
it_should_behave_like "shared non-admin CSV behaviors"
|
|
95
|
+
|
|
96
|
+
it "should not see schedule fields" do
|
|
97
|
+
@header.should_not include("Start Time")
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe "mortal user" do
|
|
104
|
+
before do
|
|
105
|
+
login_as(:quentin)
|
|
106
|
+
get_csv_index
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it_should_behave_like "shared CSV behaviors"
|
|
110
|
+
|
|
111
|
+
it_should_behave_like "shared non-admin CSV behaviors"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe "admin user" do
|
|
115
|
+
before do
|
|
116
|
+
controller.stub(:admin?).and_return(true)
|
|
117
|
+
get_csv_index
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it_should_behave_like "shared CSV behaviors"
|
|
121
|
+
|
|
122
|
+
it "should see private fields" do
|
|
123
|
+
@header.should include("Emails")
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
shared_examples_for "when exporting" do
|
|
129
|
+
# Expects following to be set by implementor's #before block:
|
|
130
|
+
# - @proposals
|
|
131
|
+
# - @records
|
|
132
|
+
# - @record
|
|
133
|
+
|
|
134
|
+
it "should assign multiple items" do
|
|
135
|
+
@proposals.size.should >= 1
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "should export same number of items as assigned" do
|
|
139
|
+
@records.size.should == @proposals.size
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "should export presenter" do
|
|
143
|
+
@record.keys.should include('presenter')
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it "should not export email" do
|
|
147
|
+
@record.keys.should_not include('email')
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "should not export private notes" do
|
|
151
|
+
@record.keys.should_not include('note_to_organizers')
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
describe "when returning XML" do
|
|
156
|
+
before(:each) do
|
|
157
|
+
get :index, event_id: @event.slug, format: "xml"
|
|
158
|
+
|
|
159
|
+
@proposals = assigns(:proposals)
|
|
160
|
+
@struct = Hash.from_xml(response.body)
|
|
161
|
+
@records = @struct['open_conference_ware_proposals']
|
|
162
|
+
@record = @records.first
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it_should_behave_like "when exporting"
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe "when returning JSON" do
|
|
169
|
+
before(:each) do
|
|
170
|
+
get :index, event_id: @event.slug, format: "json"
|
|
171
|
+
|
|
172
|
+
@proposals = assigns(:proposals)
|
|
173
|
+
@struct = ActiveSupport::JSON.decode(response.body)
|
|
174
|
+
@records = @struct
|
|
175
|
+
@record = @records.first["proposal"]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it_should_behave_like "when exporting"
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
describe "when sorting" do
|
|
182
|
+
it "should sort proposals by title" do
|
|
183
|
+
get :index, sort: "title", event_id: @event.to_param
|
|
184
|
+
extracted = extract_proposals
|
|
185
|
+
|
|
186
|
+
extracted.size.should > 0
|
|
187
|
+
values = extracted.map(&:title)
|
|
188
|
+
expected = values.sort_by(&:downcase)
|
|
189
|
+
values.should == expected
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it "should sort proposals by track" do
|
|
193
|
+
get :index, sort: "track", event_id: @event.to_param
|
|
194
|
+
proposals = extract_proposals
|
|
195
|
+
|
|
196
|
+
proposals.size.should > 0
|
|
197
|
+
|
|
198
|
+
tracks_returned = proposals.map{|proposal| proposal.track.title}
|
|
199
|
+
tracks_expected = tracks_returned.sort_by(&:downcase)
|
|
200
|
+
tracks_returned.should == tracks_expected
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it "should sort proposals by title descending" do
|
|
204
|
+
get :index, sort: "title", dir: "desc", event_id: @event.to_param
|
|
205
|
+
proposals = extract_proposals
|
|
206
|
+
|
|
207
|
+
proposals.size.should > 0
|
|
208
|
+
|
|
209
|
+
titles_returned = proposals.map(&:title)
|
|
210
|
+
titles_expected = titles_returned.sort_by(&:downcase).reverse
|
|
211
|
+
titles_returned.should == titles_expected
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it "should sort proposals by start time" do
|
|
215
|
+
get :sessions_index, sort: "start_time", event_id: @event.to_param
|
|
216
|
+
proposals = extract_proposals
|
|
217
|
+
|
|
218
|
+
proposals.size.should > 0
|
|
219
|
+
|
|
220
|
+
values = proposals.map(&:start_time)
|
|
221
|
+
expected = values.sort
|
|
222
|
+
values.should == expected
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
it "should not sort proposals by forbidden field" do
|
|
226
|
+
Proposal.any_instance.should_not_receive(:destroy)
|
|
227
|
+
get :index, sort: "destroy", event_id: @event.to_param
|
|
228
|
+
|
|
229
|
+
# default to sorting by submitted_at
|
|
230
|
+
proposals = extract_proposals
|
|
231
|
+
proposals.size.should > 0
|
|
232
|
+
values = proposals.map(&:submitted_at)
|
|
233
|
+
expected = values.sort
|
|
234
|
+
values.should == expected
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
describe "when returning ATOM" do
|
|
240
|
+
def get_entry(proposal_symbol)
|
|
241
|
+
title = proposals(proposal_symbol).title
|
|
242
|
+
return @doc.xpath("//entry/title[text()='#{title}']")
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
describe "for /proposals.atom" do
|
|
246
|
+
before do
|
|
247
|
+
get :index, format: "atom"
|
|
248
|
+
@doc = Nokogiri.parse(response.body)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it "should include proposals from multiple events" do
|
|
252
|
+
get_entry(:clio_chupacabras).should_not be_empty
|
|
253
|
+
get_entry(:aaron_aardvarks).should_not be_empty
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
describe "for /events/:event_id/proposals.atom" do
|
|
258
|
+
before do
|
|
259
|
+
get :index, format: "atom", event_id: @event.slug
|
|
260
|
+
@doc = Nokogiri.parse(response.body)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
it "should include proposals from this event" do
|
|
264
|
+
get_entry(:aaron_aardvarks).should_not be_empty
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
it "should not include proposals from other events" do
|
|
268
|
+
get_entry(:clio_chupacabras).should be_empty
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
describe "sessions" do
|
|
276
|
+
it "should display session_text" do
|
|
277
|
+
event = stub_model(Event,
|
|
278
|
+
:proposal_status_published? => true,
|
|
279
|
+
id: 1234,
|
|
280
|
+
slug: 'event_slug',
|
|
281
|
+
session_text: "MySessionText",
|
|
282
|
+
populated_sessions: []
|
|
283
|
+
)
|
|
284
|
+
stub_current_event!(event: event)
|
|
285
|
+
|
|
286
|
+
get :sessions_index, event_id: event.to_param
|
|
287
|
+
response.body.should have_selector(".event_text.session_text") do |text|
|
|
288
|
+
text.should contain("MySessionText")
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
it "should display a list of sessions" do
|
|
293
|
+
proposal = stub_model(Proposal, state: "confirmed", users: [])
|
|
294
|
+
proposals = [proposal]
|
|
295
|
+
event = stub_model(Event,
|
|
296
|
+
:proposal_status_published? => true,
|
|
297
|
+
id: 1234,
|
|
298
|
+
slug: 'event_slug',
|
|
299
|
+
populated_sessions: proposals
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
stub_current_event!(event: event)
|
|
303
|
+
|
|
304
|
+
# Bypass #fetch_object because it can't cache our singleton doubles.
|
|
305
|
+
Proposal.stub(:fetch_object).and_return do |slug, callback|
|
|
306
|
+
callback.call
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
get :sessions_index, event_id: event.to_param
|
|
310
|
+
expect(assigns(:proposals)).to be_a_kind_of(proposals.class)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it "should redirect to proposals unless the proposal status is published" do
|
|
314
|
+
event = stub_model(Event, :proposal_status_published? => false, id: 1234, slug: 'event_slug')
|
|
315
|
+
stub_current_event!(event: event)
|
|
316
|
+
get :sessions_index, event_id: event.to_param
|
|
317
|
+
|
|
318
|
+
response.should redirect_to(event_proposals_url(event))
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
it "should redirect /sessions to proposals unless proposal status is published" do
|
|
322
|
+
event = stub_model(Event, :proposal_status_published? => false, id: 1234, slug: 'event_slug')
|
|
323
|
+
stub_current_event!(event: event, status: :assigned_to_current)
|
|
324
|
+
get :sessions_index, format: :html
|
|
325
|
+
|
|
326
|
+
response.should redirect_to(event_proposals_url(event))
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
it "should normalize /sessions if proposal status is published" do
|
|
330
|
+
event = stub_model(Event, :proposal_status_published? => true, id: 1234, slug: 'event_slug')
|
|
331
|
+
stub_current_event!(event: event, status: :assigned_to_current)
|
|
332
|
+
get :sessions_index, format: :html
|
|
333
|
+
|
|
334
|
+
response.should redirect_to(event_sessions_path(event))
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
it "should normalize /schedule if proposal status is published" do
|
|
338
|
+
event = stub_model(Event, :proposal_status_published? => true, :schedule_published? => true, id: 1234, slug: 'event_slug')
|
|
339
|
+
stub_current_event!(event: event, status: :assigned_to_current)
|
|
340
|
+
get :schedule, format: :html
|
|
341
|
+
|
|
342
|
+
response.should redirect_to(event_schedule_path(event))
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
describe "show" do
|
|
347
|
+
it "should display extant proposal" do
|
|
348
|
+
proposal = proposals(:quentin_widgets)
|
|
349
|
+
get :show, id: proposal.id
|
|
350
|
+
|
|
351
|
+
response.should be_success
|
|
352
|
+
assigns(:proposal).should == proposal
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
it "should redirect back to proposals list if asked to display a non-existent proposal" do
|
|
356
|
+
get :show, id: -1
|
|
357
|
+
|
|
358
|
+
flash[:failure].should_not be_blank
|
|
359
|
+
response.should redirect_to(proposals_url)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
it "should redirect back to proposals list if asked to display a proposal without an event" do
|
|
363
|
+
proposal = proposals(:quentin_widgets)
|
|
364
|
+
proposal.stub(event: nil)
|
|
365
|
+
Proposal.stub(find_by_id: proposal, find: proposal, lookup: proposal)
|
|
366
|
+
|
|
367
|
+
get :show, id: proposal.id
|
|
368
|
+
|
|
369
|
+
flash[:failure].should_not be_blank
|
|
370
|
+
response.should redirect_to(event_proposals_path(events(:open)))
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
describe "redirect" do
|
|
374
|
+
# Options:
|
|
375
|
+
# * published: Are proposal statuses published for this event?
|
|
376
|
+
# * confirmed: Is this proposal confirmed?
|
|
377
|
+
# * session: Is this proposal being accessed via a sessions#show route?
|
|
378
|
+
# * redirect: Redirect to where? (:proposal, :session, nil)
|
|
379
|
+
def assert_show(opts={}, &block)
|
|
380
|
+
@key = 123
|
|
381
|
+
@event.stub(:proposal_status_published?).and_return(opts[:published])
|
|
382
|
+
stub_current_event!(event: @event)
|
|
383
|
+
|
|
384
|
+
@users = []
|
|
385
|
+
@users.stub(:by_name).and_return([])
|
|
386
|
+
|
|
387
|
+
@proposal = stub_model(Proposal, id: @key, event: @event, track: @event.tracks.empty? ? nil : Track.first, users: @users)
|
|
388
|
+
@proposal.stub(:confirmed?).and_return(opts[:confirmed])
|
|
389
|
+
controller.stub(:get_proposal_and_assignment_status).and_return([@proposal, :assigned_via_param])
|
|
390
|
+
get opts[:session] ? :session_show : :show, id: @key
|
|
391
|
+
case opts[:redirect]
|
|
392
|
+
when :proposal
|
|
393
|
+
response.should redirect_to(proposal_path(@key))
|
|
394
|
+
when :session
|
|
395
|
+
response.should redirect_to(session_path(@key))
|
|
396
|
+
when nil, false
|
|
397
|
+
response.should be_success
|
|
398
|
+
else
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
describe "when status published" do
|
|
403
|
+
it "should redirect confirmed proposal to session" do
|
|
404
|
+
assert_show published: true, confirmed: true, session: false, redirect: :session
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
it "should redirect non-session to proposal" do
|
|
408
|
+
assert_show published: true, confirmed: false, session: true, redirect: :proposal
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
it "should display session" do
|
|
412
|
+
assert_show published: true, confirmed: true, session: true, redirect: false
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
it "should display proposal" do
|
|
416
|
+
assert_show published: true, confirmed: false, session: false, redirect: false
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
describe "when status not published" do
|
|
421
|
+
it "should allow admin to view sessions" do
|
|
422
|
+
login_as :aaron
|
|
423
|
+
assert_show published: false, confirmed: true, session: true, redirect: false
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
it "should redirect confirmed proposal to proposals" do
|
|
427
|
+
assert_show published: false, confirmed: true, session: true, redirect: :proposal
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
it "should redirect non-session to proposal" do
|
|
431
|
+
assert_show published: false, confirmed: false, session: true, redirect: :proposal
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
it "should display confirmed proposal" do
|
|
435
|
+
assert_show published: false, confirmed: true, session: false, redirect: false
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
it "should display session as proposal" do
|
|
439
|
+
assert_show published: false, confirmed: false, session: false, redirect: false
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
describe "non-current event" do
|
|
444
|
+
render_views false
|
|
445
|
+
it "should not redirect a published session of an old event if current event isn't publishing sesions" do
|
|
446
|
+
current_event = stub_model(Event, slug: 'new', proposal_status_published: false)
|
|
447
|
+
old_event = stub_model(Event, slug: 'old', proposal_status_published: true)
|
|
448
|
+
old_session_user = users(:clio)
|
|
449
|
+
old_session = stub_model(Proposal, status: 'confirmed', event: old_event)
|
|
450
|
+
old_session.users << old_session_user
|
|
451
|
+
|
|
452
|
+
Proposal.stub(find: old_session, find_by_id: old_session, lookup: old_session)
|
|
453
|
+
Event.stub(current: current_event)
|
|
454
|
+
|
|
455
|
+
get :session_show, id: old_session.id
|
|
456
|
+
response.should be_success
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
describe "accepted proposal" do
|
|
462
|
+
before do
|
|
463
|
+
@proposal = proposals(:quentin_widgets)
|
|
464
|
+
@proposal.accept!
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
it "should notify owners of acceptance" do
|
|
468
|
+
login_as(users(:quentin))
|
|
469
|
+
get :show, id: @proposal.id
|
|
470
|
+
response.body.should have_selector("h3", text: 'Congratulations')
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
it "should not notify non-owners of acceptance" do
|
|
474
|
+
get :show, id: @proposal.id
|
|
475
|
+
response.body.should_not have_selector("h3", text: 'Congratulations')
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
it "should not notify owners of acceptance if proposal confirmation controls are not visible" do
|
|
479
|
+
event = @proposal.event
|
|
480
|
+
event.stub(:show_proposal_confirmation_controls? => false)
|
|
481
|
+
Proposal.stub(lookup: @proposal)
|
|
482
|
+
|
|
483
|
+
login_as(users(:quentin))
|
|
484
|
+
|
|
485
|
+
get :show, id: @proposal.id
|
|
486
|
+
response.body.should_not have_selector("h3", text: 'Congratulations')
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
describe "not-accepted proposal" do
|
|
491
|
+
before do
|
|
492
|
+
login_as(users(:quentin))
|
|
493
|
+
@proposal = proposals(:quentin_widgets)
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
it "should not notify proposed proposal owners of acceptance" do
|
|
497
|
+
get :show, id: @proposal.id
|
|
498
|
+
response.body.should_not have_selector("h3", text: 'Congratulations')
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
it "should not notify rejected proposal owners of acceptance" do
|
|
502
|
+
@proposal.reject!
|
|
503
|
+
get :show, id: @proposal.id
|
|
504
|
+
response.body.should_not have_selector("h3", text: 'Congratulations')
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
it "should not notify junk proposal owners of acceptance" do
|
|
508
|
+
@proposal.mark_as_junk!
|
|
509
|
+
get :show, id: @proposal.id
|
|
510
|
+
response.body.should_not have_selector("h3", text: 'Congratulations')
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
describe "new" do
|
|
517
|
+
describe "for open event" do
|
|
518
|
+
describe "with user_profiles?" do
|
|
519
|
+
before(:each) do
|
|
520
|
+
OpenConferenceWare.stub(have_user_profiles: true)
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
it "should redirect incomplete profiles to user edit form" do
|
|
524
|
+
user = users(:incognito)
|
|
525
|
+
login_as(user)
|
|
526
|
+
get :new, event_id: events(:open).slug
|
|
527
|
+
|
|
528
|
+
flash.keys.should include(:notice)
|
|
529
|
+
response.should redirect_to(edit_user_path(user, require_complete_profile: true))
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
it "should allow users with complete profiles" do
|
|
533
|
+
login_as(:quentin)
|
|
534
|
+
get :new, event_id: events(:open).slug
|
|
535
|
+
|
|
536
|
+
flash.keys.should_not include(:failure)
|
|
537
|
+
response.should be_success
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
describe "without user_profiles?" do
|
|
542
|
+
before(:each) do
|
|
543
|
+
OpenConferenceWare.stub(have_user_profiles: false)
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
describe "with anonymous_proposals" do
|
|
547
|
+
before(:each) do
|
|
548
|
+
OpenConferenceWare.stub(have_anonymous_proposals: true)
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
it "should display form for open events" do
|
|
552
|
+
get :new, event_id: events(:open).slug
|
|
553
|
+
|
|
554
|
+
response.should be_success
|
|
555
|
+
assigns(:proposal).should be_true
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
it "should not assign presenter if anonymous" do
|
|
559
|
+
logout
|
|
560
|
+
get :new, event_id: events(:open).slug
|
|
561
|
+
|
|
562
|
+
response.should be_success
|
|
563
|
+
proposal = assigns(:proposal)
|
|
564
|
+
proposal.presenter.should be_blank
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
describe "without anonymous_proposals" do
|
|
569
|
+
before(:each) do
|
|
570
|
+
OpenConferenceWare.stub(have_anonymous_proposals: false)
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
it "should redirect anonymous user to login" do
|
|
574
|
+
get :new, event_id: events(:open).slug
|
|
575
|
+
|
|
576
|
+
flash.keys.should include(:notice)
|
|
577
|
+
response.should redirect_to(sign_in_path)
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
it "should assign presenter if logged in" do
|
|
582
|
+
user = users(:quentin)
|
|
583
|
+
login_as(user)
|
|
584
|
+
get :new, event_id: events(:open).slug
|
|
585
|
+
|
|
586
|
+
response.should be_success
|
|
587
|
+
proposal = assigns(:proposal)
|
|
588
|
+
proposal.presenter.should == user.fullname
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
describe "when an event can have tracks" do
|
|
592
|
+
it "should assign a track if there's only one" do
|
|
593
|
+
event = create(:event)
|
|
594
|
+
event.session_types << build(:session_type)
|
|
595
|
+
track = create(:track, event: event)
|
|
596
|
+
user = create(:user)
|
|
597
|
+
login_as(user)
|
|
598
|
+
|
|
599
|
+
get :new, event_id: event.slug
|
|
600
|
+
|
|
601
|
+
flash[:failure].should be_nil
|
|
602
|
+
assigns(:proposal).track.should == track
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
it "should not assign a track if there's more than one" do
|
|
606
|
+
event = create(:event)
|
|
607
|
+
event.session_types << build(:session_type)
|
|
608
|
+
track1 = create(:track, event: event)
|
|
609
|
+
track2 = create(:track, event: event)
|
|
610
|
+
user = create(:user)
|
|
611
|
+
login_as(user)
|
|
612
|
+
|
|
613
|
+
get :new, event_id: event.slug
|
|
614
|
+
|
|
615
|
+
flash[:failure].should be_nil
|
|
616
|
+
assigns(:proposal).track.should be_nil
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
describe "when event can have session types" do
|
|
621
|
+
it "should assign a session type if there's only one" do
|
|
622
|
+
event = create(:event)
|
|
623
|
+
event.tracks << build(:track)
|
|
624
|
+
session_type = create(:session_type, event: event)
|
|
625
|
+
user = create(:user)
|
|
626
|
+
login_as(user)
|
|
627
|
+
|
|
628
|
+
get :new, event_id: event.slug
|
|
629
|
+
|
|
630
|
+
assigns(:proposal).session_type.should == session_type
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
it "should not assign a session type if there's more than one" do
|
|
634
|
+
event = create(:event)
|
|
635
|
+
event.tracks << build(:track)
|
|
636
|
+
session_type1 = create(:session_type, event: event)
|
|
637
|
+
session_type2 = create(:session_type, event: event)
|
|
638
|
+
user = create(:user)
|
|
639
|
+
login_as(user)
|
|
640
|
+
|
|
641
|
+
get :new, event_id: event.slug
|
|
642
|
+
|
|
643
|
+
assigns(:proposal).session_type.should be_nil
|
|
644
|
+
end
|
|
645
|
+
end
|
|
646
|
+
end
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
describe "with closed event" do
|
|
650
|
+
it "should not display form" do
|
|
651
|
+
login_as(users(:quentin))
|
|
652
|
+
event = events(:closed)
|
|
653
|
+
get :new, event_id: event.to_param
|
|
654
|
+
|
|
655
|
+
response.should redirect_to(event_proposals_path(event))
|
|
656
|
+
end
|
|
657
|
+
end
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
describe "edit" do
|
|
661
|
+
before do
|
|
662
|
+
@proposal = proposals(:quentin_widgets)
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
shared_examples_for "shared allowed edit behaviors" do
|
|
666
|
+
it "should not redirect with failure" do
|
|
667
|
+
get :edit, id: @proposal.id, event_id: @event.to_param
|
|
668
|
+
flash.keys.should_not include(:failure)
|
|
669
|
+
response.should be_success
|
|
670
|
+
end
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
shared_examples_for "shared forbidden edit behaviors" do
|
|
674
|
+
it "should redirect with failure" do
|
|
675
|
+
get :edit, id: @proposal.id, event_id: @event.to_param
|
|
676
|
+
flash.keys.should include(:failure)
|
|
677
|
+
response.should redirect_to(proposal_path(@proposal))
|
|
678
|
+
end
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
describe "anonymous user" do
|
|
682
|
+
before(){ logout }
|
|
683
|
+
|
|
684
|
+
it "should redirect to login" do
|
|
685
|
+
get :edit, id: @proposal.id, event_id: @event.to_param
|
|
686
|
+
response.should redirect_to(sign_in_path)
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
describe "non-owner mortal user" do
|
|
691
|
+
before(){ login_as :clio }
|
|
692
|
+
it_should_behave_like "shared forbidden edit behaviors"
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
describe "owner mortal user" do
|
|
696
|
+
before(){ login_as :quentin }
|
|
697
|
+
it_should_behave_like "shared allowed edit behaviors"
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
describe "admin user" do
|
|
701
|
+
before { login_as :aaron }
|
|
702
|
+
it_should_behave_like "shared allowed edit behaviors"
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
describe "when closed" do
|
|
706
|
+
it "should redirect if owner tries to edit proposal for closed event" do
|
|
707
|
+
proposal = proposals(:clio_chupacabras)
|
|
708
|
+
login_as :clio
|
|
709
|
+
get :edit, id: proposal.id
|
|
710
|
+
|
|
711
|
+
pending "FIXME when should people not be able to edit proposals?"
|
|
712
|
+
response.should redirect_to(event_proposals_path(proposal.event))
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
it "should allow admin to edit" do
|
|
716
|
+
proposal = proposals(:clio_chupacabras)
|
|
717
|
+
login_as :aaron
|
|
718
|
+
get :edit, id: proposal.id
|
|
719
|
+
|
|
720
|
+
response.should be_success
|
|
721
|
+
assigns(:proposal).should == proposal
|
|
722
|
+
end
|
|
723
|
+
end
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
describe "create" do
|
|
727
|
+
# Try to create a proposal.
|
|
728
|
+
#
|
|
729
|
+
# Arguments:
|
|
730
|
+
# * login: User to login as, can be nil for none, symbol or user object.
|
|
731
|
+
# * inputs: Hash of properties to create a proposal from.
|
|
732
|
+
def assert_create(login=nil, inputs={}, &block)
|
|
733
|
+
login ? login_as(login) : logout
|
|
734
|
+
# TODO extract :commit into separate argument
|
|
735
|
+
post :create, inputs.reverse_merge(commit: 'really')
|
|
736
|
+
@record = assigns(:proposal)
|
|
737
|
+
block.call
|
|
738
|
+
end
|
|
739
|
+
|
|
740
|
+
before do
|
|
741
|
+
# TODO test other settings combinations
|
|
742
|
+
OpenConferenceWare.stub(have_proposal_excerpts: false)
|
|
743
|
+
OpenConferenceWare.stub(have_multiple_presenters: false)
|
|
744
|
+
OpenConferenceWare.stub(have_user_profiles: false)
|
|
745
|
+
|
|
746
|
+
@inputs = proposals(:quentin_widgets).attributes
|
|
747
|
+
@record = nil
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
describe "with user_profiles?" do
|
|
751
|
+
before(:each) do
|
|
752
|
+
OpenConferenceWare.stub(have_user_profiles: true)
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
it "should fail to create proposal without a complete user" do
|
|
756
|
+
user = users(:quentin)
|
|
757
|
+
user.should_receive(:complete_profile?).at_least(:once).and_return(false)
|
|
758
|
+
User.should_receive(:find).and_return(user)
|
|
759
|
+
proposal = Proposal.new(@inputs)
|
|
760
|
+
proposal.users << user
|
|
761
|
+
Proposal.should_receive(:new).and_return(proposal)
|
|
762
|
+
assert_create(user, event_id: @event.slug, proposal: @inputs) do
|
|
763
|
+
response.should be_success
|
|
764
|
+
proposal = assigns(:proposal)
|
|
765
|
+
proposal.should_not be_valid
|
|
766
|
+
end
|
|
767
|
+
end
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
describe "without user_profiles?" do
|
|
771
|
+
before(:each) do
|
|
772
|
+
OpenConferenceWare.stub(have_user_profiles: false)
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
describe "with anonymous proposals" do
|
|
776
|
+
before(:each) do
|
|
777
|
+
OpenConferenceWare.stub(have_anonymous_proposals: true)
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
it "should create proposal for anonymous user" do
|
|
781
|
+
assert_create(nil, event_id: @event.slug, proposal: @inputs) do
|
|
782
|
+
proposal = assigns(:proposal)
|
|
783
|
+
proposal.should be_valid
|
|
784
|
+
proposal.id.should_not be_nil
|
|
785
|
+
end
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
it "should preview proposal for anonymous user" do
|
|
789
|
+
@inputs['title'] = ''
|
|
790
|
+
assert_create(nil, event_id: @event.slug, proposal: @inputs, submit: nil, preview: 'Preview') do
|
|
791
|
+
proposal = assigns(:proposal)
|
|
792
|
+
proposal.errors.should_not be_empty
|
|
793
|
+
proposal.should_not be_valid
|
|
794
|
+
proposal.id.should be_nil
|
|
795
|
+
end
|
|
796
|
+
end
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
describe "without anonymous proposals" do
|
|
800
|
+
before(:each) do
|
|
801
|
+
OpenConferenceWare.stub(have_anonymous_proposals: false)
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
it "should not create proposal for anonymous user" do
|
|
805
|
+
assert_create(nil, event_id: @event.slug, proposal: @inputs) do
|
|
806
|
+
response.should redirect_to(sign_in_path)
|
|
807
|
+
end
|
|
808
|
+
end
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
it "should create proposal for mortal user" do
|
|
812
|
+
assert_create(:quentin, event_id: @event.slug, proposal: @inputs) do
|
|
813
|
+
proposal = assigns(:proposal)
|
|
814
|
+
proposal.should be_valid
|
|
815
|
+
proposal.id.should_not be_nil
|
|
816
|
+
end
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
it "should fail to create proposal without a presenter" do
|
|
820
|
+
inputs = @inputs.clone
|
|
821
|
+
inputs['presenter'] = nil
|
|
822
|
+
assert_create(:quentin, event_id: @event.slug, proposal: inputs) do
|
|
823
|
+
response.should be_success
|
|
824
|
+
proposal = assigns(:proposal)
|
|
825
|
+
proposal.should_not be_valid
|
|
826
|
+
end
|
|
827
|
+
end
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
describe "success page" do
|
|
831
|
+
before(:each) do
|
|
832
|
+
login_as(:quentin)
|
|
833
|
+
@proposal = stub_model(Proposal, id: 123)
|
|
834
|
+
@proposal.should_receive(:save).and_return(true)
|
|
835
|
+
@proposal.should_receive(:add_user).and_return(true)
|
|
836
|
+
Proposal.should_receive(:new).and_return(@proposal)
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
it "should display success page" do
|
|
840
|
+
@controller.should_receive(:render).and_return("My HTML here")
|
|
841
|
+
|
|
842
|
+
post :create, commit: "Create", proposal: {foo: 'bar'}
|
|
843
|
+
end
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
end
|
|
847
|
+
|
|
848
|
+
describe "update" do
|
|
849
|
+
def assert_update(login=nil, inputs={}, optional_params={}, &block)
|
|
850
|
+
login ? login_as(login) : logout
|
|
851
|
+
optional_params.reverse_merge commit: 'really'
|
|
852
|
+
put :update, { id: ( inputs['id'] || inputs[:id] ), proposal: inputs }.merge(optional_params)
|
|
853
|
+
block.call
|
|
854
|
+
end
|
|
855
|
+
|
|
856
|
+
before do
|
|
857
|
+
@user = users(:quentin)
|
|
858
|
+
@proposal = proposals(:quentin_widgets)
|
|
859
|
+
@inputs = @proposal.attributes
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
it "should prevent editing of title when proposal titles are locked" do
|
|
863
|
+
@event = stub_current_event!
|
|
864
|
+
@event.stub(:proposal_titles_locked?).and_return(true)
|
|
865
|
+
@controller.stub(:get_proposal_and_assignment_status).and_return(@proposal)
|
|
866
|
+
@proposal.stub(:event).and_return(@event)
|
|
867
|
+
|
|
868
|
+
assert_update(:quentin, id: @proposal.id, title: 'OMG') do
|
|
869
|
+
@proposal.reload
|
|
870
|
+
@proposal.title.should_not == 'OMG'
|
|
871
|
+
end
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
it "should redirect anonymous user to login" do
|
|
875
|
+
assert_update(nil, @inputs) do
|
|
876
|
+
response.should redirect_to(sign_in_path)
|
|
877
|
+
end
|
|
878
|
+
end
|
|
879
|
+
|
|
880
|
+
it "should reject non-owner mortal user" do
|
|
881
|
+
assert_update(:clio, @inputs) do
|
|
882
|
+
flash.keys.should include(:failure)
|
|
883
|
+
response.should redirect_to(proposal_url(@proposal))
|
|
884
|
+
end
|
|
885
|
+
end
|
|
886
|
+
|
|
887
|
+
describe "when settings status" do
|
|
888
|
+
it "should allow admin to change status" do
|
|
889
|
+
@inputs[:transition] = 'accept'
|
|
890
|
+
@controller.should_receive(:get_proposal_and_assignment_status).and_return([@proposal, :assigned_via_param])
|
|
891
|
+
@proposal.should_receive(:accept!)
|
|
892
|
+
assert_update(:aaron, @inputs) do
|
|
893
|
+
# Everything is done through the should_receive
|
|
894
|
+
end
|
|
895
|
+
end
|
|
896
|
+
|
|
897
|
+
it "should not allow non-admin to change status" do
|
|
898
|
+
@inputs[:transition] = 'accept'
|
|
899
|
+
@controller.should_receive(:get_proposal_and_assignment_status).and_return([@proposal, :assigned_via_param])
|
|
900
|
+
@proposal.should_not_receive(:accept!)
|
|
901
|
+
assert_update(:quentin, @inputs) do
|
|
902
|
+
end
|
|
903
|
+
end
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
describe "with user_profiles?" do
|
|
907
|
+
before(:each) do
|
|
908
|
+
OpenConferenceWare.stub(have_user_profiles: true)
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
it "should specify update behavior"
|
|
912
|
+
end
|
|
913
|
+
|
|
914
|
+
describe "without user_profiles?" do
|
|
915
|
+
before(:each) do
|
|
916
|
+
OpenConferenceWare.stub(have_user_profiles: false)
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
it "should display edit form if fields are invalid" do
|
|
920
|
+
inputs = @inputs.clone
|
|
921
|
+
inputs['presenter'] = nil
|
|
922
|
+
assert_update(:quentin, inputs) do
|
|
923
|
+
response.should be_success
|
|
924
|
+
response.should render_template('edit')
|
|
925
|
+
end
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
it "should allow owner mortal user" do
|
|
929
|
+
assert_update(:quentin, @inputs) do
|
|
930
|
+
flash.keys.should include(:success)
|
|
931
|
+
response.should redirect_to(proposal_url(@proposal))
|
|
932
|
+
end
|
|
933
|
+
end
|
|
934
|
+
|
|
935
|
+
it "should display preview" do
|
|
936
|
+
assert_update(:quentin, @inputs, { commit: nil, preview: 'Preview' }) do
|
|
937
|
+
response.should be_success
|
|
938
|
+
response.should render_template('edit')
|
|
939
|
+
end
|
|
940
|
+
end
|
|
941
|
+
|
|
942
|
+
it "should allow admin user" do
|
|
943
|
+
assert_update(:aaron, @inputs) do
|
|
944
|
+
flash.keys.should include(:success)
|
|
945
|
+
response.should redirect_to(proposal_url(@proposal))
|
|
946
|
+
end
|
|
947
|
+
end
|
|
948
|
+
end
|
|
949
|
+
end
|
|
950
|
+
|
|
951
|
+
describe "delete" do
|
|
952
|
+
before do
|
|
953
|
+
@proposal = proposals(:quentin_widgets)
|
|
954
|
+
Proposal.stub(:lookup).and_return(@proposal)
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
def assert_delete(login=nil, &block)
|
|
958
|
+
login ? login_as(login) : logout
|
|
959
|
+
delete :destroy, id: @proposal.id
|
|
960
|
+
block.call
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
it "should ask anonymous to login" do
|
|
964
|
+
@proposal.should_not_receive(:destroy)
|
|
965
|
+
assert_delete do
|
|
966
|
+
response.should redirect_to(sign_in_path)
|
|
967
|
+
end
|
|
968
|
+
end
|
|
969
|
+
|
|
970
|
+
it "should reject non-owner mortal user" do
|
|
971
|
+
@proposal.should_not_receive(:destroy)
|
|
972
|
+
assert_delete(:clio) do
|
|
973
|
+
flash.keys.should include(:failure)
|
|
974
|
+
response.should redirect_to(proposal_url(@proposal))
|
|
975
|
+
end
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
it "should allow owner mortal user" do
|
|
979
|
+
@proposal.should_receive(:destroy)
|
|
980
|
+
assert_delete(:quentin) do
|
|
981
|
+
flash.keys.should include(:success)
|
|
982
|
+
response.should redirect_to(event_proposals_url(@proposal.event))
|
|
983
|
+
end
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
it "should allow admin user" do
|
|
987
|
+
@proposal.should_receive(:destroy)
|
|
988
|
+
assert_delete(:quentin) do
|
|
989
|
+
flash.keys.should include(:success)
|
|
990
|
+
response.should redirect_to(event_proposals_url(@proposal.event))
|
|
991
|
+
end
|
|
992
|
+
end
|
|
993
|
+
end
|
|
994
|
+
|
|
995
|
+
describe "schedule" do
|
|
996
|
+
it "should not fail like a whale" do
|
|
997
|
+
@controller.stub(:schedule_visible?).and_return(true)
|
|
998
|
+
item = proposals(:postgresql_session)
|
|
999
|
+
|
|
1000
|
+
get :schedule, event_id: @event.slug
|
|
1001
|
+
|
|
1002
|
+
response.should be_success
|
|
1003
|
+
response.body.should have_selector(".summary", text: item.title)
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
it "should not fail like a whale with iCalendar" do
|
|
1007
|
+
@controller.stub(:schedule_visible?).and_return(true)
|
|
1008
|
+
item = proposals(:postgresql_session)
|
|
1009
|
+
|
|
1010
|
+
get :schedule, event_id: @event.slug, format: "ics"
|
|
1011
|
+
|
|
1012
|
+
response.should be_success
|
|
1013
|
+
calendar = Vpim::Icalendar.decode(response.body).first
|
|
1014
|
+
component = calendar.find{|t| t.summary == item.title}
|
|
1015
|
+
|
|
1016
|
+
dtstart = Time.parse(component.dtstart.strftime('%Y-%m-%d %H:%M:%S UTC'))
|
|
1017
|
+
dtend = Time.parse(component.dtend.strftime('%Y-%m-%d %H:%M:%S UTC'))
|
|
1018
|
+
|
|
1019
|
+
component.should_not be_nil
|
|
1020
|
+
dtstart.should == item.start_time
|
|
1021
|
+
dtend.should == item.end_time
|
|
1022
|
+
component.summary.should == item.title
|
|
1023
|
+
component.description.should == (item.respond_to?(:users) ?
|
|
1024
|
+
"#{item.users.map(&:fullname).join(', ')}: #{item.excerpt}" :
|
|
1025
|
+
item.excerpt)
|
|
1026
|
+
component.url == session_url(item)
|
|
1027
|
+
end
|
|
1028
|
+
end
|
|
1029
|
+
|
|
1030
|
+
describe "manage speakers" do
|
|
1031
|
+
before(:each) do
|
|
1032
|
+
OpenConferenceWare.stub(have_user_profiles: true)
|
|
1033
|
+
@bubba = stub_model(User, fullname: "Bubba Smith")
|
|
1034
|
+
@billy = stub_model(User, fullname: "Billy Jack")
|
|
1035
|
+
@sue = stub_model(User, fullname: "Sue Smith")
|
|
1036
|
+
@proposal = stub_model(Proposal)
|
|
1037
|
+
@proposal.users = [@bubba, @billy]
|
|
1038
|
+
@event = stub_current_event!
|
|
1039
|
+
controller.stub(:assign_get_proposal_for_speaker_manager)
|
|
1040
|
+
controller.stub(:get_proposal_for_speaker_manager).and_return(@proposal)
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
it "should list" do
|
|
1044
|
+
get :manage_speakers, speakers: "#{@bubba.id},#{@billy.id}", id: @proposal.to_param
|
|
1045
|
+
response.body.should have_selector(".speaker_id[name='speaker_ids[#{@bubba.id}]']")
|
|
1046
|
+
response.body.should have_selector(".speaker_id[name='speaker_ids[#{@billy.id}]']")
|
|
1047
|
+
response.body.should_not have_selector(".speaker_id[name='speaker_ids[#{@sue.id}]']")
|
|
1048
|
+
end
|
|
1049
|
+
|
|
1050
|
+
it "should add user" do
|
|
1051
|
+
User.should_receive(:find).and_return(@sue)
|
|
1052
|
+
get :manage_speakers, speakers: "#{@bubba.id},#{@billy.id}", add: @sue.id, id: @proposal.to_param
|
|
1053
|
+
response.body.should have_selector(".speaker_id[name='speaker_ids[#{@bubba.id}]']")
|
|
1054
|
+
response.body.should have_selector(".speaker_id[name='speaker_ids[#{@billy.id}]']")
|
|
1055
|
+
response.body.should have_selector(".speaker_id[name='speaker_ids[#{@sue.id}]']")
|
|
1056
|
+
end
|
|
1057
|
+
|
|
1058
|
+
it "should remove user" do
|
|
1059
|
+
User.should_receive(:find).and_return(@billy)
|
|
1060
|
+
get :manage_speakers, speakers: "#{@bubba.id},#{@billy.id}", remove: @billy.id, id: @proposal.to_param
|
|
1061
|
+
response.body.should have_selector(".speaker_id[name='speaker_ids[#{@bubba.id}]']")
|
|
1062
|
+
response.body.should_not have_selector(".speaker_id[name='speaker_ids[#{@billy.id}]']")
|
|
1063
|
+
end
|
|
1064
|
+
end
|
|
1065
|
+
|
|
1066
|
+
describe "search speakers" do
|
|
1067
|
+
before(:each) do
|
|
1068
|
+
@proposal = stub_model(Proposal)
|
|
1069
|
+
|
|
1070
|
+
@bubba = stub_model(User, fullname: "Bubba Smith")
|
|
1071
|
+
@billy = stub_model(User, fullname: "Billy Smith")
|
|
1072
|
+
@john = stub_model(User, fullname: "John Doe")
|
|
1073
|
+
|
|
1074
|
+
@params = {
|
|
1075
|
+
search: "smith",
|
|
1076
|
+
speakers: "IGNORED",
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
User.should_receive(:complete_profiles).and_return([@bubba, @john, @billy])
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1082
|
+
describe "new record" do
|
|
1083
|
+
before(:each) do
|
|
1084
|
+
@params[:id] = "new_record"
|
|
1085
|
+
Proposal.should_receive(:new).and_return(@proposal)
|
|
1086
|
+
@proposal.should_receive(:add_user)
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
it "should match users that aren't in the proposal" do
|
|
1090
|
+
@proposal.should_receive(:users).and_return([])
|
|
1091
|
+
post :search_speakers, @params
|
|
1092
|
+
assigns(:matches).should == [@bubba, @billy]
|
|
1093
|
+
end
|
|
1094
|
+
|
|
1095
|
+
it "should not match users that are in the proposal" do
|
|
1096
|
+
@proposal.should_receive(:users).and_return([@bubba])
|
|
1097
|
+
post :search_speakers, @params
|
|
1098
|
+
assigns(:matches).should == [@billy]
|
|
1099
|
+
end
|
|
1100
|
+
end
|
|
1101
|
+
|
|
1102
|
+
describe "existing record" do
|
|
1103
|
+
before(:each) do
|
|
1104
|
+
@proposal.id = 123
|
|
1105
|
+
@proposal.event = events(:open)
|
|
1106
|
+
@params[:id] = @proposal.id
|
|
1107
|
+
Proposal.stub(:find).and_return(@proposal)
|
|
1108
|
+
end
|
|
1109
|
+
|
|
1110
|
+
it "should match users that aren't in the proposal" do
|
|
1111
|
+
@proposal.should_receive(:users).and_return([])
|
|
1112
|
+
post :search_speakers, @params
|
|
1113
|
+
assigns(:matches).should == [@bubba, @billy]
|
|
1114
|
+
end
|
|
1115
|
+
|
|
1116
|
+
it "should not match users that are in the proposal" do
|
|
1117
|
+
@proposal.should_receive(:users).and_return([@bubba])
|
|
1118
|
+
post :search_speakers, @params
|
|
1119
|
+
assigns(:matches).should == [@billy]
|
|
1120
|
+
end
|
|
1121
|
+
end
|
|
1122
|
+
end
|
|
1123
|
+
|
|
1124
|
+
def assert_confirmed
|
|
1125
|
+
post :speaker_confirm, id: @proposal.id
|
|
1126
|
+
@proposal.reload
|
|
1127
|
+
@proposal.status.should == 'confirmed'
|
|
1128
|
+
flash[:success].should =~ /Updated/
|
|
1129
|
+
end
|
|
1130
|
+
|
|
1131
|
+
def assert_not_confirmed
|
|
1132
|
+
post :speaker_confirm, id: @proposal.id
|
|
1133
|
+
@proposal.reload
|
|
1134
|
+
@proposal.status.should_not == 'confirmed'
|
|
1135
|
+
flash[:success].should_not =~ /Updated/
|
|
1136
|
+
end
|
|
1137
|
+
|
|
1138
|
+
describe "proposal login required" do
|
|
1139
|
+
it "should redirect to login if not logged in" do
|
|
1140
|
+
proposal = proposals(:quentin_widgets)
|
|
1141
|
+
get :proposal_login_required, proposal_id: proposal.id
|
|
1142
|
+
response.should redirect_to(sign_in_path)
|
|
1143
|
+
end
|
|
1144
|
+
|
|
1145
|
+
it "should redirect to proposal if logged in" do
|
|
1146
|
+
login_as(users(:quentin))
|
|
1147
|
+
proposal = proposals(:quentin_widgets)
|
|
1148
|
+
get :proposal_login_required, proposal_id: proposal.id
|
|
1149
|
+
response.should redirect_to(proposal_path(proposal))
|
|
1150
|
+
end
|
|
1151
|
+
end
|
|
1152
|
+
|
|
1153
|
+
describe "speaker confirm" do
|
|
1154
|
+
describe "accepted proposal" do
|
|
1155
|
+
before(:each) do
|
|
1156
|
+
@proposal = proposals(:quentin_widgets)
|
|
1157
|
+
@proposal.accept!
|
|
1158
|
+
end
|
|
1159
|
+
|
|
1160
|
+
it "should confirm for owners of the proposal" do
|
|
1161
|
+
login_as(users(:quentin))
|
|
1162
|
+
assert_confirmed
|
|
1163
|
+
end
|
|
1164
|
+
it "should not confirm for non-owners of the proposal" do
|
|
1165
|
+
login_as(users(:aaron))
|
|
1166
|
+
assert_not_confirmed
|
|
1167
|
+
end
|
|
1168
|
+
end
|
|
1169
|
+
|
|
1170
|
+
describe "not-accepted proposal" do
|
|
1171
|
+
before(:each) do
|
|
1172
|
+
@proposal = proposals(:quentin_widgets)
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
it "should not confirm for owners of the proposal" do
|
|
1176
|
+
login_as(users(:quentin))
|
|
1177
|
+
lambda { post :speaker_confirm, id: @proposal.id }.should raise_error(AASM::InvalidTransition)
|
|
1178
|
+
end
|
|
1179
|
+
it "should not confirm for non-owners of the proposal" do
|
|
1180
|
+
login_as(users(:aaron))
|
|
1181
|
+
assert_not_confirmed
|
|
1182
|
+
end
|
|
1183
|
+
end
|
|
1184
|
+
end
|
|
1185
|
+
|
|
1186
|
+
def assert_declined
|
|
1187
|
+
post :speaker_decline, id: @proposal.id
|
|
1188
|
+
@proposal.reload
|
|
1189
|
+
@proposal.status.should == 'declined'
|
|
1190
|
+
flash[:success].should =~ /Updated/
|
|
1191
|
+
end
|
|
1192
|
+
|
|
1193
|
+
def assert_not_declined
|
|
1194
|
+
post :speaker_decline, id: @proposal.id
|
|
1195
|
+
@proposal.reload
|
|
1196
|
+
@proposal.status.should_not == 'declined'
|
|
1197
|
+
flash[:success].should_not =~ /Updated/
|
|
1198
|
+
end
|
|
1199
|
+
|
|
1200
|
+
describe "speaker decline" do
|
|
1201
|
+
describe "accepted proposal" do
|
|
1202
|
+
before(:each) do
|
|
1203
|
+
@proposal = proposals(:quentin_widgets)
|
|
1204
|
+
@proposal.accept!
|
|
1205
|
+
end
|
|
1206
|
+
|
|
1207
|
+
it "should decline for owners of the proposal" do
|
|
1208
|
+
login_as(users(:quentin))
|
|
1209
|
+
assert_declined
|
|
1210
|
+
end
|
|
1211
|
+
it "should not decline for non-owners of the proposal" do
|
|
1212
|
+
login_as(users(:aaron))
|
|
1213
|
+
assert_not_declined
|
|
1214
|
+
end
|
|
1215
|
+
end
|
|
1216
|
+
|
|
1217
|
+
describe "not-accepted proposal" do
|
|
1218
|
+
before(:each) do
|
|
1219
|
+
@proposal = proposals(:quentin_widgets)
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
it "should not decline for owners of the proposal" do
|
|
1223
|
+
login_as(users(:quentin))
|
|
1224
|
+
lambda { post :speaker_decline, id: @proposal.id }.should raise_error(AASM::InvalidTransition)
|
|
1225
|
+
end
|
|
1226
|
+
it "should not decline for non-owners of the proposal" do
|
|
1227
|
+
login_as(users(:aaron))
|
|
1228
|
+
assert_not_declined
|
|
1229
|
+
end
|
|
1230
|
+
end
|
|
1231
|
+
end
|
|
1232
|
+
|
|
1233
|
+
describe "get_proposal_and_assignment_status" do
|
|
1234
|
+
it "should return a status of :invalid_proposal when no proposal id is given" do
|
|
1235
|
+
@controller.stub(:params).and_return({ id: nil })
|
|
1236
|
+
@controller.send(:get_proposal_and_assignment_status).should == [nil, :invalid_proposal]
|
|
1237
|
+
end
|
|
1238
|
+
|
|
1239
|
+
it "should return a status of :invalid_event when a proposal doesn't have a valid event" do
|
|
1240
|
+
proposal = stub_model(Proposal, state: "confirmed", event: nil)
|
|
1241
|
+
Proposal.stub(:lookup).and_return(proposal)
|
|
1242
|
+
@controller.stub(:params).and_return({ id: 1000 })
|
|
1243
|
+
@controller.send(:get_proposal_and_assignment_status).should == [proposal, :invalid_event]
|
|
1244
|
+
end
|
|
1245
|
+
end
|
|
1246
|
+
|
|
1247
|
+
describe "assign_proposal_and_event" do
|
|
1248
|
+
|
|
1249
|
+
it "should return false and not redirect when proposal and its event are successfully found" do
|
|
1250
|
+
proposal = stub_model(Proposal, state: "confirmed", event: @event)
|
|
1251
|
+
@controller.should_receive(:get_proposal_and_assignment_status).and_return([proposal, :assigned_via_param])
|
|
1252
|
+
@controller.send(:assign_proposal_and_event).should == false
|
|
1253
|
+
flash[:failure].should be_nil
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
it "should redirect when proposal assignment status is :invalid_proposal" do
|
|
1257
|
+
proposal = stub_model(Proposal, event: @event)
|
|
1258
|
+
@controller.should_receive(:get_proposal_and_assignment_status).and_return([proposal, :invalid_proposal])
|
|
1259
|
+
@controller.should_receive(:redirect_to)
|
|
1260
|
+
@controller.send(:assign_proposal_and_event)
|
|
1261
|
+
flash[:failure].should == "Sorry, that presentation proposal doesn't exist or has been deleted."
|
|
1262
|
+
end
|
|
1263
|
+
|
|
1264
|
+
it "should redirect when proposal assignment status is :invalid_event" do
|
|
1265
|
+
proposal = stub_model(Proposal, state: "confirmed", event: nil, id: 1)
|
|
1266
|
+
@controller.should_receive(:get_proposal_and_assignment_status).and_return([proposal, :invalid_event])
|
|
1267
|
+
@controller.should_receive(:redirect_to)
|
|
1268
|
+
@controller.send(:assign_proposal_and_event)
|
|
1269
|
+
flash[:failure].should == "Sorry, no event was associated with proposal #1"
|
|
1270
|
+
end
|
|
1271
|
+
end
|
|
1272
|
+
|
|
1273
|
+
end
|