calagator 0.0.1.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 (384) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +23 -0
  3. data/README.md +75 -0
  4. data/Rakefile +12 -0
  5. data/app/assets/images/confused-alligator-sm.png +0 -0
  6. data/app/assets/images/disk.png +0 -0
  7. data/app/assets/images/edit.png +0 -0
  8. data/app/assets/images/external_sites/epdx.png +0 -0
  9. data/app/assets/images/external_sites/external.gif +0 -0
  10. data/app/assets/images/external_sites/facebook.png +0 -0
  11. data/app/assets/images/external_sites/foursquare.png +0 -0
  12. data/app/assets/images/external_sites/gowalla.png +0 -0
  13. data/app/assets/images/external_sites/lanyrd.png +0 -0
  14. data/app/assets/images/external_sites/meetup.png +0 -0
  15. data/app/assets/images/external_sites/plancast.png +0 -0
  16. data/app/assets/images/external_sites/shizzow.png +0 -0
  17. data/app/assets/images/external_sites/upcoming.png +0 -0
  18. data/app/assets/images/external_sites/yelp.png +0 -0
  19. data/app/assets/images/feed.png +0 -0
  20. data/app/assets/images/heart.png +0 -0
  21. data/app/assets/images/icon_ical.gif +0 -0
  22. data/app/assets/images/information.png +0 -0
  23. data/app/assets/images/nav_marker.gif +0 -0
  24. data/app/assets/images/nav_marker.png +0 -0
  25. data/app/assets/images/plus.png +0 -0
  26. data/app/assets/images/redx.png +0 -0
  27. data/app/assets/images/site-icon.png +0 -0
  28. data/app/assets/images/spinner.gif +0 -0
  29. data/app/assets/images/star.png +0 -0
  30. data/app/assets/images/subnav_marker.gif +0 -0
  31. data/app/assets/images/subnav_marker.png +0 -0
  32. data/app/assets/images/tag_blue.png +0 -0
  33. data/app/assets/images/tag_icons/angular.png +0 -0
  34. data/app/assets/images/tag_icons/beer.png +0 -0
  35. data/app/assets/images/tag_icons/bitcoin.png +0 -0
  36. data/app/assets/images/tag_icons/free.png +0 -0
  37. data/app/assets/images/tag_icons/golang.png +0 -0
  38. data/app/assets/images/tag_icons/html.png +0 -0
  39. data/app/assets/images/tag_icons/javascript.png +0 -0
  40. data/app/assets/images/tag_icons/linux.png +0 -0
  41. data/app/assets/images/tag_icons/php.png +0 -0
  42. data/app/assets/images/tag_icons/pizza.png +0 -0
  43. data/app/assets/images/tag_icons/python.png +0 -0
  44. data/app/assets/images/tag_icons/rails.png +0 -0
  45. data/app/assets/images/tag_icons/ruby.png +0 -0
  46. data/app/assets/images/tag_icons/sass.png +0 -0
  47. data/app/assets/images/tag_icons/swift.png +0 -0
  48. data/app/assets/images/transmit_blue.png +0 -0
  49. data/app/assets/images/weekday_background.gif +0 -0
  50. data/app/assets/javascripts/calagator.js +18 -0
  51. data/app/assets/javascripts/calagator/forms.js +60 -0
  52. data/app/assets/stylesheets/calagator.scss +8 -0
  53. data/app/assets/stylesheets/calagator/common.scss +14 -0
  54. data/app/assets/stylesheets/calagator/datepicker.scss +177 -0
  55. data/app/assets/stylesheets/calagator/errors.css +110 -0
  56. data/app/assets/stylesheets/calagator/forms.scss +4 -0
  57. data/app/assets/stylesheets/calagator/reset.css +40 -0
  58. data/app/assets/stylesheets/calagator/theme.css +0 -0
  59. data/app/controllers/calagator/admin_controller.rb +27 -0
  60. data/app/controllers/calagator/application_controller.rb +82 -0
  61. data/app/controllers/calagator/events_controller.rb +171 -0
  62. data/app/controllers/calagator/site_controller.rb +35 -0
  63. data/app/controllers/calagator/sources_controller.rb +94 -0
  64. data/app/controllers/calagator/venues_controller.rb +133 -0
  65. data/app/controllers/calagator/versions_controller.rb +20 -0
  66. data/app/helpers/calagator/application_helper.rb +128 -0
  67. data/app/helpers/calagator/events_helper.rb +184 -0
  68. data/app/helpers/calagator/google_event_export_helper.rb +67 -0
  69. data/app/helpers/calagator/mapping_helper.rb +103 -0
  70. data/app/helpers/calagator/sources_helper.rb +10 -0
  71. data/app/helpers/calagator/tags_helper.rb +42 -0
  72. data/app/helpers/calagator/time_range_helper.rb +166 -0
  73. data/app/models/calagator/event.rb +246 -0
  74. data/app/models/calagator/event/cloner.rb +39 -0
  75. data/app/models/calagator/event/ical_renderer.rb +155 -0
  76. data/app/models/calagator/event/overview.rb +45 -0
  77. data/app/models/calagator/event/saver.rb +58 -0
  78. data/app/models/calagator/event/search.rb +72 -0
  79. data/app/models/calagator/event/search_engine.rb +28 -0
  80. data/app/models/calagator/event/search_engine/apache_sunspot.rb +106 -0
  81. data/app/models/calagator/event/search_engine/sql.rb +107 -0
  82. data/app/models/calagator/source.rb +115 -0
  83. data/app/models/calagator/source/importer.rb +46 -0
  84. data/app/models/calagator/source/parser.rb +128 -0
  85. data/app/models/calagator/source/parser/facebook.rb +67 -0
  86. data/app/models/calagator/source/parser/hcal.rb +108 -0
  87. data/app/models/calagator/source/parser/http_authentication_required_error.rb +6 -0
  88. data/app/models/calagator/source/parser/ical.rb +186 -0
  89. data/app/models/calagator/source/parser/meetup.rb +72 -0
  90. data/app/models/calagator/source/parser/not_found.rb +9 -0
  91. data/app/models/calagator/source/parser/plancast.rb +59 -0
  92. data/app/models/calagator/venue.rb +161 -0
  93. data/app/models/calagator/venue/geocoder.rb +51 -0
  94. data/app/models/calagator/venue/search.rb +63 -0
  95. data/app/models/calagator/venue/search_engine.rb +24 -0
  96. data/app/models/calagator/venue/search_engine/apache_sunspot.rb +85 -0
  97. data/app/models/calagator/venue/search_engine/sql.rb +68 -0
  98. data/app/models/event/search_engine/base.rb +0 -0
  99. data/app/observers/calagator/cache_observer.rb +37 -0
  100. data/app/views/calagator/admin/events.html.erb +28 -0
  101. data/app/views/calagator/admin/index.html.erb +8 -0
  102. data/app/views/calagator/events/_feed_item.html.erb +62 -0
  103. data/app/views/calagator/events/_form.html.erb +63 -0
  104. data/app/views/calagator/events/_gcal_reminder.html.erb +1 -0
  105. data/app/views/calagator/events/_hcal.html.erb +41 -0
  106. data/app/views/calagator/events/_item.html.erb +120 -0
  107. data/app/views/calagator/events/_list.html.erb +30 -0
  108. data/app/views/calagator/events/_list_item.html.erb +37 -0
  109. data/app/views/calagator/events/_search_section.html.erb +15 -0
  110. data/app/views/calagator/events/_subnav.html.erb +13 -0
  111. data/app/views/calagator/events/_table.html.erb +74 -0
  112. data/app/views/calagator/events/duplicates.html.erb +58 -0
  113. data/app/views/calagator/events/edit.html.erb +3 -0
  114. data/app/views/calagator/events/index.atom.builder +32 -0
  115. data/app/views/calagator/events/index.html.erb +51 -0
  116. data/app/views/calagator/events/index.kml.erb +20 -0
  117. data/app/views/calagator/events/new.html.erb +7 -0
  118. data/app/views/calagator/events/search.html.erb +25 -0
  119. data/app/views/calagator/events/show.html.erb +81 -0
  120. data/app/views/calagator/site/_appropriateness_message.html.erb +15 -0
  121. data/app/views/calagator/site/_description.html.erb +3 -0
  122. data/app/views/calagator/site/about.html.erb +7 -0
  123. data/app/views/calagator/site/defunct.html.erb +15 -0
  124. data/app/views/calagator/site/export.html.erb +4 -0
  125. data/app/views/calagator/site/index.html.erb +40 -0
  126. data/app/views/calagator/site/opensearch.xml.builder +8 -0
  127. data/app/views/calagator/sources/_subnav.html.erb +0 -0
  128. data/app/views/calagator/sources/edit.html.erb +12 -0
  129. data/app/views/calagator/sources/import.html.erb +10 -0
  130. data/app/views/calagator/sources/index.html.erb +22 -0
  131. data/app/views/calagator/sources/new.html.erb +32 -0
  132. data/app/views/calagator/sources/show.html.erb +16 -0
  133. data/app/views/calagator/venues/_form.html.erb +57 -0
  134. data/app/views/calagator/venues/_subnav.html.erb +10 -0
  135. data/app/views/calagator/venues/duplicates.html.erb +65 -0
  136. data/app/views/calagator/venues/edit.html.erb +3 -0
  137. data/app/views/calagator/venues/index.html.erb +93 -0
  138. data/app/views/calagator/venues/index.kml.erb +15 -0
  139. data/app/views/calagator/venues/map.html.erb +4 -0
  140. data/app/views/calagator/venues/new.html.erb +5 -0
  141. data/app/views/calagator/venues/show.html.erb +113 -0
  142. data/app/views/calagator/versions/_chooser.html.erb +28 -0
  143. data/app/views/calagator/versions/_edit_with_chooser.html.erb +16 -0
  144. data/app/views/layouts/calagator/application.html.erb +110 -0
  145. data/config/deploy/local.rb +37 -0
  146. data/config/deploy/lucca.rb +33 -0
  147. data/config/initializers/dates.rb +7 -0
  148. data/config/initializers/formtastic.rb +82 -0
  149. data/config/initializers/geokit.rb +74 -0
  150. data/config/initializers/ics_renderer.rb +6 -0
  151. data/config/initializers/load_tag_model_extensions.rb +3 -0
  152. data/config/initializers/mime_types.rb +9 -0
  153. data/config/initializers/observers.rb +1 -0
  154. data/config/initializers/search_engine.rb +4 -0
  155. data/config/initializers/set_default_url_host.rb +5 -0
  156. data/config/initializers/time_get_zone.rb +8 -0
  157. data/config/locales/en.yml +5 -0
  158. data/config/routes.rb +55 -0
  159. data/config/secrets.yml.blag +75 -0
  160. data/config/sunspot.yml +23 -0
  161. data/db/development.sqlite3 +0 -0
  162. data/db/development.sqlite3.bak +0 -0
  163. data/db/development.sqlite3.old +0 -0
  164. data/db/development~20111112@110950.sqlite3 +0 -0
  165. data/db/migrate/001_create_events.rb +17 -0
  166. data/db/migrate/002_create_venues.rb +17 -0
  167. data/db/migrate/003_create_sources.rb +16 -0
  168. data/db/migrate/004_add_detailed_fields_to_venue.rb +19 -0
  169. data/db/migrate/005_add_end_time_to_events.rb +9 -0
  170. data/db/migrate/006_add_source_id_to_events.rb +9 -0
  171. data/db/migrate/008_add_source_id_to_venues.rb +10 -0
  172. data/db/migrate/009_add_duplicate_of_column_to_venues.rb +9 -0
  173. data/db/migrate/010_add_duplicate_of_column_to_events.rb +9 -0
  174. data/db/migrate/011_change_lat_long_type.rb +12 -0
  175. data/db/migrate/012_add_source_reimport.rb +9 -0
  176. data/db/migrate/013_change_end_time_to_duration.rb +11 -0
  177. data/db/migrate/014_remove_format_type_from_source.rb +9 -0
  178. data/db/migrate/015_create_updates.rb +15 -0
  179. data/db/migrate/016_remove_next_update_from_source.rb +9 -0
  180. data/db/migrate/20080705163959_change_duration_to_end_time.rb +11 -0
  181. data/db/migrate/20080705164959_create_tags_and_taggings.rb +28 -0
  182. data/db/migrate/20081011181519_create_versioned_events.rb +25 -0
  183. data/db/migrate/20081011193124_create_versioned_venues.rb +32 -0
  184. data/db/migrate/20081115190515_add_rrule_to_events.rb +15 -0
  185. data/db/migrate/20090912082129_create_versions.rb +18 -0
  186. data/db/migrate/20110219205156_add_closed_flag_to_venues.rb +9 -0
  187. data/db/migrate/20110220001008_add_wifi_flag_to_venues.rb +9 -0
  188. data/db/migrate/20110220011427_add_access_notes_to_venues.rb +9 -0
  189. data/db/migrate/20110220031117_add_events_count_to_venues.rb +8 -0
  190. data/db/migrate/20110604174521_add_venue_details_to_events.rb +9 -0
  191. data/db/migrate/20110717231316_acts_as_taggable_on_migration.rb +50 -0
  192. data/db/migrate/20120709092821_cleanup.rb +14 -0
  193. data/db/migrate/20120831234448_specify_venues_latitude_and_longitude_precision.rb +11 -0
  194. data/db/migrate/20150206085809_remove_updates.rb +13 -0
  195. data/db/migrate/20150207231355_add_locked_status_to_events.rb +5 -0
  196. data/db/production.sqlite3 +0 -0
  197. data/db/schema.rb +102 -0
  198. data/db/seeds.rb +16 -0
  199. data/db/test.sqlite3 +0 -0
  200. data/db/test2.sqlite3 +0 -0
  201. data/lib/calagator.rb +30 -0
  202. data/lib/calagator/blacklist_validator.rb +69 -0
  203. data/lib/calagator/decode_html_entities_hack.rb +33 -0
  204. data/lib/calagator/duplicate_checking.rb +133 -0
  205. data/lib/calagator/duplicate_checking/controller_actions.rb +38 -0
  206. data/lib/calagator/duplicate_checking/duplicate_finder.rb +83 -0
  207. data/lib/calagator/duplicate_checking/duplicate_squasher.rb +74 -0
  208. data/lib/calagator/engine.rb +30 -0
  209. data/lib/calagator/strip_whitespace.rb +19 -0
  210. data/lib/calagator/tag_model_extensions.rb +104 -0
  211. data/lib/calagator/url_prefixer.rb +9 -0
  212. data/lib/calagator/version.rb +3 -0
  213. data/lib/generators/calagator/install_generator.rb +39 -0
  214. data/lib/generators/calagator/templates/config/calagator.rb +26 -0
  215. data/lib/generators/calagator/templates/config/secrets.yml.sample +83 -0
  216. data/lib/secrets_reader.rb +76 -0
  217. data/lib/tasks/spec_db.rake +53 -0
  218. data/lib/tasks/sunspot_reindex_calagator.rake +6 -0
  219. data/lib/tasks/sunspot_solr_restart_enhancements.rake +19 -0
  220. data/lib/tasks/update_counter_caches.rake +13 -0
  221. data/lib/templates/erb/scaffold/_form.html.erb +11 -0
  222. data/lib/theme_reader.rb +17 -0
  223. data/lib/wait_for_solr.rb +25 -0
  224. data/spec/controllers/calagator/application_controller_spec.rb +47 -0
  225. data/spec/controllers/calagator/events_controller_spec.rb +794 -0
  226. data/spec/controllers/calagator/site_controller_spec.rb +59 -0
  227. data/spec/controllers/calagator/sources_controller_spec.rb +439 -0
  228. data/spec/controllers/calagator/venues_controller_spec.rb +319 -0
  229. data/spec/controllers/calagator/versions_controller_spec.rb +82 -0
  230. data/spec/controllers/squash_many_duplicates_examples.rb +49 -0
  231. data/spec/dummy/Gemfile +39 -0
  232. data/spec/dummy/Gemfile.lock +195 -0
  233. data/spec/dummy/README.rdoc +261 -0
  234. data/spec/dummy/Rakefile +7 -0
  235. data/spec/dummy/app/assets/images/rails.png +0 -0
  236. data/spec/dummy/app/assets/javascripts/application.js +16 -0
  237. data/spec/dummy/app/assets/stylesheets/application.css +14 -0
  238. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  239. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  240. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  241. data/spec/dummy/config.ru +4 -0
  242. data/spec/dummy/config/application.rb +62 -0
  243. data/spec/dummy/config/boot.rb +6 -0
  244. data/spec/dummy/config/database.yml +25 -0
  245. data/spec/dummy/config/environment.rb +5 -0
  246. data/spec/dummy/config/environments/development.rb +37 -0
  247. data/spec/dummy/config/environments/production.rb +67 -0
  248. data/spec/dummy/config/environments/test.rb +37 -0
  249. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  250. data/spec/dummy/config/initializers/calagator.rb +26 -0
  251. data/spec/dummy/config/initializers/inflections.rb +15 -0
  252. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  253. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  254. data/spec/dummy/config/initializers/session_store.rb +8 -0
  255. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  256. data/spec/dummy/config/locales/en.yml +5 -0
  257. data/spec/dummy/config/routes.rb +59 -0
  258. data/spec/dummy/config/secrets.yml +83 -0
  259. data/spec/dummy/db/development.sqlite3 +0 -0
  260. data/spec/dummy/db/migrate/20150309023304_create_events.calagator.rb +18 -0
  261. data/spec/dummy/db/migrate/20150309023305_create_venues.calagator.rb +18 -0
  262. data/spec/dummy/db/migrate/20150309023306_create_sources.calagator.rb +17 -0
  263. data/spec/dummy/db/migrate/20150309023307_add_detailed_fields_to_venue.calagator.rb +20 -0
  264. data/spec/dummy/db/migrate/20150309023308_add_end_time_to_events.calagator.rb +10 -0
  265. data/spec/dummy/db/migrate/20150309023309_add_source_id_to_events.calagator.rb +10 -0
  266. data/spec/dummy/db/migrate/20150309023310_add_source_id_to_venues.calagator.rb +11 -0
  267. data/spec/dummy/db/migrate/20150309023311_add_duplicate_of_column_to_venues.calagator.rb +10 -0
  268. data/spec/dummy/db/migrate/20150309023312_add_duplicate_of_column_to_events.calagator.rb +10 -0
  269. data/spec/dummy/db/migrate/20150309023313_change_lat_long_type.calagator.rb +13 -0
  270. data/spec/dummy/db/migrate/20150309023314_add_source_reimport.calagator.rb +10 -0
  271. data/spec/dummy/db/migrate/20150309023315_change_end_time_to_duration.calagator.rb +12 -0
  272. data/spec/dummy/db/migrate/20150309023316_remove_format_type_from_source.calagator.rb +10 -0
  273. data/spec/dummy/db/migrate/20150309023317_create_updates.calagator.rb +16 -0
  274. data/spec/dummy/db/migrate/20150309023318_remove_next_update_from_source.calagator.rb +10 -0
  275. data/spec/dummy/db/migrate/20150309023319_change_duration_to_end_time.calagator.rb +12 -0
  276. data/spec/dummy/db/migrate/20150309023320_create_tags_and_taggings.calagator.rb +29 -0
  277. data/spec/dummy/db/migrate/20150309023321_create_versioned_events.calagator.rb +26 -0
  278. data/spec/dummy/db/migrate/20150309023322_create_versioned_venues.calagator.rb +33 -0
  279. data/spec/dummy/db/migrate/20150309023323_add_rrule_to_events.calagator.rb +16 -0
  280. data/spec/dummy/db/migrate/20150309023324_create_versions.calagator.rb +19 -0
  281. data/spec/dummy/db/migrate/20150309023325_add_closed_flag_to_venues.calagator.rb +10 -0
  282. data/spec/dummy/db/migrate/20150309023326_add_wifi_flag_to_venues.calagator.rb +10 -0
  283. data/spec/dummy/db/migrate/20150309023327_add_access_notes_to_venues.calagator.rb +10 -0
  284. data/spec/dummy/db/migrate/20150309023328_add_events_count_to_venues.calagator.rb +9 -0
  285. data/spec/dummy/db/migrate/20150309023329_add_venue_details_to_events.calagator.rb +10 -0
  286. data/spec/dummy/db/migrate/20150309023330_acts_as_taggable_on_migration.calagator.rb +51 -0
  287. data/spec/dummy/db/migrate/20150309023331_cleanup.calagator.rb +15 -0
  288. data/spec/dummy/db/migrate/20150309023332_specify_venues_latitude_and_longitude_precision.calagator.rb +12 -0
  289. data/spec/dummy/db/migrate/20150309023333_remove_updates.calagator.rb +14 -0
  290. data/spec/dummy/db/migrate/20150309023334_add_locked_status_to_events.calagator.rb +6 -0
  291. data/spec/dummy/db/schema.rb +95 -0
  292. data/spec/dummy/db/seeds.rb +7 -0
  293. data/spec/dummy/db/test.sqlite3 +0 -0
  294. data/spec/dummy/doc/README_FOR_APP +2 -0
  295. data/spec/dummy/log/development.log +273 -0
  296. data/spec/dummy/public/404.html +26 -0
  297. data/spec/dummy/public/422.html +26 -0
  298. data/spec/dummy/public/500.html +25 -0
  299. data/spec/dummy/public/favicon.ico +0 -0
  300. data/spec/dummy/public/robots.txt +5 -0
  301. data/spec/dummy/script/rails +6 -0
  302. data/spec/dummy/test/performance/browsing_test.rb +12 -0
  303. data/spec/dummy/test/test_helper.rb +13 -0
  304. data/spec/factories.rb +93 -0
  305. data/spec/features/add_event_spec.rb +99 -0
  306. data/spec/features/add_venue_spec.rb +34 -0
  307. data/spec/features/admin_auth_spec.rb +22 -0
  308. data/spec/features/admin_lock_event_spec.rb +41 -0
  309. data/spec/features/import_events_from_feed_spec.rb +43 -0
  310. data/spec/features/managing_event_spec.rb +111 -0
  311. data/spec/features/managing_venue_spec.rb +71 -0
  312. data/spec/features/search_event_spec.rb +27 -0
  313. data/spec/helpers/calagator/application_helper_spec.rb +82 -0
  314. data/spec/helpers/calagator/events_helper_spec.rb +172 -0
  315. data/spec/helpers/calagator/google_event_export_helper_spec.rb +70 -0
  316. data/spec/helpers/calagator/sources_helper_spec.rb +12 -0
  317. data/spec/helpers/calagator/tags_helper_spec.rb +85 -0
  318. data/spec/helpers/calagator/time_range_helper_spec.rb +59 -0
  319. data/spec/lib/calagator/blacklist_validator_spec.rb +65 -0
  320. data/spec/lib/calagator/decode_html_entities_hack_spec.rb +54 -0
  321. data/spec/lib/calagator/settings_spec.rb +20 -0
  322. data/spec/lib/calagator/url_prefixer_spec.rb +33 -0
  323. data/spec/lib/secrets_reader_spec.rb +65 -0
  324. data/spec/models/calagator/event/cloner_spec.rb +43 -0
  325. data/spec/models/calagator/event/overview_spec.rb +79 -0
  326. data/spec/models/calagator/event/search_spec.rb +103 -0
  327. data/spec/models/calagator/event_search_spec.rb +149 -0
  328. data/spec/models/calagator/event_spec.rb +859 -0
  329. data/spec/models/calagator/source/parser_facebook_spec.rb +73 -0
  330. data/spec/models/calagator/source/parser_hcal_spec.rb +69 -0
  331. data/spec/models/calagator/source/parser_ical_non_standard_spec.rb +91 -0
  332. data/spec/models/calagator/source/parser_ical_spec.rb +322 -0
  333. data/spec/models/calagator/source/parser_meetup_spec.rb +69 -0
  334. data/spec/models/calagator/source/parser_plancast_spec.rb +53 -0
  335. data/spec/models/calagator/source/parser_spec.rb +238 -0
  336. data/spec/models/calagator/source_spec.rb +135 -0
  337. data/spec/models/calagator/venue/search_spec.rb +92 -0
  338. data/spec/models/calagator/venue_search_spec.rb +124 -0
  339. data/spec/models/calagator/venue_spec.rb +346 -0
  340. data/spec/models/tag_spec.rb +35 -0
  341. data/spec/rails_helper.rb +39 -0
  342. data/spec/spec_helper.rb +140 -0
  343. data/spec/support/disable_geocoding.rb +1 -0
  344. data/spec/support/http_samples.rb +5 -0
  345. data/spec/support/samples/facebook.json +23 -0
  346. data/spec/support/samples/hcal_basic.xml +6 -0
  347. data/spec/support/samples/hcal_dup_event_dup_venue.xml +13 -0
  348. data/spec/support/samples/hcal_event_duplicates_fixture.xml +13 -0
  349. data/spec/support/samples/hcal_event_wo_lat_and_long.xml +14 -0
  350. data/spec/support/samples/hcal_multiple.xml +16 -0
  351. data/spec/support/samples/hcal_same_event_twice_with_different_venues.xml +12 -0
  352. data/spec/support/samples/hcal_single.xml +8 -0
  353. data/spec/support/samples/hcal_two_identical_events.xml +14 -0
  354. data/spec/support/samples/hcal_upcoming_v1.html +412 -0
  355. data/spec/support/samples/hcal_upcoming_v2.html +749 -0
  356. data/spec/support/samples/hcal_upcoming_v3.html +685 -0
  357. data/spec/support/samples/hcal_upcoming_v4.html +761 -0
  358. data/spec/support/samples/ical_apple.ics +22 -0
  359. data/spec/support/samples/ical_apple_v3.ics +37 -0
  360. data/spec/support/samples/ical_basic.ics +15 -0
  361. data/spec/support/samples/ical_basic_with_duration.ics +16 -0
  362. data/spec/support/samples/ical_event_with_squashed_venue.ics +12 -0
  363. data/spec/support/samples/ical_eventful_many.ics +504 -0
  364. data/spec/support/samples/ical_gmt.ics +12 -0
  365. data/spec/support/samples/ical_google.ics +786 -0
  366. data/spec/support/samples/ical_multiple_calendars.ics +111 -0
  367. data/spec/support/samples/ical_upcoming.ics +36 -0
  368. data/spec/support/samples/ical_upcoming_many.ics +682 -0
  369. data/spec/support/samples/ical_upcoming_v2.ics +43 -0
  370. data/spec/support/samples/ical_z.ics +10 -0
  371. data/spec/support/samples/meetup.ics +16 -0
  372. data/spec/support/samples/meetup.json +31 -0
  373. data/spec/support/samples/plancast.ics +59 -0
  374. data/spec/support/samples/plancast.json +51 -0
  375. data/spec/support/samples/plancast_with_missing_venue.json +39 -0
  376. data/spec/support/samples/upcoming_v1.xml +8 -0
  377. data/spec/support/samples/upcoming_v2_with_invalid_utc_dates.xml +8 -0
  378. data/spec/support/time_convenience_methods.rb +8 -0
  379. data/spec/support/time_zones.rb +12 -0
  380. data/spec/support/url_helpers.rb +5 -0
  381. data/spec/support/wait_for_ajax.rb +15 -0
  382. data/spec/support/webmock.rb +8 -0
  383. data/spec/travis_spec.rb +7 -0
  384. metadata +1194 -0
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ module Calagator
4
+
5
+ describe Source::Parser::Facebook, :type => :model do
6
+
7
+ describe "when importing an event" do
8
+ before(:each) do
9
+ url = 'http://facebook.com/event.php?eid=247619485255249'
10
+ graph_url = "http://graph.facebook.com/247619485255249"
11
+ stub_request(:get, graph_url).to_return(body: read_sample('facebook.json'), headers: { content_type: "application/json" })
12
+ @events = Source::Parser::Facebook.to_events(url: url)
13
+ @event = @events.first
14
+ end
15
+
16
+ it "should find one event" do
17
+ expect(@events.size).to eq 1
18
+ end
19
+
20
+ it "should set event details" do
21
+ expect(@event.title).to eq "Open Source Bridge 2012"
22
+ time = Time.zone.parse("26 Jun 2012 09:00:00")
23
+ expect(@event.start_time).to eq time
24
+ end
25
+
26
+ it "should tag Facebook events with automagic machine tags" do
27
+ expect(@event.tag_list).to eq ["facebook:event=247619485255249"]
28
+ end
29
+
30
+ it "should set the event url to the original import URL" do
31
+ expect(@event.url).to eq 'http://facebook.com/event.php?eid=247619485255249'
32
+ end
33
+
34
+ it "should populate a venue when structured data is provided" do
35
+ expect(@event.venue.title).to eq "Eliot Center"
36
+ expect(@event.venue.street_address).to eq "1226 SW Salmon Street"
37
+ expect(@event.venue.locality).to eq "Portland"
38
+ expect(@event.venue.region).to eq "Oregon"
39
+ expect(@event.venue.country).to eq "United States"
40
+ expect(@event.venue.latitude.to_s).to eq "45.5236"
41
+ expect(@event.venue.longitude.to_s).to eq "-122.675"
42
+ end
43
+ end
44
+
45
+ describe "when parsing Facebook URLs" do
46
+ def should_parse(url)
47
+ expect(url.match(Source::Parser::Facebook.url_pattern)[1]).to eq "247619485255249"
48
+ end
49
+
50
+ it "should parse a GET-style URL" do
51
+ should_parse 'http://facebook.com/event.php?eid=247619485255249'
52
+ end
53
+
54
+ it "should parse a GET-style URL using HTTPS" do
55
+ should_parse 'https://facebook.com/event.php?eid=247619485255249'
56
+ end
57
+
58
+ it "should parse a REST-style URL" do
59
+ should_parse 'http://www.facebook.com/events/247619485255249'
60
+ end
61
+
62
+ it "should parse a GET-style URL with a 'www.' host prefix" do
63
+ should_parse 'http://www.facebook.com/event.php?eid=247619485255249'
64
+ end
65
+
66
+ it "should parse a API uri" do
67
+ should_parse 'http://graph.facebook.com/247619485255249'
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ module Calagator
4
+
5
+ describe Source::Parser::Hcal, "with hCalendar events", :type => :model do
6
+ it "should parse hcal" do
7
+ url = "http://mysample.hcal/"
8
+ stub_request(:get, url).to_return(body: read_sample('hcal_single.xml'))
9
+ hcal_source = Source.new(title: "Calendar event feed", url: url)
10
+
11
+ events = hcal_source.to_events
12
+
13
+ expect(events.size).to eq 1
14
+ for key, value in {
15
+ :title => "Calendar event",
16
+ :description => "Check it out!",
17
+ :start_time => Time.parse("2008-1-19"),
18
+ :end_time => Time.parse("2008-1-20"),
19
+ :url => "http://www.cubespacepdx.com",
20
+ :venue_id => nil, # TODO what should venue instance be?
21
+ }
22
+ expect(events.first.send(key)).to eq value
23
+ end
24
+ end
25
+
26
+ it "should strip html from the venue title" do
27
+ url = "http://mysample.hcal/"
28
+ stub_request(:get, url).to_return(body: read_sample('hcal_upcoming_v1.html'))
29
+ hcal_source = Source.new(title: "Calendar event feed", url: url)
30
+
31
+ events = hcal_source.to_events
32
+
33
+ expect(events.first.venue.title).to eq 'Jive Software Office'
34
+ end
35
+
36
+ it "should parse a page with multiple events" do
37
+ url = "http://mysample.hcal/"
38
+ stub_request(:get, url).to_return(body: read_sample('hcal_multiple.xml'))
39
+ hcal_source = Source.new(title: "Calendar event feed", url: url)
40
+
41
+ events = hcal_source.to_events
42
+ expect(events.size).to eq 2
43
+ first, second = *events
44
+ expect(first.start_time).to eq Time.parse('2008-1-19')
45
+ expect(first.end_time).to eq Time.parse('2008-01-20')
46
+ expect(second.start_time).to eq Time.parse('2008-2-2')
47
+ expect(second.end_time).to eq Time.parse('2008-02-03')
48
+ end
49
+ end
50
+
51
+ describe Source::Parser::Hcal, "with hCalendar to Venue parsing", :type => :model do
52
+ it "should extract an Venue from an hCalendar text" do
53
+ url = "http://mysample.hcal/"
54
+ stub_request(:get, url).to_return(body: read_sample('hcal_upcoming_v1.html'))
55
+
56
+ events = Source::Parser::Hcal.to_events(url: url)
57
+ event = events.first
58
+ venue = event.venue
59
+
60
+ expect(venue).to be_a_kind_of(Venue)
61
+ expect(venue.locality).to eq "portland"
62
+ expect(venue.street_address).to eq "317 SW Alder St Ste 500"
63
+ expect(venue.latitude).to be_within(0.1).of(45.5191)
64
+ expect(venue.longitude).to be_within(0.1).of(-122.675)
65
+ expect(venue.postal_code).to eq "97204"
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ module Calagator
4
+
5
+ describe Calagator::Source::Parser::Ical, "when parsing VVENUE", :type => :model do
6
+ before(:each) do
7
+ @venue = Source::Parser::Ical.new.send(:to_venue, %(
8
+ BEGIN:VVENUE
9
+ X-VVENUE-INFO:http://evdb.com/docs/ical-venue/draft-norris-ical-venue.
10
+ html
11
+ UID:V0-001-001423875-1@eventful.com
12
+ NAME:Apple Store Pioneer Place
13
+ DESCRIPTION:(503) 222-3002 Driving Directions & Map Store Hours: Mon
14
+ - Fri: 9:30 a.m. to 9:00 p.m. Sat: 9:30 a.m. to 8:00 p.m. Sun: 11:00
15
+ a.m. to 6:00 p.m.
16
+ ADDRESS:700 Southwest Fifth Avenue Suite #1035
17
+ CITY:Portland
18
+ REGION;ABBREV=OR:Oregon
19
+ COUNTRY;ABBREV=USA:United States
20
+ POSTALCODE:97204
21
+ GEO:45.518798;-122.677583
22
+ URL;X-LABEL=Venue Info:http://eventful.com/V0-001-001423875-1
23
+ CATEGORIES:apple applecom appleinc technology
24
+ END:VVENUE))
25
+ end
26
+
27
+ it "should have a street_address" do
28
+ expect(@venue.street_address).not_to be_nil
29
+ end
30
+
31
+ it "should have the adress as is" do
32
+ @venue.street_address == '700 Southwest Fifth Avenue Suite #1035'
33
+ end
34
+
35
+ it "should have a locality" do
36
+ expect(@venue.locality).not_to be_nil
37
+ end
38
+
39
+ it "should have the locality as is" do
40
+ @venue.locality == 'Portland'
41
+ end
42
+ end
43
+
44
+ describe Source::Parser::Ical, "when parsing VCARD lines", :type => :model do
45
+ before(:each) do
46
+ # Note that each line here represents a single, complete property definition -- this method doesn't do any magical unwrapping of text.
47
+ @vcard_hash = Source::Parser::Ical.new.send(:hash_from_vcard_lines, %(
48
+ X-VVENUE-INFO:http://evdb.com/docs/ical-venue/draft-norris-ical-venue.html
49
+ UID:V0-001-001423875-1@eventful.com
50
+ NAME:Apple Store Pioneer Place
51
+ DESCRIPTION:(503) 222-3002 Driving Directions & Map Store Hours: Mon - Fri: 9:30 a.m. to 9:00 p.m. Sat: 9:30 a.m. to 8:00 p.m. Sun: 11:00 a.m. to 6:00 p.m.
52
+ ADDRESS:700 Southwest Fifth Avenue Suite; #1035
53
+ CITY:Portland
54
+ REGION;KMeta=none&bizzare:Oregon
55
+ COUNTRY;;;ABBREV=USA:United States
56
+ POSTALCODE:97204
57
+ GEO:45.518798;-122.677583
58
+ URL;X-LABEL=Venue Info:http://eventful.com/V0-001-001423875-1
59
+ CATEGORIES:apple applecom appleinc technology).split("\n"))
60
+ end
61
+
62
+ it "should find a property set by its key" do
63
+ expect(@vcard_hash['NAME']).to eq 'Apple Store Pioneer Place'
64
+ end
65
+
66
+ it "should find a property set by its key and meta-qualifier" do
67
+ expect(@vcard_hash['URL;X-LABEL=Venue Info']).to eq 'http://eventful.com/V0-001-001423875-1'
68
+ end
69
+
70
+ it "should find a property set by its key and meta-qualifier by its key when one wasn't specified" do
71
+ expect(@vcard_hash['URL']).to eq 'http://eventful.com/V0-001-001423875-1'
72
+ end
73
+
74
+ it "should find a property set by its key and multiple meta-qualifier by" do
75
+ @vcard_hash['COUNTRY;;;ABBREV=USA'] == 'United States'
76
+ end
77
+
78
+ it "should find a property set by its key and multiple meta-qualifiers by its key when one wasn't specified" do
79
+ @vcard_hash['COUNTRY'] == 'United States'
80
+ end
81
+
82
+ it "should find a property set by its key and meta-qualifier with odd characters" do
83
+ @vcard_hash['REGION;KMeta=none&bizzare'] == 'Oregon'
84
+ end
85
+
86
+ it "should find a property set by its key and meta-qualifier with odd characters by its key when one wasn't specified" do
87
+ @vcard_hash['REGION'] == 'Oregon'
88
+ end
89
+ end
90
+
91
+ end
@@ -0,0 +1,322 @@
1
+ require 'spec_helper'
2
+
3
+ def events_from_ical_at(filename)
4
+ url = "http://foo.bar/"
5
+ source = Calagator::Source.new(:title => "Calendar event feed", :url => url)
6
+ stub_request(:get, url).to_return(body: read_sample(filename))
7
+ return source.to_events(:skip_old => false)
8
+ end
9
+
10
+ module Calagator
11
+
12
+ describe Source::Parser::Ical, "in general", :type => :model do
13
+ it "should read http URLs as-is" do
14
+ url = "http://foo.bar/"
15
+ stub_request(:get, url).to_return(body: "42")
16
+ expect(Source::Parser::Ical.read_url(url)).to eq "42"
17
+ end
18
+
19
+ it "should read webcal URLs as http" do
20
+ webcal_url = "webcal://foo.bar/"
21
+ http_url = "http://foo.bar/"
22
+ stub_request(:get, http_url).to_return(body: "42")
23
+ expect(Source::Parser::Ical.read_url(webcal_url)).to eq "42"
24
+ end
25
+ end
26
+
27
+ describe Source::Parser::Ical, "when parsing events and their venues", :type => :model do
28
+
29
+ before(:each) do
30
+ url = "http://foo.bar/"
31
+ stub_request(:get, url).to_return(body: read_sample('ical_upcoming_many.ics'))
32
+ @events = Source::Parser.to_events(url: url, skip_old: false)
33
+ end
34
+
35
+ it "venues should be" do
36
+ @events.each do |event|
37
+ expect(event.venue).not_to be_nil
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ describe Source::Parser::Ical, "when parsing multiple items in an Eventful feed", :type => :model do
44
+ before(:each) do
45
+ url = "http://foo.bar/"
46
+ stub_request(:get, url).to_return(body: read_sample('ical_eventful_many.ics'))
47
+ @events = Source::Parser.to_events(url: url, skip_old: false)
48
+ end
49
+
50
+ it "should find multiple events" do
51
+ expect(@events.size).to eq 15
52
+ end
53
+
54
+ it "should find venues for events" do
55
+ @events.each do |event|
56
+ expect(event.venue.title).not_to be_nil
57
+ end
58
+ end
59
+
60
+ it "should match each event with its venue" do
61
+ event_titles_and_street_addresses = [
62
+ ["iMovie and iDVD Workshop", "7293 SW Bridgeport Road"],
63
+ ["Portland Macintosh Users Group (PMUG)", "Jean Vollum Natural Capital Center"],
64
+ ["Morning Meetings: IT", "622 SE Grand Avenue"]
65
+ ]
66
+
67
+ # Make sure each of the above events has the expected street address
68
+ event_titles_and_street_addresses.each do |event_title, street_address|
69
+ expect(@events.find { |event|
70
+ event.title == event_title && event.venue.street_address == street_address
71
+ }).not_to be_nil
72
+ end
73
+ end
74
+ end
75
+
76
+ describe Source::Parser::Ical, "with iCalendar events", :type => :model do
77
+
78
+ it "should parse Apple iCalendar v3 format" do
79
+ events = events_from_ical_at('ical_apple_v3.ics')
80
+
81
+ expect(events.size).to eq 1
82
+ event = events.first
83
+ expect(event.title).to eq "Coffee with Jason"
84
+ expect(event.start_time).to eq Time.zone.parse('2010-04-08 00:00:00 PDT -07:00')
85
+ expect(event.end_time).to eq Time.zone.parse('2010-04-08 01:00:00 PDT -07:00')
86
+ expect(event.venue).to be_nil
87
+ end
88
+
89
+ it "should parse basic iCalendar format" do
90
+ events = events_from_ical_at('ical_basic.ics')
91
+
92
+ expect(events.size).to eq 1
93
+ event = events.first
94
+ expect(event.title).to be_blank
95
+ expect(event.start_time).to eq Time.zone.parse('Wed Jan 17 00:00:00 2007')
96
+ expect(event.venue).to be_nil
97
+ end
98
+
99
+ it "should parse basic iCalendar format with a duration and set the correct end time" do
100
+ events = events_from_ical_at('ical_basic_with_duration.ics')
101
+
102
+ expect(events.size).to eq 1
103
+ event = events.first
104
+ expect(event.title).to be_blank
105
+ expect(event.start_time).to eq Time.zone.parse('2010-04-08 00:00:00')
106
+ expect(event.end_time).to eq Time.zone.parse('2010-04-08 01:00:00')
107
+ expect(event.venue).to be_nil
108
+ end
109
+
110
+ it "should parse Google iCalendar feed with multiple events" do
111
+ events = events_from_ical_at('ical_google.ics')
112
+ # TODO add specs for venues/locations
113
+
114
+ expect(events.size).to eq 47
115
+
116
+ event = events.first
117
+ expect(event.title).to eq "XPDX (eXtreme Programming) at CubeSpace"
118
+ expect(event.description).to be_blank
119
+ expect(event.start_time).to eq Time.parse("2007-10-24 18:30:00 PDT")
120
+ expect(event.end_time).to eq Time.parse("2007-10-24 19:30:00 PDT")
121
+
122
+ event = events[17]
123
+ expect(event.title).to eq "Code Sprint/Coding Dojo at CubeSpace"
124
+ expect(event.description).to be_blank
125
+ expect(event.start_time).to eq Time.parse("2007-10-17 19:00:00 PDT")
126
+ expect(event.end_time).to eq Time.parse("2007-10-17 21:00:00 PDT")
127
+
128
+ event = events.last
129
+ expect(event.title).to eq "Adobe Developer User Group"
130
+ expect(event.description).to eq "http://pdxria.com/"
131
+ expect(event.start_time).to eq Time.parse("2007-01-16 17:30:00 PST")
132
+ expect(event.end_time).to eq Time.parse("2007-01-16 18:30:00 PST")
133
+ end
134
+
135
+ it "should parse non-Vcard locations" do
136
+ events = events_from_ical_at('ical_google.ics')
137
+ expect(events.first.venue.title).to eq 'CubeSpace'
138
+ end
139
+
140
+ it "should parse a calendar file with multiple calendars" do
141
+ events = events_from_ical_at('ical_multiple_calendars.ics')
142
+ expect(events.size).to eq 3
143
+ expect(events.map(&:title)).to eq ["Coffee with Jason", "Coffee with Mike", "Coffee with Kim"]
144
+ end
145
+
146
+ it "should not swallow errors" do
147
+ expect(RiCal).to receive(:parse_string).and_raise(TypeError)
148
+ expect { events_from_ical_at('ical_multiple_calendars.ics') }.to raise_error(TypeError)
149
+ end
150
+ end
151
+
152
+ describe Source::Parser::Ical, "when importing events with non-local times", :type => :model do
153
+
154
+ it "should store time ending in Z as UTC" do
155
+ url = "http://foo.bar/"
156
+ stub_request(:get, url).to_return(body: read_sample('ical_z.ics'))
157
+ @source = Source.new(:title => "Non-local time", :url => url)
158
+ events = @source.create_events!(:skip_old => false)
159
+ event = events.first
160
+
161
+ expect(event.start_time).to eq Time.parse('Thu Jul 01 08:00:00 +0000 2010')
162
+ expect(event.end_time).to eq Time.parse('Thu Jul 01 09:00:00 +0000 2010')
163
+
164
+ # time should be the same after saving event to, and getting it from, database
165
+ event.save
166
+ e = Event.find(event)
167
+ expect(e.start_time).to eq Time.parse('Thu Jul 01 08:00:00 +0000 2010')
168
+ expect(e.end_time).to eq Time.parse('Thu Jul 01 09:00:00 +0000 2010')
169
+ end
170
+
171
+ it "should store time with TZID=GMT in UTC" do
172
+ events = events_from_ical_at('ical_gmt.ics')
173
+ expect(events.size).to eq 1
174
+ event = events.first
175
+ expect(event.start_time).to eq Time.parse('Fri May 07 08:00:00 +0000 2020')
176
+ expect(event.end_time).to eq Time.parse('Fri May 07 09:00:00 +0000 2020')
177
+ end
178
+ end
179
+
180
+ describe Source::Parser::Ical, "munge_gmt_dates", :type => :model do
181
+ it "should return unexpected-format strings unmodified" do
182
+ munged = Source::Parser::Ical.new.send(:munge_gmt_dates, 'justin bieber on a train')
183
+ expect(munged).to eq 'justin bieber on a train'
184
+ end
185
+
186
+ it "should return GMT-less ical strings unmodified" do
187
+ icard = %{
188
+ BEGIN:VCALENDAR
189
+ BEGIN:VEVENT
190
+ DTSTART:20200507T080000
191
+ DTEND:20200507T090000
192
+ END:VEVENT
193
+ END:VCALENDAR
194
+ }
195
+
196
+ expect(Source::Parser::Ical.new.send(:munge_gmt_dates, icard)).to eq icard
197
+ end
198
+
199
+ it "should replace TZID=GMT with a TZID-less UTC time" do
200
+ icard = %{
201
+ BEGIN:VCALENDAR
202
+ BEGIN:VEVENT
203
+ DTSTART;TZID=GMT:20200507T080000
204
+ DTEND;TZID=GMT:20200507T090000
205
+ END:VEVENT
206
+ END:VCALENDAR
207
+ }
208
+
209
+ munged = %{
210
+ BEGIN:VCALENDAR
211
+ BEGIN:VEVENT
212
+ DTSTART:20200507T080000Z
213
+ DTEND:20200507T090000Z
214
+ END:VEVENT
215
+ END:VCALENDAR
216
+ }
217
+
218
+ expect(Source::Parser::Ical.new.send(:munge_gmt_dates, icard)).to eq munged
219
+ end
220
+ end
221
+
222
+ describe Source::Parser::Ical, "when skipping old events", :type => :model do
223
+ before(:each) do
224
+ url = "http://foo.bar/"
225
+ stub_request(:get, url).to_return(body:
226
+ %(BEGIN:VCALENDAR
227
+ X-WR-CALNAME;VALUE=TEXT:NERV
228
+ VERSION:2.0
229
+ CALSCALE:GREGORIAN
230
+ PRODID:-//nerv.go.jp//iCal 1.0//EN
231
+ X-WR-TIMEZONE;VALUE=TEXT:US/Eastern
232
+ BEGIN:VEVENT
233
+ UID:Unit-01
234
+ SUMMARY:Past start and no end
235
+ DESCRIPTION:Ayanami
236
+ DTSTART:#{(Time.now-1.year).strftime("%Y%m%d")}
237
+ DTSTAMP:040425
238
+ SEQ:0
239
+ END:VEVENT
240
+ BEGIN:VEVENT
241
+ UID:Unit-02
242
+ SUMMARY:Current start and no end
243
+ DESCRIPTION:Soryu
244
+ DTSTART:#{(Time.now+1.year).strftime("%Y%m%d")}
245
+ DTSTAMP:040425
246
+ SEQ:1
247
+ END:VEVENT
248
+ BEGIN:VEVENT
249
+ UID:Unit-03
250
+ SUMMARY:Past start and current end
251
+ DESCRIPTION:Soryu a
252
+ DTSTART:#{(Time.now-1.year).strftime("%Y%m%d")}
253
+ DTEND:#{(Time.now+1.year).strftime("%Y%m%d")}
254
+ DTSTAMP:040425
255
+ END:VEVENT
256
+ BEGIN:VEVENT
257
+ UID:Unit-04
258
+ SUMMARY:Current start and current end
259
+ DESCRIPTION:Soryu as
260
+ DTSTART:#{Time.now.strftime("%Y%m%d")}
261
+ DTEND:#{(Time.now+1.year).strftime("%Y%m%d")}
262
+ DTSTAMP:040425
263
+ END:VEVENT
264
+ BEGIN:VEVENT
265
+ UID:Unit-05
266
+ SUMMARY:Past start and past end
267
+ DESCRIPTION:Soryu qewr
268
+ DTSTART:#{(Time.now-1.year).strftime("%Y%m%d")}
269
+ DTEND:#{(Time.now-1.year).strftime("%Y%m%d")}
270
+ DTSTAMP:040425
271
+ END:VEVENT
272
+ BEGIN:VEVENT
273
+ UID:Unit-06
274
+ SUMMARY:Current start and past end
275
+ DESCRIPTION:Not a valid event
276
+ DTSTART:#{Time.now.strftime("%Y%m%d")}
277
+ DTEND:#{(Time.now-1.year).strftime("%Y%m%d")}
278
+ DTSTAMP:040425
279
+ END:VEVENT
280
+ END:VCALENDAR))
281
+ @source = Source.new(title: "Title", url: url)
282
+ end
283
+
284
+ # for following specs a 'valid' event does not start after it ends"
285
+ it "should be able to import all valid events" do
286
+ events = @source.create_events!(:skip_old => false)
287
+ expect(events.map(&:title)).to eq [
288
+ "Past start and no end",
289
+ "Current start and no end",
290
+ "Past start and current end",
291
+ "Current start and current end",
292
+ "Past start and past end"
293
+ ]
294
+ end
295
+
296
+ it "should be able to skip invalid and old events" do
297
+ events = @source.create_events!(:skip_old => true)
298
+ expect(events.map(&:title)).to eq [
299
+ "Current start and no end",
300
+ "Past start and current end",
301
+ "Current start and current end"
302
+ ]
303
+ end
304
+ end
305
+
306
+ describe Source::Parser::Ical, "when parsing an invalid ical", :type => :model do
307
+ before(:each) do
308
+ url = "http://foo.bar/"
309
+ stub_request(:get, url).to_return(body:
310
+ %(BEGIN:VCALENDAR
311
+ BEGIN:VEVENT
312
+ OMGWTFBBQ
313
+ END:VCALENDAR))
314
+ @source = Source.new(title: "Title", url: url)
315
+ end
316
+
317
+ it "should return no events" do
318
+ @source.create_events!.should == []
319
+ end
320
+ end
321
+
322
+ end