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,42 @@
1
+ module OpenConferenceWare
2
+ class AuthenticationsController < ApplicationController
3
+ before_filter :require_auth_hash, only: [:create]
4
+
5
+ def sign_in
6
+ page_title "Sign In"
7
+ end
8
+
9
+ def sign_out
10
+ cookies.delete :auth_token
11
+ reset_session
12
+ flash[:notice] = "You have been logged out."
13
+
14
+ redirect_back_or_default
15
+ end
16
+
17
+ def create
18
+ @authentication = Authentication.find_and_update_or_create_from_auth_hash(auth_hash)
19
+
20
+ if @authentication.user
21
+ self.current_user = @authentication.user
22
+ elsif logged_in?
23
+ @authentication.user = current_user
24
+ @authentication.save
25
+ else
26
+ self.current_user = User.create_from_authentication(@authentication)
27
+ end
28
+
29
+ redirect_back_or_default
30
+ end
31
+
32
+ protected
33
+
34
+ def auth_hash
35
+ request.env['omniauth.auth']
36
+ end
37
+
38
+ def require_auth_hash
39
+ redirect_to(sign_in_path) and return unless auth_hash
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,86 @@
1
+ module OpenConferenceWare
2
+ class CommentsController < ApplicationController
3
+
4
+ SECRET = OpenConferenceWare.comments_secret
5
+
6
+ MAX_FEED_ITEMS = 50
7
+
8
+ before_filter :require_admin, except: [:index, :create]
9
+
10
+ def index
11
+ @comments = Comment.listable
12
+ add_breadcrumb "Comments", comments_path()
13
+
14
+ if [:atom, :json, :xml].include?(request.format.to_sym)
15
+ unless params[:secret] == SECRET
16
+ render(text: "403 Forbidden: You can't see the comments feed unless you supply the secret key", status: 403) and return
17
+ end
18
+ @comments = @comments[0..MAX_FEED_ITEMS]
19
+ else
20
+ if admin?
21
+ respond_to do |format|
22
+ format.html # index.html.erb
23
+ format.atom
24
+ end
25
+ else
26
+ require_admin
27
+ end
28
+ end
29
+ end
30
+
31
+ # This is a weird action. The form is part of the proposals#show page, so errors and successes both go back to that page.
32
+ def create
33
+ if params[:quagmire].present?
34
+ flash[:failure] = "Comment rejected because you're behaving like a robot, please leave the 'Leave blank' field blank."
35
+ redirect_to(:back) rescue redirect_to proposals_path()
36
+ return
37
+ end
38
+
39
+ @proposal = Proposal.find(params[:proposal_id])
40
+ @comment = @proposal.comments.new(comment_params)
41
+
42
+ # Use session to store email address and prefill it as needed
43
+ if @comment.email.blank?
44
+ @comment.email = current_email
45
+ else
46
+ session[:email] = @comment.email
47
+ end
48
+
49
+ respond_to do |format|
50
+ if @comment.save
51
+ flash[:success] = "Comment added."
52
+ format.html { redirect_to(proposal_path(@comment.proposal, commented: true)) }
53
+ format.xml { render xml: @comment, status: :created }
54
+ format.json { render json: @comment, status: :created }
55
+ else
56
+ @display_comment_form = true
57
+ @focus_comment = true
58
+ flash[:failure] = "Invalid comment."
59
+
60
+ format.html { render template: "open_conference_ware/proposals/show" }
61
+ format.xml { render xml: @comment.errors, status: :unprocessable_entity }
62
+ format.json { render json: @comment.errors, status: :unprocessable_entity }
63
+ end
64
+ end
65
+ end
66
+
67
+ def destroy
68
+ @comment = Comment.find(params[:id])
69
+ @comment.destroy
70
+ flash[:success] = "Destroyed comment: #{@comment.id}"
71
+
72
+ respond_to do |format|
73
+ format.html {
74
+ redirect_to(:back) rescue redirect_to(comments_path)
75
+ }
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def comment_params
82
+ params.require(:comment).permit(:name, :email, :message)
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,36 @@
1
+ module OpenConferenceWare
2
+ class EventsController < ApplicationController
3
+ include BreadcrumbsMixin
4
+ add_breadcrumb "Events", "/events"
5
+
6
+ before_filter :assert_current_event_or_redirect
7
+ before_filter :normalize_event_path_or_redirect
8
+ before_filter :assert_proposal_status_published, only: :speakers
9
+ before_filter :require_admin, only: [:selector_votes]
10
+
11
+ def index
12
+ @events = Event.order("deadline asc")
13
+
14
+ respond_to do |format|
15
+ format.html
16
+ format.json { render json: @events }
17
+ end
18
+ end
19
+
20
+ def show
21
+ respond_to do |format|
22
+ format.html { redirect_to event_proposals_path(@event) }
23
+ format.json { render json: @event }
24
+ end
25
+ end
26
+
27
+ def speakers
28
+ assign_prefetched_hashes
29
+
30
+ respond_to do |format|
31
+ format.html
32
+ format.csv { render csv: @speakers, style: admin? ? :full : :public }
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,157 @@
1
+ module OpenConferenceWare
2
+ module Manage
3
+ class EventsController < ApplicationController
4
+ before_filter :require_admin
5
+ before_filter :assert_current_event_or_redirect, only: [:show, :edit, :update, :destroy]
6
+
7
+ include BreadcrumbsMixin
8
+ add_breadcrumb "Manage", "/manage"
9
+ add_breadcrumb "Events", "/manage/events"
10
+
11
+ # GET /events
12
+ # GET /events.xml
13
+ def index
14
+ @events = Event.lookup
15
+
16
+ respond_to do |format|
17
+ format.html # index.html.erb
18
+ format.xml { render xml: @events }
19
+ end
20
+ end
21
+
22
+ # GET /events/1
23
+ # GET /events/1.xml
24
+ def show
25
+ warn_about_incomplete_event
26
+
27
+ add_breadcrumb @event.title, manage_event_path(@event)
28
+
29
+ respond_to do |format|
30
+ format.html # show.html.erb
31
+ format.xml { render xml: @event }
32
+ end
33
+ end
34
+
35
+ # GET /events/new
36
+ # GET /events/new.xml
37
+ def new
38
+ @event = Event.new
39
+ if params[:parent_id]
40
+ @event.parent_id = params[:parent_id]
41
+ end
42
+
43
+ respond_to do |format|
44
+ format.html # new.html.erb
45
+ format.xml { render xml: @event }
46
+ end
47
+ end
48
+
49
+ # GET /events/1/edit
50
+ def edit
51
+ @return_to = params[:return_to] || request.env["HTTP_REFERER"]
52
+ end
53
+
54
+ # POST /events
55
+ # POST /events.xml
56
+ def create
57
+ @event = Event.new(event_params)
58
+
59
+ respond_to do |format|
60
+ if @event.save
61
+ flash[:notice] = 'Event was successfully created.'
62
+ format.html { redirect_to(manage_event_path(@event)) }
63
+ format.xml { render xml: @event, status: :created, location: @event }
64
+ else
65
+ format.html { render action: "new" }
66
+ format.xml { render xml: @event.errors, status: :unprocessable_entity }
67
+ end
68
+ end
69
+ end
70
+
71
+ # PUT /events/1
72
+ # PUT /events/1.xml
73
+ def update
74
+ @return_to = params[:return_to]
75
+
76
+ respond_to do |format|
77
+ if @event.update_attributes(event_params)
78
+ flash[:notice] = 'Event was successfully updated.'
79
+ format.html { redirect_to(@return_to ? @return_to : [:manage, @event]) }
80
+ format.xml { head :ok }
81
+ else
82
+ format.html { render action: "edit" }
83
+ format.xml { render xml: @event.errors, status: :unprocessable_entity }
84
+ end
85
+ end
86
+ end
87
+
88
+ # DELETE /events/1
89
+ # DELETE /events/1.xml
90
+ def destroy
91
+ @event.destroy
92
+ flash[:success] = "Destroyed event: #{@event.title}"
93
+
94
+ respond_to do |format|
95
+ format.html { redirect_to(manage_events_path) }
96
+ format.xml { head :ok }
97
+ end
98
+ end
99
+
100
+ def proposals
101
+ # NOTE: This is the bulk editor for the admin.
102
+ @proposals = @event.proposals.populated
103
+ end
104
+
105
+ # POST /events/1/notify_speakers
106
+ def notify_speakers
107
+ emailed = []
108
+ already_emailed = []
109
+ proposals = params[:proposal_ids].split(',')
110
+ proposals.each do |proposal_id|
111
+ proposal = Proposal.lookup(proposal_id)
112
+ next unless proposal
113
+ case params[:proposal_status]
114
+ when 'accepted'
115
+ e, a = proposal.notify_accepted_speakers
116
+ when 'rejected'
117
+ e, a = proposal.notify_rejected_speakers
118
+ else
119
+ raise ArgumentError, "No proposal_status specified"
120
+ end
121
+ emailed << e if e
122
+ already_emailed << a if a
123
+ end
124
+ flash[:success] = "Notified these speakers: "
125
+ flash[:success] << ( emailed.count == 0 ? "none" : emailed.join(' &amp; ') )
126
+ unless already_emailed.count == 0
127
+ flash[:success] << "<br/>These proposal speakers were not emailed because they have already been notified: #{already_emailed.join(' &amp; ')}."
128
+ end
129
+ redirect_to(manage_event_proposals_path(@event))
130
+ end
131
+
132
+ private
133
+
134
+ def event_params
135
+ params.require(:event).permit(
136
+ :slug,
137
+ :title,
138
+ :deadline,
139
+ :open_text,
140
+ :closed_text,
141
+ :session_text,
142
+ :tracks_text,
143
+ :start_date,
144
+ :end_date,
145
+ :proposal_status_published,
146
+ :accept_proposal_comments_after_deadline,
147
+ :schedule_published,
148
+ :proposal_titles_locked,
149
+ :accept_selector_votes,
150
+ :show_proposal_confirmation_controls,
151
+ :parent,
152
+ :parent_id
153
+ ) if admin?
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,110 @@
1
+ module OpenConferenceWare
2
+ module Manage
3
+ class SnippetsController < ApplicationController
4
+ before_filter :require_admin
5
+
6
+ include BreadcrumbsMixin
7
+ add_breadcrumb "Manage", "/manage"
8
+ add_breadcrumb "Snippets", "/manage/snippets/"
9
+
10
+ # GET /snippets
11
+ # GET /snippets.xml
12
+ def index
13
+ @snippets = Snippet.order(:slug).where(public: true)
14
+
15
+ respond_to do |format|
16
+ format.html # index.html.erb
17
+ format.xml { render xml: @snippets }
18
+ end
19
+ end
20
+
21
+ # GET /snippets/1
22
+ # GET /snippets/1.xml
23
+ def show
24
+ @snippet = Snippet.find(params[:id])
25
+ add_breadcrumb @snippet.slug, manage_snippet_path(@snippet)
26
+
27
+ respond_to do |format|
28
+ format.html # show.html.erb
29
+ format.xml { render xml: @snippet }
30
+ end
31
+ end
32
+
33
+ # GET /snippets/new
34
+ # GET /snippets/new.xml
35
+ def new
36
+ @snippet = Snippet.new
37
+
38
+ respond_to do |format|
39
+ format.html # new.html.erb
40
+ format.xml { render xml: @snippet }
41
+ end
42
+ end
43
+
44
+ # GET /snippets/1/edit
45
+ def edit
46
+ @snippet = Snippet.find(params[:id])
47
+ add_breadcrumb @snippet.slug, manage_snippet_path(@snippet)
48
+
49
+ @return_to = params[:return_to] || request.env["HTTP_REFERER"]
50
+ end
51
+
52
+ # POST /snippets
53
+ # POST /snippets.xml
54
+ def create
55
+ @snippet = Snippet.new(snippet_params)
56
+
57
+ respond_to do |format|
58
+ if @snippet.save
59
+ flash[:notice] = 'Snippet was successfully created.'
60
+ format.html { redirect_to([:manage, @snippet]) }
61
+ format.xml { render xml: @snippet, status: :created, location: @snippet }
62
+ else
63
+ format.html { render action: "new" }
64
+ format.xml { render xml: @snippet.errors, status: :unprocessable_entity }
65
+ end
66
+ end
67
+ end
68
+
69
+ # PUT /snippets/1
70
+ # PUT /snippets/1.xml
71
+ def update
72
+ @snippet = Snippet.find(params[:id])
73
+ add_breadcrumb @snippet.slug, manage_snippet_path(@snippet)
74
+
75
+ @return_to = params[:return_to]
76
+
77
+ respond_to do |format|
78
+ if @snippet.update_attributes(snippet_params)
79
+ flash[:notice] = 'Snippet was successfully updated.'
80
+ format.html { redirect_to(@return_to ? @return_to : [:manage, @snippet]) }
81
+ format.xml { head :ok }
82
+ else
83
+ format.html { render action: "edit" }
84
+ format.xml { render xml: @snippet.errors, status: :unprocessable_entity }
85
+ end
86
+ end
87
+ end
88
+
89
+ # DELETE /snippets/1
90
+ # DELETE /snippets/1.xml
91
+ def destroy
92
+ @snippet = Snippet.find(params[:id])
93
+ @snippet.destroy
94
+
95
+ respond_to do |format|
96
+ format.html { redirect_to manage_snippets_path, :flash => {:success => "Snippet was deleted."} }
97
+ format.xml { head :ok }
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ def snippet_params
104
+ params.require(:snippet).permit(
105
+ :slug, :description, :content, :value, :public
106
+ ) if admin?
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,521 @@
1
+ module OpenConferenceWare
2
+ class ProposalsController < ApplicationController
3
+
4
+ before_filter :authentication_required, only: [:edit, :update, :destroy, :speaker_confirm, :speaker_decline, :proposal_login_required]
5
+ before_filter :assert_current_event_or_redirect
6
+ before_filter :assert_proposal_status_published, only: [:sessions_index, :sessions_index_terse, :session_show]
7
+ before_filter :assert_schedule_published, only: [:schedule]
8
+ before_filter :normalize_event_path_or_redirect, only: [:index, :sessions_index, :schedule]
9
+ before_filter :assert_anonymous_proposals, only: [:new, :create]
10
+ before_filter :assert_accepting_proposals, only: [:new, :create]
11
+ before_filter :assign_proposal_and_event, only: [:show, :session_show, :edit, :update, :destroy, :speaker_confirm, :speaker_decline]
12
+ before_filter :assert_record_ownership, only: [:edit, :update, :destroy, :speaker_confirm, :speaker_decline]
13
+ before_filter :assert_user_complete_profile, only: [:new, :edit, :update]
14
+ before_filter :assign_proposals_breadcrumb
15
+
16
+ MAX_FEED_ITEMS = 50
17
+ SESSION_RELATED_ACTIONS = ['sessions_index', 'session_show', 'schedule']
18
+
19
+ def proposals_or_sessions
20
+ if @event && @event.proposal_status_published?
21
+ redirect_to event_sessions_path(@event)
22
+ else
23
+ redirect_to event_proposals_path(@event)
24
+ end
25
+ end
26
+
27
+ # GET /proposals
28
+ # GET /proposals.xml
29
+ def index
30
+ warn_about_incomplete_event
31
+
32
+ @kind = :proposals
33
+
34
+ assign_prefetched_hashes
35
+ @proposals = Defer { @proposals_hash.values }
36
+
37
+ unless params[:sort]
38
+ params[:sort] = "submitted_at"
39
+ params[:dir] = "desc"
40
+ end
41
+
42
+ respond_to do |format|
43
+ format.html {
44
+ add_breadcrumb @event.title, event_proposals_path(@event)
45
+ }
46
+ format.xml {
47
+ render xml: @proposals
48
+ }
49
+ format.json {
50
+ render json: @proposals
51
+ }
52
+ format.atom {
53
+ # index.atom.builder
54
+ if @event_assignment == :assigned_to_param
55
+ @cache_key = "proposals_atom,event_#{@event.id}"
56
+ @proposals = Defer { @event.populated_proposals(:proposals).order("submitted_at desc").limit(MAX_FEED_ITEMS) }
57
+ else
58
+ @cache_key = "proposals_atom,all"
59
+ @proposals = Defer { Proposal.populated.order("submitted_at desc").limit(MAX_FEED_ITEMS) }
60
+ end
61
+ }
62
+ format.csv {
63
+ records = @event.populated_proposals(@kind).includes(:comments)
64
+ if admin?
65
+ render csv: records, style: :admin
66
+ else
67
+ if schedule_visible?
68
+ render csv: records, style: :schedule
69
+ else
70
+ render csv: records
71
+ end
72
+ end
73
+ }
74
+ end
75
+ end
76
+
77
+ def sessions_index
78
+ @kind = :sessions
79
+
80
+ assign_prefetched_hashes
81
+ @proposals = Defer { @sessions_hash.values }
82
+
83
+ params[:sort] ||= "track"
84
+
85
+ respond_to do |format|
86
+ format.html {
87
+ add_breadcrumb @event.title, event_proposals_path(@event)
88
+ render action: "index"
89
+ }
90
+ format.xml {
91
+ render xml: @proposals
92
+ }
93
+ format.json {
94
+ render json: @proposals
95
+ }
96
+ end
97
+ end
98
+
99
+ def sessions_index_terse
100
+ assign_prefetched_hashes
101
+ end
102
+
103
+ def schedule
104
+ page_title 'Schedule'
105
+
106
+ @schedule = Defer { Schedule.new(@event, admin?) }
107
+ assign_prefetched_hashes
108
+
109
+ respond_to do |format|
110
+ format.html {
111
+ @view_cache_key = "schedule,event_#{@event.id},admin_#{admin?}"
112
+ }
113
+ format.json {
114
+ render json: @schedule
115
+ }
116
+ format.xml {
117
+ ### render xml: @schedule
118
+ render xml: {error: "XML output of schedule not yet supported"}, status: :unprocessable_entity
119
+ }
120
+ format.ics {
121
+ view_cache_key = "schedule,event_#{@event.id}.ics"
122
+ data = Rails.cache.fetch(view_cache_key) {
123
+ Proposal.to_icalendar(
124
+ @schedule.items,
125
+ title: "#{@event.title}",
126
+ url_helper: lambda {|item| session_url(item)})
127
+ }
128
+ render text: data
129
+ }
130
+ end
131
+ end
132
+
133
+ def session_show
134
+ # @proposal and @event set via #assign_proposal_and_event filter
135
+ @kind = :session
136
+ unless @proposal.confirmed?
137
+ @redirector = lambda {
138
+ flash[:failure] = "This proposal is not a session."
139
+ return redirect_to( proposal_path(@proposal) )
140
+ }
141
+ end
142
+ return base_show
143
+ end
144
+
145
+ # GET /proposals/1
146
+ # GET /proposals/1.xml
147
+ def show
148
+ # @proposal and @event set via #assign_proposal_and_event filter
149
+ @kind = :proposal
150
+ if @event.proposal_status_published? && @proposal.confirmed?
151
+ @redirector = lambda {
152
+ # flash[:notice] = "This proposal has been accepted as a session."
153
+ flash.keep
154
+ return redirect_to( session_path(@proposal) )
155
+ }
156
+ end
157
+ return base_show
158
+ end
159
+
160
+ # GET /proposals/new
161
+ # GET /proposals/new.xml
162
+ def new
163
+ add_breadcrumb @event.title, event_proposals_path(@event)
164
+ add_breadcrumb "Create a proposal", new_event_proposal_path(@event)
165
+
166
+ @proposal = Proposal.new(agreement: false)
167
+
168
+ # Set default track if only one was found.
169
+ if event_tracks? && @event.tracks.size == 1
170
+ @proposal.track = @event.tracks.first
171
+ end
172
+
173
+ # Set default session_type if only one was found.
174
+ if event_session_types? && @event.session_types.size == 1
175
+ @proposal.session_type = @event.session_types.first
176
+ end
177
+
178
+ if logged_in?
179
+ @proposal.presenter = current_user.fullname
180
+ @proposal.add_user(current_user)
181
+ end
182
+ @proposal.email = current_email
183
+
184
+ respond_to do |format|
185
+ format.html # new.html.erb
186
+ format.xml { render xml: @proposal }
187
+ format.json { render json: @proposal }
188
+ end
189
+ end
190
+
191
+ # GET /proposals/1/edit
192
+ def edit
193
+ # @proposal set via #assign_proposal filter
194
+
195
+ @event = @proposal.event
196
+ add_breadcrumb @event.title, event_proposals_path(@event)
197
+ add_breadcrumb @proposal.title, proposal_path(@proposal)
198
+ end
199
+
200
+ # POST /proposals
201
+ # POST /proposals.xml
202
+ def create
203
+ @proposal = @event.proposals.new(proposal_params)
204
+ @proposal.add_user(current_user) if logged_in?
205
+ @proposal.transition = transition_from_params if admin?
206
+
207
+ manage_speakers_on_submit
208
+
209
+ respond_to do |format|
210
+ if params[:speaker_submit].blank? && params[:preview].nil? && @proposal.save
211
+ format.html {
212
+ # Display a page thanking users for submitting a proposal and telling them what to do next.
213
+ page_title "Thank You!"
214
+ }
215
+ format.xml { render xml: @proposal, status: :created, location: @proposal }
216
+ format.json { render json: @proposal, status: :created, location: @proposal }
217
+ else
218
+ @proposal.valid? if params[:preview]
219
+ format.html { render action: "new" }
220
+ format.xml { render xml: @proposal.errors, status: :unprocessable_entity }
221
+ format.json { render json: @proposal.errors, status: :unprocessable_entity }
222
+ end
223
+ end
224
+ end
225
+
226
+ # PUT /proposals/1
227
+ # PUT /proposals/1.xml
228
+ def update
229
+ # @proposal and @event set via #assign_proposal_and_event filter
230
+
231
+ # If proposal title editing is locked, prevent non-admin from modifying title.
232
+ if params[:proposal] && @event.proposal_titles_locked? && ! admin?
233
+ params[:proposal].delete(:title)
234
+ end
235
+
236
+ if params[:start_time] && admin?
237
+ if params[:start_time][:date].blank? || params[:start_time][:hour].blank? || params[:start_time][:minute].blank?
238
+ @proposal.start_time = nil
239
+ else
240
+ @proposal.start_time = "#{params[:start_time][:date]} #{params[:start_time][:hour]}:#{params[:start_time][:minute]}"
241
+ end
242
+ end
243
+
244
+ @proposal.assign_attributes(proposal_params)
245
+
246
+ add_breadcrumb @event.title, event_proposals_path(@event)
247
+ add_breadcrumb @proposal.title, proposal_path(@proposal)
248
+
249
+ manage_speakers_on_submit
250
+
251
+ respond_to do |format|
252
+ if params[:speaker_submit].blank? && params[:preview].nil? && @proposal.save
253
+ @proposal.transition = transition_from_params if admin?
254
+ format.html {
255
+ flash[:success] = 'Updated proposal.'
256
+ redirect_to(@proposal)
257
+ }
258
+ format.xml { head :ok }
259
+ format.json {
260
+ render(
261
+ json: {
262
+ proposal_status: @proposal.status,
263
+ _transition_control_html: render_to_string(partial: '/proposals/transition_control')
264
+ },
265
+ status: :ok
266
+ )
267
+ }
268
+ else
269
+ @proposal.valid? if params[:preview]
270
+
271
+ format.html { render action: "edit" }
272
+ format.xml { render xml: @proposal.errors, status: :unprocessable_entity }
273
+ format.json { render json: @proposal.errors, status: :unprocessable_entity }
274
+ end
275
+ end
276
+ end
277
+
278
+ # DELETE /proposals/1
279
+ # DELETE /proposals/1.xml
280
+ def destroy
281
+ # @proposal and @event set via #assign_proposal_and_event filter
282
+
283
+ @proposal.destroy
284
+ flash[:success] = "Destroyed proposal: #{@proposal.title}"
285
+
286
+ respond_to do |format|
287
+ format.html { redirect_to(event_proposals_path(@proposal.event)) }
288
+ format.xml { head :ok }
289
+ format.json { head :ok }
290
+ end
291
+ end
292
+
293
+ def manage_speakers
294
+ @proposal = get_proposal_for_speaker_manager(params[:id], params[:speakers])
295
+
296
+ if params[:add]
297
+ user = User.find(params[:add])
298
+ @proposal.add_user(user)
299
+ elsif params[:remove]
300
+ user = User.find(params[:remove])
301
+ @proposal.remove_user(user)
302
+ end
303
+
304
+ respond_to do |format|
305
+ format.html { render partial: "manage_speakers", layout: false }
306
+ end
307
+ end
308
+
309
+ def search_speakers
310
+ @proposal = get_proposal_for_speaker_manager(params[:id], params[:speakers])
311
+ @matches = get_speaker_matches(params[:search])
312
+
313
+ respond_to do |format|
314
+ format.html { render partial: "search_speakers", layout: false }
315
+ end
316
+ end
317
+
318
+ def stats
319
+ # Uses @event
320
+ end
321
+
322
+ # GET /proposals/1/login
323
+ def proposal_login_required
324
+ return redirect_to(proposal_path(params[:proposal_id]))
325
+ end
326
+
327
+ def speaker_confirm
328
+ # @proposal and @event set via #assign_proposal_and_event filter
329
+ if current_user_is_proposal_speaker? and @proposal.confirm!
330
+ flash[:success] = 'Updated proposal. Thank you for confirming!'
331
+ end
332
+ redirect_to(@proposal)
333
+ end
334
+
335
+ def speaker_decline
336
+ # @proposal and @event set via #assign_proposal_and_event filter
337
+ if current_user_is_proposal_speaker? and @proposal.decline!
338
+ flash[:success] = 'Updated proposal.'
339
+ end
340
+ redirect_to(@proposal)
341
+ end
342
+
343
+ protected
344
+
345
+ def proposal_params
346
+ permitted = [
347
+ :presenter,
348
+ :affiliation,
349
+ :email,
350
+ :website,
351
+ :biography,
352
+ :title,
353
+ :description,
354
+ :excerpt,
355
+ :agreement,
356
+ :note_to_organizers,
357
+ :track_id,
358
+ :session_type_id,
359
+ :speaking_experience,
360
+ :audience_level]
361
+
362
+ permitted += [:status, :room_id, :start_time, :audio_url] if admin?
363
+
364
+ params.require(:proposal).permit(permitted)
365
+ end
366
+
367
+ # Is this event accepting proposals? If not, redirect with a warning.
368
+ def assert_accepting_proposals
369
+ unless accepting_proposals? || admin?
370
+ flash[:failure] = Snippet.content_for(:proposals_not_accepted_error)
371
+ redirect_to @event ? event_proposals_path(@event) : proposals_path
372
+ end
373
+ end
374
+
375
+ # Ensure that anonymous users are allowed to add proposals
376
+ def assert_anonymous_proposals
377
+ if logged_in?
378
+ return false # Logged in users can always create
379
+ else
380
+ if anonymous_proposals?
381
+ return false # Anonymous proposals are allowed
382
+ else
383
+ flash[:notice] = "Please sign in so you can create and manage proposals."
384
+ store_location
385
+ return redirect_to(sign_in_path)
386
+ end
387
+ end
388
+ end
389
+
390
+ # Return the proposal and its assignment status for this request. The status
391
+ # can be:
392
+ # * :assigned_via_param
393
+ # * :invalid_proposal
394
+ # * :invalid_event
395
+ def get_proposal_and_assignment_status
396
+ if proposal = Proposal.lookup(params[:id].to_i) rescue nil
397
+ if proposal.event
398
+ return [proposal, :assigned_via_param]
399
+ else
400
+ return [proposal, :invalid_event]
401
+ end
402
+ else
403
+ return [proposal, :invalid_proposal]
404
+ end
405
+ end
406
+
407
+ def get_proposal_for_speaker_manager(proposal_id, speaker_ids_string)
408
+ if proposal_id.blank? || proposal_id == "new_record"
409
+ proposal = Proposal.new
410
+ speaker_ids_string.split(',').each do |speaker|
411
+ proposal.add_user(speaker)
412
+ end
413
+ else
414
+ proposal = Proposal.find(proposal_id)
415
+ end
416
+ return proposal
417
+ end
418
+
419
+ # Assign @proposal and @event from parameters, or redirect with warnings.
420
+ def assign_proposal_and_event
421
+ @proposal, @proposal_assignment_status = get_proposal_and_assignment_status()
422
+ case @proposal_assignment_status
423
+ when :assigned_via_param
424
+ @event = @proposal.event
425
+ return false # Successfully found both @event and @proposal
426
+ when :invalid_proposal
427
+ flash[:failure] = "Sorry, that presentation proposal doesn't exist or has been deleted."
428
+ return redirect_to(action: :index)
429
+ when :invalid_event
430
+ flash[:failure] = "Sorry, no event was associated with proposal ##{@proposal.id}"
431
+ return redirect_to(action: :index)
432
+ end
433
+ end
434
+
435
+ def assert_user_complete_profile
436
+ if user_profiles? and logged_in? and not current_user.complete_profile?
437
+ current_user.complete_profile = true
438
+ if current_user.valid?
439
+ current_user.save
440
+ else
441
+ flash[:notice] = "Please complete your profile before creating a proposal."
442
+ store_location
443
+ return redirect_to(edit_user_path(current_user, require_complete_profile: true))
444
+ end
445
+ end
446
+ end
447
+
448
+ def assign_proposals_breadcrumb
449
+ add_breadcrumb "Proposals", proposals_path
450
+ end
451
+
452
+ def manage_speakers_on_submit
453
+ if params[:speaker_ids].present?
454
+ speakers = params[:speaker_ids].map(&:first)
455
+ unless speakers.blank?
456
+ speakers.each do |speaker|
457
+ @proposal.add_user(speaker)
458
+ end
459
+ end
460
+ end
461
+ end
462
+
463
+ # Return the name of a transition (e.g., "accept") from a Proposal's params.
464
+ def transition_from_params
465
+ return params[:proposal].present? ? params[:proposal][:transition] : nil
466
+ end
467
+
468
+ # Return a sanitized Regexp for matching a speaker by name from the +query+ string.
469
+ def get_speaker_matcher(query)
470
+ string = query.gsub(/[[:punct:]]/, ' ').gsub(/\s{2,}/, ' ').strip
471
+ return Regexp.new(Regexp.escape(string), Regexp::IGNORECASE)
472
+ end
473
+
474
+ # Return an array of speakers (User records) matching the +query+ string.
475
+ def get_speaker_matches(query)
476
+ if query.blank? || ! query.match(/\w+/)
477
+ return []
478
+ else
479
+ matcher = get_speaker_matcher(query)
480
+ return(User.complete_profiles.select{|u| u.fullname.try(:match, matcher)} - @proposal.users)
481
+ end
482
+ end
483
+
484
+ # Base method used for #show and #session_show
485
+ def base_show
486
+ if selector? && @event.accept_selector_votes?
487
+ @selector_vote = @proposal.selector_votes.find_or_initialize_by(user_id: current_user.id)
488
+ end
489
+
490
+ unless defined?(@redirector)
491
+ add_breadcrumb @event.title, event_proposals_path(@event)
492
+ add_breadcrumb @proposal.title, proposal_path(@proposal)
493
+
494
+ @profile = @proposal.profile
495
+ @comment = @proposal.comments.new(email: current_email)
496
+ @display_comment_form = \
497
+ # Admin can always leave comments
498
+ admin? || (
499
+ # Display comment form if the event is accepting proposals
500
+ accepting_proposals? ||
501
+ # or if the settings provide a toggle and the event is accepting comments
502
+ (event_proposal_comments_after_deadline? && @event.accept_proposal_comments_after_deadline?)
503
+ )
504
+ @focus_comment = false
505
+ end
506
+
507
+ respond_to do |format|
508
+ format.html {
509
+ if defined?(@redirector)
510
+ @redirector.call
511
+ else
512
+ render template: "open_conference_ware/proposals/show"
513
+ end
514
+ }
515
+ format.xml { render xml: @proposal }
516
+ format.json { render json: @proposal }
517
+ end
518
+ end
519
+
520
+ end
521
+ end