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.
Files changed (471) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.autotest +14 -0
  3. data/.coveralls.yml +1 -0
  4. data/.gitignore +21 -0
  5. data/.rspec +1 -0
  6. data/.travis.yml +18 -0
  7. data/CHANGES.md +280 -0
  8. data/CONTRIBUTORS.markdown +17 -0
  9. data/Gemfile +21 -0
  10. data/Gemfile.lock +296 -0
  11. data/Guardfile +24 -0
  12. data/LICENSE.txt +23 -0
  13. data/README.markdown +173 -0
  14. data/Rakefile +27 -0
  15. data/TODO.txt +22 -0
  16. data/app/assets/images/open_conference_ware/accept.png +0 -0
  17. data/app/assets/images/open_conference_ware/arrow-left.png +0 -0
  18. data/app/assets/images/open_conference_ware/arrow-out.png +0 -0
  19. data/app/assets/images/open_conference_ware/arrow-right.png +0 -0
  20. data/app/assets/images/open_conference_ware/arrow-up.png +0 -0
  21. data/app/assets/images/open_conference_ware/arrow_refresh.png +0 -0
  22. data/app/assets/images/open_conference_ware/comment.png +0 -0
  23. data/app/assets/images/open_conference_ware/comment_edit.png +0 -0
  24. data/app/assets/images/open_conference_ware/delete.png +0 -0
  25. data/app/assets/images/open_conference_ware/disk.png +0 -0
  26. data/app/assets/images/open_conference_ware/document-blank.png +0 -0
  27. data/app/assets/images/open_conference_ware/document.png +0 -0
  28. data/app/assets/images/open_conference_ware/edit.png +0 -0
  29. data/app/assets/images/open_conference_ware/extras/001_01.png +0 -0
  30. data/app/assets/images/open_conference_ware/extras/001_05.png +0 -0
  31. data/app/assets/images/open_conference_ware/extras/001_05x16.png +0 -0
  32. data/app/assets/images/open_conference_ware/extras/001_21.png +0 -0
  33. data/app/assets/images/open_conference_ware/extras/001_23.png +0 -0
  34. data/app/assets/images/open_conference_ware/extras/001_24.png +0 -0
  35. data/app/assets/images/open_conference_ware/extras/001_29.png +0 -0
  36. data/app/assets/images/open_conference_ware/extras/01.png +0 -0
  37. data/app/assets/images/open_conference_ware/extras/05.png +0 -0
  38. data/app/assets/images/open_conference_ware/extras/06.png +0 -0
  39. data/app/assets/images/open_conference_ware/extras/1.png +0 -0
  40. data/app/assets/images/open_conference_ware/extras/14.png +0 -0
  41. data/app/assets/images/open_conference_ware/extras/16.png +0 -0
  42. data/app/assets/images/open_conference_ware/extras/2.png +0 -0
  43. data/app/assets/images/open_conference_ware/extras/21.png +0 -0
  44. data/app/assets/images/open_conference_ware/extras/28.png +0 -0
  45. data/app/assets/images/open_conference_ware/extras/3.png +0 -0
  46. data/app/assets/images/open_conference_ware/extras/31.png +0 -0
  47. data/app/assets/images/open_conference_ware/extras/32.png +0 -0
  48. data/app/assets/images/open_conference_ware/extras/35.png +0 -0
  49. data/app/assets/images/open_conference_ware/extras/36.png +0 -0
  50. data/app/assets/images/open_conference_ware/extras/4.png +0 -0
  51. data/app/assets/images/open_conference_ware/extras/44.png +0 -0
  52. data/app/assets/images/open_conference_ware/extras/45.png +0 -0
  53. data/app/assets/images/open_conference_ware/extras/46.png +0 -0
  54. data/app/assets/images/open_conference_ware/extras/cancel.png +0 -0
  55. data/app/assets/images/open_conference_ware/extras/cancelx16.png +0 -0
  56. data/app/assets/images/open_conference_ware/extras/icon.trashcan.gif +0 -0
  57. data/app/assets/images/open_conference_ware/favorite.png +0 -0
  58. data/app/assets/images/open_conference_ware/feed.png +0 -0
  59. data/app/assets/images/open_conference_ware/heart.png +0 -0
  60. data/app/assets/images/open_conference_ware/house.png +0 -0
  61. data/app/assets/images/open_conference_ware/ignite_portland_header3_clear.png +0 -0
  62. data/app/assets/images/open_conference_ware/ignite_portland_header3_clear_cropped.png +0 -0
  63. data/app/assets/images/open_conference_ware/jquery.wysiwyg.gif +0 -0
  64. data/app/assets/images/open_conference_ware/lock.png +0 -0
  65. data/app/assets/images/open_conference_ware/new_window.gif +0 -0
  66. data/app/assets/images/open_conference_ware/openid-icon.gif +0 -0
  67. data/app/assets/images/open_conference_ware/pencil.png +0 -0
  68. data/app/assets/images/open_conference_ware/plus.png +0 -0
  69. data/app/assets/images/open_conference_ware/quote.png +0 -0
  70. data/app/assets/images/open_conference_ware/rails.png +0 -0
  71. data/app/assets/images/open_conference_ware/redx.png +0 -0
  72. data/app/assets/images/open_conference_ware/reset-fff.png +0 -0
  73. data/app/assets/images/open_conference_ware/spinner-big.gif +0 -0
  74. data/app/assets/images/open_conference_ware/spinner.gif +0 -0
  75. data/app/assets/images/open_conference_ware/star.png +0 -0
  76. data/app/assets/images/open_conference_ware/tag_blue.png +0 -0
  77. data/app/assets/images/open_conference_ware/time.png +0 -0
  78. data/app/assets/javascripts/open_conference_ware/application.js +18 -0
  79. data/app/assets/javascripts/open_conference_ware/base.js +15 -0
  80. data/app/assets/javascripts/open_conference_ware/favorites.js +76 -0
  81. data/app/assets/javascripts/open_conference_ware/ie.js +2 -0
  82. data/app/assets/javascripts/open_conference_ware/menu.js +47 -0
  83. data/app/assets/javascripts/open_conference_ware/persona.js +10 -0
  84. data/app/assets/javascripts/open_conference_ware/proposals.js +208 -0
  85. data/app/assets/javascripts/open_conference_ware/schedule.js +20 -0
  86. data/app/assets/javascripts/open_conference_ware/spinner.js +11 -0
  87. data/app/assets/javascripts/open_conference_ware/util.js +23 -0
  88. data/app/assets/stylesheets/open_conference_ware/application.css +8 -0
  89. data/app/assets/stylesheets/open_conference_ware/common.css.scss +491 -0
  90. data/app/assets/stylesheets/open_conference_ware/custom.css.scss +1033 -0
  91. data/app/assets/stylesheets/open_conference_ware/scaffold.css +54 -0
  92. data/app/controllers/open_conference_ware/application_controller.rb +488 -0
  93. data/app/controllers/open_conference_ware/authentications_controller.rb +42 -0
  94. data/app/controllers/open_conference_ware/comments_controller.rb +86 -0
  95. data/app/controllers/open_conference_ware/events_controller.rb +36 -0
  96. data/app/controllers/open_conference_ware/manage/events_controller.rb +157 -0
  97. data/app/controllers/open_conference_ware/manage/snippets_controller.rb +110 -0
  98. data/app/controllers/open_conference_ware/proposals_controller.rb +521 -0
  99. data/app/controllers/open_conference_ware/rooms_controller.rb +130 -0
  100. data/app/controllers/open_conference_ware/schedule_items_controller.rb +128 -0
  101. data/app/controllers/open_conference_ware/selector_votes_controller.rb +71 -0
  102. data/app/controllers/open_conference_ware/session_types_controller.rb +123 -0
  103. data/app/controllers/open_conference_ware/tracks_controller.rb +118 -0
  104. data/app/controllers/open_conference_ware/user_favorites_controller.rb +68 -0
  105. data/app/controllers/open_conference_ware/users_controller.rb +120 -0
  106. data/app/helpers/open_conference_ware/application_helper.rb +167 -0
  107. data/app/helpers/open_conference_ware/authentications_helper.rb +25 -0
  108. data/app/helpers/open_conference_ware/cache_if_helper.rb +13 -0
  109. data/app/helpers/open_conference_ware/display_link_to_helper.rb +25 -0
  110. data/app/helpers/open_conference_ware/display_textile_for_helper.rb +11 -0
  111. data/app/helpers/open_conference_ware/field_annotation_helper.rb +11 -0
  112. data/app/helpers/open_conference_ware/focus_helper.rb +16 -0
  113. data/app/helpers/open_conference_ware/localcss_helper.rb +10 -0
  114. data/app/helpers/open_conference_ware/page_title_helper.rb +17 -0
  115. data/app/helpers/open_conference_ware/proposals_helper.rb +54 -0
  116. data/app/helpers/open_conference_ware/rooms_helper.rb +5 -0
  117. data/app/helpers/open_conference_ware/scroll_to_helper.rb +15 -0
  118. data/app/helpers/open_conference_ware/session_types_helper.rb +5 -0
  119. data/app/helpers/open_conference_ware/snippets_helper.rb +36 -0
  120. data/app/helpers/open_conference_ware/time_range_helper.rb +198 -0
  121. data/app/helpers/open_conference_ware/tracks_helper.rb +9 -0
  122. data/app/helpers/open_conference_ware/user_favorites_helper.rb +15 -0
  123. data/app/mailers/open_conference_ware/speaker_mailer.rb +51 -0
  124. data/app/mixins/open_conference_ware/breadcrumbs_mixin.rb +76 -0
  125. data/app/mixins/open_conference_ware/cache_lookups_mixin.rb +128 -0
  126. data/app/mixins/open_conference_ware/faux_routes_mixin.rb +83 -0
  127. data/app/mixins/open_conference_ware/normalize_url_mixin.rb +40 -0
  128. data/app/mixins/open_conference_ware/public_attributes_mixin.rb +62 -0
  129. data/app/mixins/open_conference_ware/schedule_overlaps_mixin.rb +12 -0
  130. data/app/mixins/open_conference_ware/settings_checkers_mixin.rb +50 -0
  131. data/app/mixins/open_conference_ware/simple_slug_mixin.rb +26 -0
  132. data/app/models/open_conference_ware/authentication.rb +47 -0
  133. data/app/models/open_conference_ware/base.rb +6 -0
  134. data/app/models/open_conference_ware/comment.rb +26 -0
  135. data/app/models/open_conference_ware/event.rb +227 -0
  136. data/app/models/open_conference_ware/proposal.rb +625 -0
  137. data/app/models/open_conference_ware/room.rb +42 -0
  138. data/app/models/open_conference_ware/schedule.rb +216 -0
  139. data/app/models/open_conference_ware/schedule_item.rb +55 -0
  140. data/app/models/open_conference_ware/selector_vote.rb +22 -0
  141. data/app/models/open_conference_ware/session_type.rb +33 -0
  142. data/app/models/open_conference_ware/snippet.rb +58 -0
  143. data/app/models/open_conference_ware/track.rb +51 -0
  144. data/app/models/open_conference_ware/user.rb +262 -0
  145. data/app/models/open_conference_ware/user_favorite.rb +42 -0
  146. data/app/observers/open_conference_ware/cache_watcher.rb +42 -0
  147. data/app/views/layouts/open_conference_ware/_header.html.erb +106 -0
  148. data/app/views/layouts/open_conference_ware/application.atom.erb +1 -0
  149. data/app/views/layouts/open_conference_ware/application.html.erb +126 -0
  150. data/app/views/layouts/open_conference_ware/scaffold.html.erb +21 -0
  151. data/app/views/open_conference_ware/404.html.erb +8 -0
  152. data/app/views/open_conference_ware/422.html.erb +11 -0
  153. data/app/views/open_conference_ware/500.html.erb +11 -0
  154. data/app/views/open_conference_ware/_email_link.html.erb +24 -0
  155. data/app/views/open_conference_ware/_google_analytics.html.erb +9 -0
  156. data/app/views/open_conference_ware/authentications/_developer.html.erb +7 -0
  157. data/app/views/open_conference_ware/authentications/_openid.html.erb +11 -0
  158. data/app/views/open_conference_ware/authentications/_persona.html.erb +17 -0
  159. data/app/views/open_conference_ware/authentications/sign_in.html.erb +12 -0
  160. data/app/views/open_conference_ware/comments/_list.html.erb +31 -0
  161. data/app/views/open_conference_ware/comments/index.atom.builder +25 -0
  162. data/app/views/open_conference_ware/comments/index.html.erb +3 -0
  163. data/app/views/open_conference_ware/events/index.html.erb +9 -0
  164. data/app/views/open_conference_ware/events/show.html.erb +0 -0
  165. data/app/views/open_conference_ware/events/speakers.html.erb +7 -0
  166. data/app/views/open_conference_ware/manage/events/_form.html.erb +107 -0
  167. data/app/views/open_conference_ware/manage/events/edit.html.erb +3 -0
  168. data/app/views/open_conference_ware/manage/events/index.html.erb +41 -0
  169. data/app/views/open_conference_ware/manage/events/new.html.erb +3 -0
  170. data/app/views/open_conference_ware/manage/events/proposals.html.erb +133 -0
  171. data/app/views/open_conference_ware/manage/events/show.html.erb +181 -0
  172. data/app/views/open_conference_ware/manage/snippets/_form.html.erb +30 -0
  173. data/app/views/open_conference_ware/manage/snippets/edit.html.erb +3 -0
  174. data/app/views/open_conference_ware/manage/snippets/index.html.erb +34 -0
  175. data/app/views/open_conference_ware/manage/snippets/new.html.erb +3 -0
  176. data/app/views/open_conference_ware/manage/snippets/show.html.erb +32 -0
  177. data/app/views/open_conference_ware/proposals/_admin_controls.html.erb +33 -0
  178. data/app/views/open_conference_ware/proposals/_form.html.erb +381 -0
  179. data/app/views/open_conference_ware/proposals/_list.html.erb +164 -0
  180. data/app/views/open_conference_ware/proposals/_list_concise.html.erb +93 -0
  181. data/app/views/open_conference_ware/proposals/_manage_speakers.html.erb +30 -0
  182. data/app/views/open_conference_ware/proposals/_room_control.html.erb +21 -0
  183. data/app/views/open_conference_ware/proposals/_schedule_block.html.erb +8 -0
  184. data/app/views/open_conference_ware/proposals/_schedule_control.html.erb +13 -0
  185. data/app/views/open_conference_ware/proposals/_search_speakers.html.erb +20 -0
  186. data/app/views/open_conference_ware/proposals/_sub_list.html.erb +65 -0
  187. data/app/views/open_conference_ware/proposals/_sub_list_for_kind.html.erb +31 -0
  188. data/app/views/open_conference_ware/proposals/_transition_control.html.erb +16 -0
  189. data/app/views/open_conference_ware/proposals/create.html.erb +29 -0
  190. data/app/views/open_conference_ware/proposals/edit.html.erb +7 -0
  191. data/app/views/open_conference_ware/proposals/index.atom.builder +63 -0
  192. data/app/views/open_conference_ware/proposals/index.html.erb +46 -0
  193. data/app/views/open_conference_ware/proposals/new.html.erb +3 -0
  194. data/app/views/open_conference_ware/proposals/schedule.html.erb +108 -0
  195. data/app/views/open_conference_ware/proposals/sessions_index_terse.html.erb +22 -0
  196. data/app/views/open_conference_ware/proposals/show.html.erb +316 -0
  197. data/app/views/open_conference_ware/proposals/stats.html.erb +72 -0
  198. data/app/views/open_conference_ware/rooms/_form.html.erb +36 -0
  199. data/app/views/open_conference_ware/rooms/edit.html.erb +3 -0
  200. data/app/views/open_conference_ware/rooms/index.html.erb +13 -0
  201. data/app/views/open_conference_ware/rooms/new.html.erb +3 -0
  202. data/app/views/open_conference_ware/rooms/show.html.erb +27 -0
  203. data/app/views/open_conference_ware/schedule_items/_form.html.erb +35 -0
  204. data/app/views/open_conference_ware/schedule_items/edit.html.erb +3 -0
  205. data/app/views/open_conference_ware/schedule_items/index.html.erb +31 -0
  206. data/app/views/open_conference_ware/schedule_items/new.html.erb +3 -0
  207. data/app/views/open_conference_ware/schedule_items/show.html.erb +30 -0
  208. data/app/views/open_conference_ware/selector_votes/index.html.erb +81 -0
  209. data/app/views/open_conference_ware/session_types/_form.html.erb +23 -0
  210. data/app/views/open_conference_ware/session_types/edit.html.erb +3 -0
  211. data/app/views/open_conference_ware/session_types/index.html.erb +18 -0
  212. data/app/views/open_conference_ware/session_types/new.html.erb +3 -0
  213. data/app/views/open_conference_ware/session_types/show.html.erb +14 -0
  214. data/app/views/open_conference_ware/speaker_mailer/speaker_email.text.erb +14 -0
  215. data/app/views/open_conference_ware/tracks/_colors.css.erb +7 -0
  216. data/app/views/open_conference_ware/tracks/_form.html.erb +36 -0
  217. data/app/views/open_conference_ware/tracks/edit.html.erb +3 -0
  218. data/app/views/open_conference_ware/tracks/index.html.erb +25 -0
  219. data/app/views/open_conference_ware/tracks/new.html.erb +3 -0
  220. data/app/views/open_conference_ware/tracks/show.html.erb +19 -0
  221. data/app/views/open_conference_ware/user_favorites/index.html.erb +12 -0
  222. data/app/views/open_conference_ware/users/_account_box.html.erb +10 -0
  223. data/app/views/open_conference_ware/users/_block.html.erb +80 -0
  224. data/app/views/open_conference_ware/users/_list.html.erb +17 -0
  225. data/app/views/open_conference_ware/users/edit.html.erb +73 -0
  226. data/app/views/open_conference_ware/users/index.html.erb +28 -0
  227. data/app/views/open_conference_ware/users/new.html.erb +7 -0
  228. data/app/views/open_conference_ware/users/proposals.html.erb +24 -0
  229. data/app/views/open_conference_ware/users/show.html.erb +5 -0
  230. data/app/views/open_conference_ware/welcome/test.html.haml +8 -0
  231. data/bin/rails +8 -0
  232. data/ci/Gemfile.ci +13 -0
  233. data/ci/copy_database_config.rb +6 -0
  234. data/ci/database.mysql.yml +5 -0
  235. data/ci/database.postgresql.yml +4 -0
  236. data/ci/database.sqlite.yml +5 -0
  237. data/config/initializers/acts_as_taggable_on.rb +2 -0
  238. data/config/initializers/date_time_formats.rb +9 -0
  239. data/config/routes.rb +74 -0
  240. data/db/migrate/20131203235128_create_open_conference_ware_authentications.rb +14 -0
  241. data/db/migrate/20131203235216_create_open_conference_ware_comments.rb +14 -0
  242. data/db/migrate/20131203235418_create_open_conference_ware_events.rb +27 -0
  243. data/db/migrate/20131203235524_create_open_conference_ware_proposals.rb +36 -0
  244. data/db/migrate/20131203235723_create_open_conference_ware_rooms.rb +20 -0
  245. data/db/migrate/20131203235831_create_open_conference_ware_schedule_items.rb +18 -0
  246. data/db/migrate/20131203235910_create_open_conference_ware_selector_votes.rb +10 -0
  247. data/db/migrate/20131203235934_create_open_conference_ware_session_types.rb +14 -0
  248. data/db/migrate/20131204000008_create_open_conference_ware_snippets.rb +15 -0
  249. data/db/migrate/20131204000048_create_open_conference_ware_taggings.rb +16 -0
  250. data/db/migrate/20131204000129_create_open_conference_ware_tags.rb +7 -0
  251. data/db/migrate/20131204000147_create_open_conference_ware_tracks.rb +15 -0
  252. data/db/migrate/20131204000230_create_open_conference_ware_user_favorites.rb +10 -0
  253. data/db/migrate/20131204000251_create_open_conference_ware_users.rb +24 -0
  254. data/db/migrate/20131204000355_create_proposals_users_join_table.rb +8 -0
  255. data/db/seeds.rb +31 -0
  256. data/features/comment_create.feature +9 -0
  257. data/features/comment_destroy.feature +22 -0
  258. data/features/comment_new.feature +22 -0
  259. data/features/step_definitions/authentication_steps.rb +22 -0
  260. data/features/step_definitions/comment_create_steps.rb +5 -0
  261. data/features/step_definitions/comment_destroy_steps.rb +13 -0
  262. data/features/step_definitions/comment_new_steps.rb +41 -0
  263. data/features/step_definitions/notification_steps.rb +3 -0
  264. data/features/step_definitions/web_steps.rb +263 -0
  265. data/features/support/env.rb +58 -0
  266. data/features/support/helpers.rb +17 -0
  267. data/features/support/paths.rb +35 -0
  268. data/gem-public_cert.pem +22 -0
  269. data/lib/defer_proxy.rb +127 -0
  270. data/lib/ext/color_rgb_serializer_fix.rb +18 -0
  271. data/lib/ext/string_possessiveize.rb +7 -0
  272. data/lib/ext/vpim_icalendar_extra_properties.rb +25 -0
  273. data/lib/generators/open_conference_ware/install/USAGE +12 -0
  274. data/lib/generators/open_conference_ware/install/install_generator.rb +35 -0
  275. data/lib/generators/open_conference_ware/install/templates/config_initializer.rb +110 -0
  276. data/lib/generators/open_conference_ware/install/templates/omniauth_initializer.rb +33 -0
  277. data/lib/open_conference_ware.rb +156 -0
  278. data/lib/open_conference_ware/dependencies.rb +38 -0
  279. data/lib/open_conference_ware/engine.rb +38 -0
  280. data/lib/open_conference_ware/omni_auth_builder.rb +8 -0
  281. data/lib/open_conference_ware/version.rb +3 -0
  282. data/lib/rwikibot_page_drone.rb +70 -0
  283. data/lib/tasks/.gitkeep +0 -0
  284. data/lib/tasks/audio.rake +53 -0
  285. data/lib/tasks/cucumber.rake +65 -0
  286. data/lib/tasks/export.rake +170 -0
  287. data/lib/tasks/mediawiki.rake +96 -0
  288. data/lib/tasks/open_conference_ware_tasks.rake +16 -0
  289. data/lib/tasks/schedule.rake +103 -0
  290. data/lib/tasks/snippets.rake +23 -0
  291. data/open_conference_ware.gemspec +67 -0
  292. data/original_graphics/favorite.psd +0 -0
  293. data/spec/controllers/open_conference_ware/application_controller_spec.rb +309 -0
  294. data/spec/controllers/open_conference_ware/authentications_controller_spec.rb +87 -0
  295. data/spec/controllers/open_conference_ware/comments_controller_spec.rb +146 -0
  296. data/spec/controllers/open_conference_ware/events_controller_spec.rb +102 -0
  297. data/spec/controllers/open_conference_ware/manage_events_controller_spec.rb +103 -0
  298. data/spec/controllers/open_conference_ware/proposals_controller_spec.rb +1273 -0
  299. data/spec/controllers/open_conference_ware/rooms_controller_spec.rb +190 -0
  300. data/spec/controllers/open_conference_ware/selector_votes_controller_spec.rb +263 -0
  301. data/spec/controllers/open_conference_ware/session_types_controller_spec.rb +190 -0
  302. data/spec/controllers/open_conference_ware/sessions_routing_spec.rb +13 -0
  303. data/spec/controllers/open_conference_ware/tracks_controller_spec.rb +190 -0
  304. data/spec/controllers/open_conference_ware/user_favorites_controller_spec.rb +127 -0
  305. data/spec/controllers/open_conference_ware/users_controller_spec.rb +166 -0
  306. data/spec/dummy/README.rdoc +28 -0
  307. data/spec/dummy/Rakefile +6 -0
  308. data/spec/dummy/app/assets/images/.keep +0 -0
  309. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  310. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  311. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  312. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  313. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  314. data/spec/dummy/app/mailers/.keep +0 -0
  315. data/spec/dummy/app/models/.keep +0 -0
  316. data/spec/dummy/app/models/concerns/.keep +0 -0
  317. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  318. data/spec/dummy/bin/bundle +3 -0
  319. data/spec/dummy/bin/rails +4 -0
  320. data/spec/dummy/bin/rake +4 -0
  321. data/spec/dummy/config.ru +4 -0
  322. data/spec/dummy/config/application.rb +30 -0
  323. data/spec/dummy/config/boot.rb +5 -0
  324. data/spec/dummy/config/database.yml +25 -0
  325. data/spec/dummy/config/environment.rb +5 -0
  326. data/spec/dummy/config/environments/development.rb +29 -0
  327. data/spec/dummy/config/environments/production.rb +80 -0
  328. data/spec/dummy/config/environments/test.rb +36 -0
  329. data/spec/dummy/config/initializers/01_open_conference_ware.rb +110 -0
  330. data/spec/dummy/config/initializers/02_omniauth.rb +17 -0
  331. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  332. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  333. data/spec/dummy/config/initializers/inflections.rb +16 -0
  334. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  335. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  336. data/spec/dummy/config/initializers/session_store.rb +3 -0
  337. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  338. data/spec/dummy/config/locales/en.yml +23 -0
  339. data/spec/dummy/config/routes.rb +3 -0
  340. data/spec/dummy/db/schema.rb +219 -0
  341. data/spec/dummy/db/seeds.rb +10 -0
  342. data/spec/dummy/lib/assets/.keep +0 -0
  343. data/spec/dummy/log/.keep +0 -0
  344. data/spec/dummy/public/404.html +58 -0
  345. data/spec/dummy/public/422.html +58 -0
  346. data/spec/dummy/public/500.html +57 -0
  347. data/spec/dummy/public/favicon.ico +0 -0
  348. data/spec/factories/authentication_factory.rb +16 -0
  349. data/spec/factories/common_factory.rb +4 -0
  350. data/spec/factories/event_factory.rb +26 -0
  351. data/spec/factories/proposal_factory.rb +57 -0
  352. data/spec/factories/proposal_user_factory.rb +7 -0
  353. data/spec/factories/room_factory.rb +11 -0
  354. data/spec/factories/schedule_item_factory.rb +13 -0
  355. data/spec/factories/session_types_factory.rb +10 -0
  356. data/spec/factories/snippet_factory.rb +7 -0
  357. data/spec/factories/track_factory.rb +12 -0
  358. data/spec/factories/user_factory.rb +22 -0
  359. data/spec/factories/user_favorite_factory.rb +7 -0
  360. data/spec/features/sign_in_spec.rb +11 -0
  361. data/spec/features/snippets_spec.rb +38 -0
  362. data/spec/fixtures/open_conference_ware_comments.yml +27 -0
  363. data/spec/fixtures/open_conference_ware_events.yml +56 -0
  364. data/spec/fixtures/open_conference_ware_proposals.yml +256 -0
  365. data/spec/fixtures/open_conference_ware_rooms.yml +13 -0
  366. data/spec/fixtures/open_conference_ware_schedule_items.yml +23 -0
  367. data/spec/fixtures/open_conference_ware_session_types.yml +19 -0
  368. data/spec/fixtures/open_conference_ware_snippets.yml +62 -0
  369. data/spec/fixtures/open_conference_ware_tracks.yml +65 -0
  370. data/spec/fixtures/open_conference_ware_user_favorites.yml +7 -0
  371. data/spec/fixtures/open_conference_ware_users.yml +87 -0
  372. data/spec/helpers/open_conference_ware/application_helper_spec.rb +58 -0
  373. data/spec/helpers/open_conference_ware/authentications_helper_spec.rb +15 -0
  374. data/spec/helpers/open_conference_ware/display_link_to_helper_spec.rb +52 -0
  375. data/spec/helpers/open_conference_ware/proposals_helper_spec.rb +32 -0
  376. data/spec/helpers/open_conference_ware/rooms_helper_spec.rb +11 -0
  377. data/spec/helpers/open_conference_ware/session_types_helper_spec.rb +15 -0
  378. data/spec/helpers/open_conference_ware/time_range_helper_spec.rb +56 -0
  379. data/spec/helpers/open_conference_ware/tracks_helper_spec.rb +11 -0
  380. data/spec/helpers/open_conference_ware/user_favorites_helper_spec.rb +11 -0
  381. data/spec/integration/open_conference_ware/cache_lookups_mixin_spec.rb +122 -0
  382. data/spec/mixins/open_conference_ware/normalize_url_mixin_spec.rb +65 -0
  383. data/spec/models/open_conference_ware/authentication_spec.rb +67 -0
  384. data/spec/models/open_conference_ware/event_spec.rb +211 -0
  385. data/spec/models/open_conference_ware/proposal_spec.rb +606 -0
  386. data/spec/models/open_conference_ware/room_spec.rb +14 -0
  387. data/spec/models/open_conference_ware/schedule_item_spec.rb +12 -0
  388. data/spec/models/open_conference_ware/schedule_spec.rb +358 -0
  389. data/spec/models/open_conference_ware/selector_vote_spec.rb +12 -0
  390. data/spec/models/open_conference_ware/session_type_spec.rb +15 -0
  391. data/spec/models/open_conference_ware/snippet_spec.rb +13 -0
  392. data/spec/models/open_conference_ware/speaker_mailer_spec.rb +91 -0
  393. data/spec/models/open_conference_ware/track_spec.rb +36 -0
  394. data/spec/models/open_conference_ware/user_favorite_spec.rb +41 -0
  395. data/spec/models/open_conference_ware/user_spec.rb +77 -0
  396. data/spec/ocw_config.rb +76 -0
  397. data/spec/rcov.opts +2 -0
  398. data/spec/spec.opts +3 -0
  399. data/spec/spec_helper.rb +55 -0
  400. data/spec/spec_helper_customizations.rb +125 -0
  401. data/spec/support/add_all_helpers_to_view.rb +24 -0
  402. data/spec/support/authenticated_test_helper.rb +27 -0
  403. data/spec/support/fixture_shortcuts.rb +18 -0
  404. data/spec/support/omniauth.rb +34 -0
  405. data/spec/support/valid_params_extraction.rb +15 -0
  406. data/spec/views/open_conference_ware/proposals/_room_control.html.erb_spec.rb +23 -0
  407. data/spec/views/open_conference_ware/proposals/_transition_control.html.erb_spec.rb +14 -0
  408. data/spec/views/open_conference_ware/proposals/show.html.erb_spec.rb +128 -0
  409. data/spec/views/open_conference_ware/rooms/index.html.erb_spec.rb +19 -0
  410. data/spec/views/open_conference_ware/rooms/show.html.erb_spec.rb +15 -0
  411. data/spec/views/open_conference_ware/selector_votes/index.html.erb_spec.rb +41 -0
  412. data/spec/views/open_conference_ware/session_types/edit.html.erb_spec.rb +25 -0
  413. data/spec/views/open_conference_ware/session_types/index.html.erb_spec.rb +19 -0
  414. data/spec/views/open_conference_ware/session_types/new.html.erb_spec.rb +24 -0
  415. data/spec/views/open_conference_ware/session_types/show.html.erb_spec.rb +18 -0
  416. data/spec/views/open_conference_ware/tracks/edit.html.erb_spec.rb +25 -0
  417. data/spec/views/open_conference_ware/tracks/index.html.erb_spec.rb +56 -0
  418. data/spec/views/open_conference_ware/tracks/new.html.erb_spec.rb +26 -0
  419. data/spec/views/open_conference_ware/tracks/show.html.erb_spec.rb +23 -0
  420. data/spec/views/open_conference_ware/user_favorites/index.html.erb_spec.rb +29 -0
  421. data/spec/views/open_conference_ware/users/index_spec.rb +24 -0
  422. data/util/add_id3_tags_to_mp3.rb +57 -0
  423. data/util/schedule_demo.rb +36 -0
  424. data/util/seed_schedule.rb +61 -0
  425. data/util/sessions_to_lanyrd.rb +166 -0
  426. data/util/transfer_schedule_items.rb +25 -0
  427. data/util/update_proposal_status_from_voting_spreadsheet.rb +26 -0
  428. data/util/user_favorites_contention_report.rb +42 -0
  429. data/util/user_favorites_contention_report.sh +9 -0
  430. data/vendor/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  431. data/vendor/assets/fonts/glyphicons-halflings-regular.svg +228 -0
  432. data/vendor/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  433. data/vendor/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  434. data/vendor/assets/images/farbtastic/marker.png +0 -0
  435. data/vendor/assets/images/farbtastic/mask.png +0 -0
  436. data/vendor/assets/images/farbtastic/wheel.png +0 -0
  437. data/vendor/assets/images/idselector/aol.ico +0 -0
  438. data/vendor/assets/images/idselector/arrow.gif +0 -0
  439. data/vendor/assets/images/idselector/arrow_white_back.png +0 -0
  440. data/vendor/assets/images/idselector/arrow_white_forward.png +0 -0
  441. data/vendor/assets/images/idselector/blogger.ico +0 -0
  442. data/vendor/assets/images/idselector/claimid.ico +0 -0
  443. data/vendor/assets/images/idselector/flickr.ico +0 -0
  444. data/vendor/assets/images/idselector/google.ico +0 -0
  445. data/vendor/assets/images/idselector/lj.ico +0 -0
  446. data/vendor/assets/images/idselector/myopenid.ico +0 -0
  447. data/vendor/assets/images/idselector/openid.ico +0 -0
  448. data/vendor/assets/images/idselector/technorati.ico +0 -0
  449. data/vendor/assets/images/idselector/verisign.ico +0 -0
  450. data/vendor/assets/images/idselector/vidoop2.ico +0 -0
  451. data/vendor/assets/images/idselector/vox.ico +0 -0
  452. data/vendor/assets/images/idselector/yahoo.ico +0 -0
  453. data/vendor/assets/javascripts/audiojs/audio.min.js +23 -0
  454. data/vendor/assets/javascripts/audiojs/audiojs.swf +0 -0
  455. data/vendor/assets/javascripts/audiojs/player-graphics.gif +0 -0
  456. data/vendor/assets/javascripts/bootstrap.js +1999 -0
  457. data/vendor/assets/javascripts/farbtastic.js +329 -0
  458. data/vendor/assets/javascripts/html5shiv.js +8 -0
  459. data/vendor/assets/javascripts/idselector.js +538 -0
  460. data/vendor/assets/javascripts/idselector~original.js +532 -0
  461. data/vendor/assets/javascripts/jquery-migrate-1.2.1.js +521 -0
  462. data/vendor/assets/javascripts/jquery.localScroll.js +106 -0
  463. data/vendor/assets/javascripts/jquery.scrollTo.js +174 -0
  464. data/vendor/assets/javascripts/respond.min.js +6 -0
  465. data/vendor/assets/stylesheets/bootstrap-theme.css +384 -0
  466. data/vendor/assets/stylesheets/bootstrap.css +6805 -0
  467. data/vendor/assets/stylesheets/farbtastic.css.scss +38 -0
  468. data/vendor/assets/stylesheets/persona-buttons.css +229 -0
  469. data/vendor/assets/stylesheets/reset-fonts-grids.css +7 -0
  470. metadata +1174 -0
  471. metadata.gz.sig +0 -0
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe OpenConferenceWare::NormalizeUrlMixin do
4
+ NormalizeUrlMixin = OpenConferenceWare::NormalizeUrlMixin
5
+
6
+ describe "normalize_url!" do
7
+ it "should preserve valid URLs as-is" do
8
+ NormalizeUrlMixin.normalize_url!('http://foo.bar/').should == 'http://foo.bar/'
9
+ end
10
+
11
+ it "should append trailing slash to URLs" do
12
+ NormalizeUrlMixin.normalize_url!('http://foo.bar').should == 'http://foo.bar/'
13
+ end
14
+
15
+ it "should preserve valid URLs with paths as-is" do
16
+ NormalizeUrlMixin.normalize_url!('http://foo.bar/baz').should == 'http://foo.bar/baz'
17
+ end
18
+
19
+ it "should add http schema to pure hostnames" do
20
+ NormalizeUrlMixin.normalize_url!('foo.bar').should == 'http://foo.bar/'
21
+ end
22
+
23
+ it "should add http schema to hostname/paths" do
24
+ NormalizeUrlMixin.normalize_url!('foo.bar/baz').should == 'http://foo.bar/baz'
25
+ end
26
+ end
27
+
28
+ describe "validation" do
29
+ fixtures :open_conference_ware_users
30
+ # TODO Mock an entire ActiveRecord model to isolate these behaviors, rather than relying on User
31
+ before(:each) do
32
+ @record = users(:aaron)
33
+ end
34
+
35
+ it "should handle nil" do
36
+ @record.website = nil
37
+ @record.should be_valid
38
+ @record.website.should be_blank
39
+ end
40
+
41
+ it "should handle blank" do
42
+ @record.website = ''
43
+ @record.should be_valid
44
+ @record.website.should be_blank
45
+ end
46
+
47
+ it "should handle valid" do
48
+ @record.website = 'http://foo.bar/'
49
+ @record.should be_valid
50
+ @record.website.should == 'http://foo.bar/'
51
+ end
52
+
53
+ it "should handle unqualified" do
54
+ @record.website = 'foo.bar'
55
+ @record.should be_valid
56
+ @record.website.should == 'http://foo.bar/'
57
+ end
58
+
59
+ it "should fail invalid" do
60
+ @record.website = '<asdf>'
61
+ @record.should_not be_valid
62
+ @record.errors[:website].should == ["is invalid"]
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe OpenConferenceWare::Authentication do
4
+ describe "finding or creating from an auth hash" do
5
+ describe "when an an existing Authentication does not exist" do
6
+ before do
7
+ @auth_hash = OmniAuth::AuthHash.new(
8
+ 'provider' => 'test_provider',
9
+ 'uid' => Time.now.to_i.to_s,
10
+ 'info' => {
11
+ 'name' => 'Boris',
12
+ 'email' => 'boris@example.com'
13
+ }
14
+ )
15
+
16
+ @new_auth = OpenConferenceWare::Authentication.find_and_update_or_create_from_auth_hash(@auth_hash)
17
+ end
18
+
19
+ it "should create new Authentications" do
20
+ @new_auth.should_not be_new_record
21
+ end
22
+
23
+ it "should set base attributes from the auth hash" do
24
+ @new_auth.provider.should == @auth_hash['provider']
25
+ @new_auth.uid.should == @auth_hash['uid']
26
+ end
27
+
28
+ it "should set name and email from the info hash" do
29
+ @new_auth.name.should == @auth_hash['info']['name']
30
+ @new_auth.email.should == @auth_hash['info']['email']
31
+ end
32
+
33
+ it "should stash the info hash" do
34
+ @new_auth.info.should == @auth_hash['info']
35
+ end
36
+ end
37
+
38
+ describe "when an existing Authentication record exists" do
39
+ before do
40
+ @existing = create(:authentication)
41
+ @auth_hash = OmniAuth::AuthHash.new(
42
+ 'provider' => @existing.provider,
43
+ 'uid' => @existing.uid,
44
+ 'info' => {
45
+ 'name' => 'Beth',
46
+ 'email' => 'beth@example.com'
47
+ }
48
+ )
49
+ @found = OpenConferenceWare::Authentication.find_and_update_or_create_from_auth_hash(@auth_hash)
50
+ end
51
+
52
+ it "should find the existing record" do
53
+ @found.should == @existing
54
+ end
55
+
56
+ it "should update the record's name and email from the auth hash" do
57
+ @found.name.should == @auth_hash['info']['name']
58
+ @found.email.should == @auth_hash['info']['email']
59
+ end
60
+
61
+ it "should update the stashed copy of the info hash" do
62
+ @found.info.should == @auth_hash['info']
63
+ end
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,211 @@
1
+ require 'spec_helper'
2
+
3
+ describe OpenConferenceWare::Event do
4
+ describe "when accepting proposals" do
5
+ fixtures :all
6
+
7
+ it "should accept proposals for future" do
8
+ events(:closed).accepting_proposals?.should be_false
9
+ end
10
+
11
+ it "should not accept proposals for past" do
12
+ events(:open).accepting_proposals?.should be_true
13
+ end
14
+ end
15
+
16
+ describe "when determining if proposal status is visible" do
17
+ before :each do
18
+ @event = Event.new
19
+ end
20
+
21
+ it "should not be published by default" do
22
+ @event.proposal_status_published.should be_false
23
+ end
24
+
25
+ it "should be possible to publish proposal statuses" do
26
+ @event.proposal_status_published = true
27
+ @event.proposal_status_published.should be_true
28
+ end
29
+ end
30
+
31
+ describe "when finding current event" do
32
+ fixtures :all
33
+
34
+ it "should use find event" do
35
+ event = events(:open)
36
+
37
+ Event.should_receive(:current_by_settings).and_return(nil)
38
+ Event.should_receive(:current_by_deadline).and_return(event)
39
+
40
+ Event.current.should == event
41
+ end
42
+
43
+ it "should return nil if no current event is available" do
44
+ Event.destroy_all
45
+ Event.current.should be_nil
46
+ end
47
+ end
48
+
49
+ describe "#populated_proposals" do
50
+ fixtures :all
51
+
52
+ before(:each) do
53
+ @event = events(:open)
54
+ end
55
+
56
+ it "should get proposals and sessions for :proposals" do
57
+ records = @event.populated_proposals(:proposals)
58
+
59
+ records.select(&:confirmed?).should_not be_empty
60
+ records.reject(&:confirmed?).should_not be_empty
61
+ end
62
+
63
+ it "should get just sessions for :sessions" do
64
+ records = @event.populated_proposals(:sessions)
65
+
66
+ records.select(&:confirmed?).should_not be_empty
67
+ records.reject(&:confirmed?).should be_empty
68
+ end
69
+
70
+ it "should fail to get invalid kind" do
71
+ lambda { @event.populated_proposals(:omg) }.should raise_error(ArgumentError)
72
+ end
73
+ end
74
+
75
+ describe "#dates" do
76
+ it "should return range between start_date and end_date" do
77
+ start_date = Time.now.utc.to_date + 1.week
78
+ end_date = Time.now.utc.to_date + 2.weeks
79
+ event = build(:event, start_date: start_date, end_date: end_date)
80
+
81
+ event.dates.should == Array(start_date..end_date)
82
+ end
83
+
84
+ it "should return empty array if no dates" do
85
+ Event.new().dates.should == []
86
+ end
87
+
88
+ it "should return empty array if no start_date" do
89
+ build(:event, start_date: nil).dates.should == []
90
+ end
91
+
92
+ it "should return empty array if no end_date" do
93
+ build(:event, end_date: nil).dates.should == []
94
+ end
95
+ end
96
+
97
+ describe "#parent_or_self" do
98
+ it "should find a parent when there is one" do
99
+ parent = create(:event, title: "Mommy!", slug: "mommy", open_text: "Open!", closed_text: "Closed!")
100
+ child = create(:event, title: "Baby!", slug: "baby", open_text: "Open!", closed_text: "Closed!", parent: parent)
101
+
102
+ child.parent_or_self.should == parent
103
+ end
104
+
105
+ it "should find self when there's no parent" do
106
+ event = create(:event, title: "Event!", slug: "event", open_text: "Open!", closed_text: "Closed!")
107
+
108
+ event.parent_or_self.should == event
109
+ end
110
+ end
111
+
112
+ describe "#related_proposals" do
113
+ before :each do
114
+ Event.destroy_all
115
+
116
+ @parent = create :populated_event
117
+ @event = create :populated_event, parent: @parent
118
+ @child = create :populated_event, parent: @event
119
+ @unrelated = create :populated_event
120
+
121
+ @event_proposal = proposal_for_event @event
122
+ @parent_proposal = proposal_for_event @parent
123
+ @child_proposal = proposal_for_event @child
124
+ @unrelated_proposal = proposal_for_event @unrelated
125
+
126
+ @proposals = [@event_proposal, @parent_proposal, @child_proposal, @unrelated_proposal]
127
+
128
+ @event.reload
129
+
130
+ @related = @event.related_proposals @proposals
131
+ end
132
+
133
+ it "should find the event's proposals" do
134
+ @related.should include(@event_proposal)
135
+ end
136
+
137
+ it "should find the event parent's proposals" do
138
+ @related.should include(@parent_proposal)
139
+ end
140
+
141
+ it "should find the event children's proposals" do
142
+ @related.should include(@child_proposal)
143
+ end
144
+
145
+ it "should not find unrelated event's proposals" do
146
+ @related.should_not include(@unrelated_proposal)
147
+ end
148
+ end
149
+
150
+ describe "#descendents" do
151
+ before :each do
152
+ @parent = create :populated_event
153
+ @event = create :populated_event, parent: @parent
154
+ @child = create :populated_event, parent: @event
155
+ @grandchild = create :populated_event, parent: @child
156
+ @unrelated = create :populated_event
157
+
158
+ @descendents = @event.descendents
159
+ end
160
+
161
+ it "should include an event's children" do
162
+ @descendents.should include(@child)
163
+ end
164
+
165
+ it "should include an event's children's children" do
166
+ @descendents.should include(@grandchild)
167
+ end
168
+
169
+ it "should not include parent" do
170
+ @descendents.should_not include(@parent)
171
+ end
172
+
173
+ it "should not include unrelated event" do
174
+ @descendents.should_not include(@unrelated)
175
+ end
176
+ end
177
+
178
+ describe "#family" do
179
+ before :each do
180
+ @parent = create :populated_event
181
+ @stepchild = create :populated_event, parent: @parent
182
+ @event = create :populated_event, parent: @parent
183
+ @child = create :populated_event, parent: @event
184
+ @grandchild = create :populated_event, parent: @child
185
+ @unrelated = create :populated_event
186
+
187
+ @family = @event.family
188
+ end
189
+
190
+ it "should include an event's children" do
191
+ @family.should include(@child)
192
+ end
193
+
194
+ it "should include an event's children's children" do
195
+ @family.should include(@grandchild)
196
+ end
197
+
198
+ it "should include parent" do
199
+ @family.should include(@parent)
200
+ end
201
+
202
+ it "should include step-child" do
203
+ @family.should include(@stepchild)
204
+ end
205
+
206
+ it "should not include unrelated event" do
207
+ @family.should_not include(@unrelated)
208
+ end
209
+ end
210
+
211
+ end
@@ -0,0 +1,606 @@
1
+ require 'spec_helper'
2
+
3
+ describe OpenConferenceWare::Proposal do
4
+ fixtures :all
5
+
6
+ describe "when checking authorization for altering" do
7
+ before(:each) do
8
+ @proposal = proposals(:quentin_widgets)
9
+ end
10
+
11
+ it "should not allow anonymous" do
12
+ @proposal.can_alter?(nil).should be_false
13
+ end
14
+
15
+ it "should not allow wrong mortal" do
16
+ @proposal.can_alter?(users(:clio)).should be_false
17
+ end
18
+
19
+ it "should allow mortal owner" do
20
+ @proposal.can_alter?(users(:quentin)).should be_true
21
+ end
22
+
23
+ it "should allow admin" do
24
+ @proposal.can_alter?(users(:aaron)).should be_true
25
+ end
26
+ end
27
+
28
+ describe "when setting submitted_at date" do
29
+ it "should set value on save" do
30
+ proposal = proposals(:quentin_widgets)
31
+ proposal.submitted_at = nil
32
+ proposal.save!
33
+ proposal.reload
34
+
35
+ proposal.submitted_at.should_not be_nil
36
+ end
37
+
38
+ it "should set value to created_at date" do
39
+ proposal = proposals(:quentin_widgets)
40
+ proposal.submitted_at = nil
41
+ proposal.save!
42
+ proposal.reload
43
+
44
+ proposal.submitted_at.should == proposal.created_at
45
+ end
46
+ end
47
+
48
+ describe "when setting status" do
49
+ before(:each) do
50
+ @proposal = new_proposal
51
+ @proposal.save!
52
+ end
53
+
54
+ it "should default to a state of 'proposed'" do
55
+ @proposal.should be_proposed
56
+ end
57
+
58
+ it "should be possible to accept a proposed proposal" do
59
+ @proposal.accept!
60
+ @proposal.should be_accepted
61
+ end
62
+
63
+ it "should be possible to confirm a proposed proposal" do
64
+ @proposal.accept_and_confirm!
65
+ @proposal.should be_confirmed
66
+ end
67
+
68
+ it "should be possible to decline a proposed proposal" do
69
+ @proposal.accept_and_decline!
70
+ @proposal.should be_declined
71
+ end
72
+
73
+ it "should be possible to reject a proposed proposal" do
74
+ @proposal.reject!
75
+ @proposal.should be_rejected
76
+ end
77
+
78
+ it "should be possible to confirm an accepted proposal" do
79
+ @proposal.status = 'accepted'
80
+ @proposal.confirm!
81
+ @proposal.should be_confirmed
82
+ end
83
+
84
+ it "should be possible to decline an accepted proposal" do
85
+ @proposal.status = 'accepted'
86
+ @proposal.decline!
87
+ @proposal.should be_declined
88
+ end
89
+
90
+ it "should be possible to accept a rejected proposal" do
91
+ @proposal.status = 'rejected'
92
+ @proposal.accept!
93
+ @proposal.should be_accepted
94
+ end
95
+
96
+ it "should be possible to reject an accepted proposal" do
97
+ @proposal.status = 'accepted'
98
+ @proposal.reject!
99
+ @proposal.should be_rejected
100
+ end
101
+
102
+ it "should be possible to mark a proposed proposal as junk" do
103
+ @proposal.mark_as_junk!
104
+ @proposal.should be_junk
105
+ end
106
+
107
+ it "should be possible to cancel a confirmed proposal" do
108
+ @proposal.status = 'confirmed'
109
+ @proposal.cancel!
110
+ @proposal.should be_cancelled
111
+ end
112
+
113
+ it "should be possible to waitlist a proposed proposal" do
114
+ @proposal.waitlist!
115
+ @proposal.should be_waitlisted
116
+ end
117
+
118
+ it "should be possible to waitlist an accepted proposal" do
119
+ @proposal.status = 'accepted'
120
+ @proposal.waitlist!
121
+ @proposal.should be_waitlisted
122
+ end
123
+
124
+ it "should be possible to waitlist a rejected proposal" do
125
+ @proposal.status = 'rejected'
126
+ @proposal.waitlist!
127
+ @proposal.should be_waitlisted
128
+ end
129
+
130
+ it "should be possible to accept a waitlisted proposal" do
131
+ @proposal.status = 'waitlisted'
132
+ @proposal.accept!
133
+ @proposal.should be_accepted
134
+ end
135
+
136
+ it "should be possible to confirm a waitlisted proposal" do
137
+ @proposal.status = 'waitlisted'
138
+ @proposal.accept_and_confirm!
139
+ @proposal.should be_confirmed
140
+ end
141
+
142
+ it "should be possible to decline a waitlisted proposal" do
143
+ @proposal.status = 'waitlisted'
144
+ @proposal.accept_and_decline!
145
+ @proposal.should be_declined
146
+ end
147
+
148
+ it "should be possible to reject a waitlisted proposal" do
149
+ @proposal.status = 'waitlisted'
150
+ @proposal.reject!
151
+ @proposal.should be_rejected
152
+ end
153
+
154
+ %w(accepted confirmed waitlisted rejected declined junk cancelled).each do |initial_status|
155
+ it "should be posible to reset a #{initial_status} proposal back to proposed" do
156
+ @proposal.status = initial_status
157
+ @proposal.reset_status!
158
+ @proposal.should be_proposed
159
+ end
160
+ end
161
+
162
+ describe "through the transition accessor" do
163
+ it "should be possible to call a valid event" do
164
+ @proposal.should be_proposed
165
+ @proposal.transition = 'accept'
166
+ @proposal.should be_accepted
167
+ end
168
+
169
+ it "should not call invalid event methods" do
170
+ @proposal.should_not_receive(:destroy!)
171
+ @proposal.transition = 'destroy'
172
+ end
173
+ end
174
+ end
175
+
176
+ describe "when getting comments" do
177
+ before(:each) do
178
+ @proposal = proposals(:quentin_widgets)
179
+ end
180
+
181
+ it "should return nothing if no comments" do
182
+ @proposal.comments_text.blank?.should be_true
183
+ end
184
+
185
+ it "should return one comment" do
186
+ comments = [
187
+ double(Comment, email: "bubba@smith.com", message: "Hi"),
188
+ ]
189
+ @proposal.should_receive(:comments).and_return(comments)
190
+
191
+ @proposal.comments_text.should == "bubba@smith.com: Hi"
192
+ end
193
+
194
+ it "should return multiple comments" do
195
+ comments = [
196
+ double(Comment, email: "bubba@smith.com", message: "Hi"),
197
+ double(Comment, email: "billy.sue@smith.com", message: "Yo"),
198
+ ]
199
+ @proposal.should_receive(:comments).and_return(comments)
200
+
201
+ @proposal.comments_text.should ==
202
+ "bubba@smith.com: Hi\nbilly.sue@smith.com: Yo"
203
+ end
204
+ end
205
+
206
+ describe "when getting profile" do
207
+ before(:each) do
208
+ @proposal = proposals(:quentin_widgets)
209
+ end
210
+
211
+ it "should return false if multiple_presenters is enabled" do
212
+ OpenConferenceWare.stub(:have_multiple_presenters).and_return(true)
213
+ @proposal.profile.should be_false
214
+ end
215
+
216
+ it "should return the user if user_profiles is enabled" do
217
+ OpenConferenceWare.stub(:have_multiple_presenters).and_return(false)
218
+ OpenConferenceWare.stub(:have_user_profiles).and_return(true)
219
+ @proposal.profile.should == @proposal.user
220
+ end
221
+
222
+ it "should return itself if multiple_presenters and user_profiles are disabled" do
223
+ OpenConferenceWare.stub(:have_multiple_presenters).and_return(false)
224
+ OpenConferenceWare.stub(:have_user_profiles).and_return(false)
225
+ @proposal.profile.should == @proposal
226
+ end
227
+ end
228
+
229
+ describe "when adding or removing user" do
230
+ before(:each) do
231
+ @user = stub_model(User)
232
+ @users = []
233
+ @proposal = stub_model(Proposal)
234
+ @proposal.should_receive(:users).at_least(:once).and_return(@users)
235
+ end
236
+
237
+ describe "when adding user" do
238
+ it "should add a user" do
239
+ @users.should_receive(:include?).with(@user).and_return(false)
240
+ @users.should_receive(:<<).with(@user).and_return(@user)
241
+
242
+ @proposal.add_user(@user)
243
+ end
244
+
245
+ it "should not re-add an existing user" do
246
+ @users.should_receive(:include?).with(@user).and_return(true)
247
+ @users.should_not_receive(:<<)
248
+
249
+ @proposal.add_user(@user)
250
+ end
251
+ end
252
+
253
+ describe "when removing user" do
254
+ it "should remove a user" do
255
+ @users.should_receive(:include?).with(@user).and_return(true)
256
+ @users.should_receive(:delete).with(@user).and_return(@user)
257
+
258
+ @proposal.remove_user(@user)
259
+ end
260
+
261
+ it "should not remove a non-existent user" do
262
+ @users.should_receive(:include?).with(@user).and_return(false)
263
+ @users.should_not_receive(:delete)
264
+
265
+ @proposal.remove_user(@user)
266
+ end
267
+ end
268
+ end
269
+
270
+ describe "with rooms" do
271
+ before :each do
272
+ @proposal = Proposal.new
273
+ end
274
+
275
+ it "should be able to assign a room to an proposal" do
276
+ room = stub_model(Room)
277
+ @proposal.room = room
278
+ @proposal.room.should==room
279
+ end
280
+ end
281
+
282
+ describe "to_icalendar" do
283
+ def assert_calendar_match(item, component, url_helper=nil)
284
+ component.should_not be_nil
285
+
286
+ # This is hacky, but necessary because vPim doesn't actually parse
287
+ # time zone information out of iCalendar files.
288
+ #
289
+ # The files are output with the correct time zone, but seem to be
290
+ # parsed in the computer's local time, regardless of the Rails
291
+ # time zone setting.
292
+ dtstart = Time.parse(component.dtstart.strftime('%Y-%m-%d %H:%M:%S UTC'))
293
+ dtstart.to_i.should == item.start_time.to_i
294
+ if item.duration
295
+ dtend = Time.parse(component.dtend.strftime('%Y-%m-%d %H:%M:%S UTC'))
296
+ dtend.to_i.should == item.end_time.to_i
297
+ else
298
+ component.dtend.should be_nil
299
+ end
300
+ component.summary.should == item.title
301
+ component.description.should == (item.respond_to?(:users) ?
302
+ "#{item.users.map(&:fullname).join(', ')}: #{item.excerpt}" :
303
+ item.excerpt)
304
+ component.url.should == url_helper.call(item) if url_helper
305
+ end
306
+
307
+ it "should export proposals to iCalendar" do
308
+ mysql_record = proposals(:mysql_session)
309
+ postgresql_record = proposals(:postgresql_session)
310
+ items = [ mysql_record, postgresql_record ]
311
+ title = "MyTitle"
312
+ url_helper = lambda {|item| "http://foo.bar/#{item.id}"}
313
+
314
+ data = Proposal.to_icalendar(items, title: title, url_helper: url_helper)
315
+
316
+ calendar = Vpim::Icalendar.decode(data).first
317
+ components = Array(calendar)
318
+ components.size.should == 2
319
+ assert_calendar_match(mysql_record, components.find{|t| t.summary == mysql_record.title}, url_helper)
320
+ assert_calendar_match(postgresql_record, components.find{|t| t.summary == postgresql_record.title}, url_helper)
321
+ end
322
+
323
+ it "should skip items without a start time" do
324
+ event = create :populated_event
325
+ item = create :schedule_item, start_time: nil, duration: nil
326
+
327
+ data = Proposal.to_icalendar([item])
328
+ calendar = Vpim::Icalendar.decode(data).first
329
+ components = Array(calendar)
330
+ components.size.should == 0
331
+ end
332
+
333
+ it "should not raise exceptions if nil duration" do
334
+ event = create :populated_event
335
+ item = create :schedule_item, duration: nil
336
+
337
+ data = Proposal.to_icalendar([item])
338
+ calendar = Vpim::Icalendar.decode(data).first
339
+ components = Array(calendar)
340
+ components.size.should == 1
341
+ component = components.first
342
+ assert_calendar_match(item, component)
343
+ end
344
+ end
345
+
346
+ describe "session_notes_url" do
347
+ before do
348
+ @proposal = proposals(:clio_chupacabras)
349
+ end
350
+
351
+ it "should be nil if no session_notes_url_format is defined" do
352
+ OpenConferenceWare.stub(session_notes_url_format: nil)
353
+
354
+ @proposal.session_notes_url.should be_nil
355
+ end
356
+
357
+ describe "with wiki" do
358
+ before :each do
359
+ OpenConferenceWare.stub(
360
+ session_notes_url_format: '%1$s%2$s/wiki/',
361
+ public_url: 'http://mysite.com/'
362
+ )
363
+ end
364
+
365
+ it "should interpolate content if session_notes_url_format is defined" do
366
+ @proposal.session_notes_url.should == "http://mysite.com/closed/wiki/Chupacabras_and_you"
367
+ end
368
+
369
+ it "should replace slashes with dashes" do
370
+ @proposal.title = "CouchApp Evently Guided Hack w/ CouchDB"
371
+ @proposal.session_notes_url.should == "http://mysite.com/closed/wiki/CouchApp_Evently_Guided_Hack_w-_CouchDB"
372
+ end
373
+ end
374
+ end
375
+
376
+ describe "when sorting" do
377
+ before(:each) do
378
+ @shonen = stub_model(Track, title: "Shonen")
379
+ @bishoujo = stub_model(Track, title: "Bishoujo")
380
+ @tracks = [@shonen, @bishoujo]
381
+
382
+ @naruto = stub_model(Proposal,
383
+ title: "Naruto",
384
+ track: @shonen,
385
+ status: "proposed",
386
+ submitted_at: Time.parse('2009/12/09 01:00'),
387
+ start_time: Time.parse('2009/12/10 05:00'))
388
+ @bleach = stub_model(Proposal,
389
+ title: "Bleach",
390
+ track: @shonen,
391
+ status: "confirmed",
392
+ submitted_at: Time.parse('2009/12/09 02:00'),
393
+ start_time: Time.parse('2009/12/10 04:00'))
394
+ @sera_mun = stub_model(Proposal,
395
+ title: "Bishoujo Senshi Sera Mun",
396
+ track: @bishoujo,
397
+ status: "confirmed",
398
+ submitted_at: Time.parse('2009/12/09 04:00'),
399
+ start_time: Time.parse('2009/12/10 01:00'))
400
+ @kadocapta_sakura = stub_model(Proposal,
401
+ title: "Kadocapta Sakura",
402
+ track: @bishoujo,
403
+ status: "accepted",
404
+ submitted_at: Time.parse('2009/12/09 03:00'),
405
+ start_time: Time.parse('2009/12/10 02:00'))
406
+ @kino = stub_model(Proposal,
407
+ title: "Kino no Tabi",
408
+ track: nil,
409
+ status: "accepted",
410
+ submitted_at: Time.parse('2009/12/09 06:00'),
411
+ start_time: Time.parse('2009/12/10 06:00'))
412
+ @proposals = [@kadocapta_sakura, @bleach, @kino, @naruto, @sera_mun]
413
+ end
414
+
415
+ it "should sort by title" do
416
+ Proposal.sort(@proposals, :title).should == [@sera_mun, @bleach, @kadocapta_sakura, @kino, @naruto]
417
+ end
418
+
419
+ it "should sort by title descending" do
420
+ Proposal.sort(@proposals, :title, false).should == [@naruto, @kino, @kadocapta_sakura, @bleach, @sera_mun]
421
+ end
422
+
423
+ it "should sort by track" do
424
+ Proposal.sort(@proposals, :track).should == [@sera_mun, @kadocapta_sakura, @bleach, @naruto, @kino]
425
+ end
426
+
427
+ it "should sort by status" do
428
+ Proposal.sort(@proposals, :status).should == [@kadocapta_sakura, @kino, @sera_mun, @bleach, @naruto]
429
+ end
430
+
431
+ it "should sort by submitted date" do
432
+ Proposal.sort(@proposals, :submitted_at).should == [@naruto, @bleach, @kadocapta_sakura, @sera_mun, @kino]
433
+ end
434
+
435
+ it "should default to sorting by submitted date if given unknown sorting" do
436
+ Proposal.sort(@proposals, :submitted_at).should == [@naruto, @bleach, @kadocapta_sakura, @sera_mun, @kino]
437
+ end
438
+ end
439
+
440
+ describe "when retreiving slug" do
441
+ it "should return a slug composed of the organization and event slugs plus the proposal identifier" do
442
+ proposal = proposals(:clio_chupacabras)
443
+
444
+ proposal.slug.should == "#{OpenConferenceWare.organization_slug}#{proposal.event.slug}-%04d" % proposal.id
445
+ end
446
+ end
447
+
448
+ describe "is a proposal related to an event?" do
449
+ it "should be related to its own event" do
450
+ event = create :populated_event
451
+ proposal = proposal_for_event(event)
452
+
453
+ proposal.related_to_event?(proposal.event).should be_true
454
+ end
455
+
456
+ it "should be related to its own event's parent" do
457
+ parent = create :populated_event
458
+ event = create :populated_event, parent: parent
459
+ proposal = proposal_for_event(event)
460
+
461
+ proposal.related_to_event?(event).should be_true
462
+ end
463
+
464
+ it "should be related to its own event's parent's children" do
465
+ event = create :populated_event
466
+ child = create :populated_event, parent: event
467
+ proposal = proposal_for_event(event)
468
+
469
+ proposal.related_to_event?(event).should be_true
470
+ end
471
+
472
+ it "should not be related to an unrelated event" do
473
+ event = create :populated_event
474
+ proposal = proposal_for_event(event)
475
+ unrelated = create :populated_event
476
+
477
+ proposal.related_to_event?(unrelated).should be_false
478
+ end
479
+ end
480
+
481
+ describe "traversal" do
482
+ before(:each) do
483
+ @event = create :populated_event
484
+ @event.proposals.destroy_all
485
+ @proposal1 = proposal_for_event(@event)
486
+ @proposal2 = proposal_for_event(@event)
487
+ end
488
+
489
+ describe "when finding next proposal" do
490
+ it "should return the next proposal when it exists" do
491
+ @proposal1.next_proposal.should == @proposal2
492
+ end
493
+
494
+ it "should return nil when it's the last" do
495
+ @proposal2.next_proposal.should be_nil
496
+ end
497
+ end
498
+
499
+ describe "when finding previous proposal" do
500
+ it "should return the previous proposal when it exists" do
501
+ @proposal2.previous_proposal.should == @proposal1
502
+ end
503
+
504
+ it "should return nil when it's the first" do
505
+ @proposal1.previous_proposal.should be_nil
506
+ end
507
+ end
508
+ end
509
+
510
+ describe "when notifying accepted speakers" do
511
+ before(:each) do
512
+ @proposal = proposals(:quentin_widgets)
513
+ end
514
+
515
+ it "should not notify unaccepted proposal speakers" do
516
+ emailed, already = @proposal.notify_accepted_speakers
517
+ emailed.should be_nil
518
+ already.should be_nil
519
+ @proposal.notified_at.should be_nil
520
+ end
521
+
522
+ it "should not notify already-notified proposal speakers" do
523
+ @proposal.accept!
524
+ @proposal.notified_at = Time.now
525
+ emailed, already = @proposal.notify_accepted_speakers
526
+ emailed.should be_nil
527
+ already.should == @proposal.mailto_emails
528
+ end
529
+
530
+ it "should notify accepted proposal speakers" do
531
+ @proposal.accept!
532
+ emailed, already = @proposal.notify_accepted_speakers
533
+ emailed.should == @proposal.mailto_emails
534
+ already.should be_nil
535
+ @proposal.notified_at.should_not be_nil
536
+ end
537
+ end
538
+
539
+ describe "when notifying rejected speakers" do
540
+ before(:each) do
541
+ @proposal = proposals(:quentin_widgets)
542
+ end
543
+
544
+ it "should not notify unrejected proposal speakers" do
545
+ emailed, already = @proposal.notify_rejected_speakers
546
+ emailed.should be_nil
547
+ already.should be_nil
548
+ @proposal.notified_at.should be_nil
549
+ end
550
+
551
+ it "should not notify already-notified proposal speakers" do
552
+ @proposal.reject!
553
+ @proposal.notified_at = Time.now
554
+ emailed, already = @proposal.notify_rejected_speakers
555
+ emailed.should be_nil
556
+ already.should == @proposal.mailto_emails
557
+ end
558
+
559
+ it "should notify rejected proposal speakers" do
560
+ @proposal.reject!
561
+ emailed, already = @proposal.notify_rejected_speakers
562
+ emailed.should == @proposal.mailto_emails
563
+ already.should be_nil
564
+ @proposal.notified_at.should_not be_nil
565
+ end
566
+ end
567
+
568
+ describe "validating acceptance of the policy agreement," do
569
+ before(:each) do
570
+ @proposal = proposals(:quentin_widgets)
571
+ end
572
+
573
+ describe "when one exists," do
574
+ it "should require presenters to accept the agreement" do
575
+ @proposal.agreement = false
576
+ @proposal.should_not be_valid
577
+ @proposal.agreement = true
578
+ @proposal.should be_valid
579
+ end
580
+ end
581
+
582
+ describe "when no agreement is set" do
583
+ before do
584
+ OpenConferenceWare.stub(agreement: nil)
585
+ end
586
+
587
+ it "should not require presenters to accept the agreement" do
588
+ @proposal.agreement = false
589
+ @proposal.should be_valid
590
+ end
591
+ end
592
+ end
593
+
594
+
595
+ private
596
+
597
+ def new_proposal(attr = {})
598
+ # TODO: The proposal factory should handle these associations
599
+ valid_attr = {
600
+ event: mock_model(Event),
601
+ track: mock_model(Track),
602
+ session_type: mock_model(SessionType)
603
+ }
604
+ build(:proposal, valid_attr.merge(attr))
605
+ end
606
+ end