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.
- checksums.yaml +7 -0
- data/LICENSE.txt +23 -0
- data/README.md +75 -0
- data/Rakefile +12 -0
- data/app/assets/images/confused-alligator-sm.png +0 -0
- data/app/assets/images/disk.png +0 -0
- data/app/assets/images/edit.png +0 -0
- data/app/assets/images/external_sites/epdx.png +0 -0
- data/app/assets/images/external_sites/external.gif +0 -0
- data/app/assets/images/external_sites/facebook.png +0 -0
- data/app/assets/images/external_sites/foursquare.png +0 -0
- data/app/assets/images/external_sites/gowalla.png +0 -0
- data/app/assets/images/external_sites/lanyrd.png +0 -0
- data/app/assets/images/external_sites/meetup.png +0 -0
- data/app/assets/images/external_sites/plancast.png +0 -0
- data/app/assets/images/external_sites/shizzow.png +0 -0
- data/app/assets/images/external_sites/upcoming.png +0 -0
- data/app/assets/images/external_sites/yelp.png +0 -0
- data/app/assets/images/feed.png +0 -0
- data/app/assets/images/heart.png +0 -0
- data/app/assets/images/icon_ical.gif +0 -0
- data/app/assets/images/information.png +0 -0
- data/app/assets/images/nav_marker.gif +0 -0
- data/app/assets/images/nav_marker.png +0 -0
- data/app/assets/images/plus.png +0 -0
- data/app/assets/images/redx.png +0 -0
- data/app/assets/images/site-icon.png +0 -0
- data/app/assets/images/spinner.gif +0 -0
- data/app/assets/images/star.png +0 -0
- data/app/assets/images/subnav_marker.gif +0 -0
- data/app/assets/images/subnav_marker.png +0 -0
- data/app/assets/images/tag_blue.png +0 -0
- data/app/assets/images/tag_icons/angular.png +0 -0
- data/app/assets/images/tag_icons/beer.png +0 -0
- data/app/assets/images/tag_icons/bitcoin.png +0 -0
- data/app/assets/images/tag_icons/free.png +0 -0
- data/app/assets/images/tag_icons/golang.png +0 -0
- data/app/assets/images/tag_icons/html.png +0 -0
- data/app/assets/images/tag_icons/javascript.png +0 -0
- data/app/assets/images/tag_icons/linux.png +0 -0
- data/app/assets/images/tag_icons/php.png +0 -0
- data/app/assets/images/tag_icons/pizza.png +0 -0
- data/app/assets/images/tag_icons/python.png +0 -0
- data/app/assets/images/tag_icons/rails.png +0 -0
- data/app/assets/images/tag_icons/ruby.png +0 -0
- data/app/assets/images/tag_icons/sass.png +0 -0
- data/app/assets/images/tag_icons/swift.png +0 -0
- data/app/assets/images/transmit_blue.png +0 -0
- data/app/assets/images/weekday_background.gif +0 -0
- data/app/assets/javascripts/calagator.js +18 -0
- data/app/assets/javascripts/calagator/forms.js +60 -0
- data/app/assets/stylesheets/calagator.scss +8 -0
- data/app/assets/stylesheets/calagator/common.scss +14 -0
- data/app/assets/stylesheets/calagator/datepicker.scss +177 -0
- data/app/assets/stylesheets/calagator/errors.css +110 -0
- data/app/assets/stylesheets/calagator/forms.scss +4 -0
- data/app/assets/stylesheets/calagator/reset.css +40 -0
- data/app/assets/stylesheets/calagator/theme.css +0 -0
- data/app/controllers/calagator/admin_controller.rb +27 -0
- data/app/controllers/calagator/application_controller.rb +82 -0
- data/app/controllers/calagator/events_controller.rb +171 -0
- data/app/controllers/calagator/site_controller.rb +35 -0
- data/app/controllers/calagator/sources_controller.rb +94 -0
- data/app/controllers/calagator/venues_controller.rb +133 -0
- data/app/controllers/calagator/versions_controller.rb +20 -0
- data/app/helpers/calagator/application_helper.rb +128 -0
- data/app/helpers/calagator/events_helper.rb +184 -0
- data/app/helpers/calagator/google_event_export_helper.rb +67 -0
- data/app/helpers/calagator/mapping_helper.rb +103 -0
- data/app/helpers/calagator/sources_helper.rb +10 -0
- data/app/helpers/calagator/tags_helper.rb +42 -0
- data/app/helpers/calagator/time_range_helper.rb +166 -0
- data/app/models/calagator/event.rb +246 -0
- data/app/models/calagator/event/cloner.rb +39 -0
- data/app/models/calagator/event/ical_renderer.rb +155 -0
- data/app/models/calagator/event/overview.rb +45 -0
- data/app/models/calagator/event/saver.rb +58 -0
- data/app/models/calagator/event/search.rb +72 -0
- data/app/models/calagator/event/search_engine.rb +28 -0
- data/app/models/calagator/event/search_engine/apache_sunspot.rb +106 -0
- data/app/models/calagator/event/search_engine/sql.rb +107 -0
- data/app/models/calagator/source.rb +115 -0
- data/app/models/calagator/source/importer.rb +46 -0
- data/app/models/calagator/source/parser.rb +128 -0
- data/app/models/calagator/source/parser/facebook.rb +67 -0
- data/app/models/calagator/source/parser/hcal.rb +108 -0
- data/app/models/calagator/source/parser/http_authentication_required_error.rb +6 -0
- data/app/models/calagator/source/parser/ical.rb +186 -0
- data/app/models/calagator/source/parser/meetup.rb +72 -0
- data/app/models/calagator/source/parser/not_found.rb +9 -0
- data/app/models/calagator/source/parser/plancast.rb +59 -0
- data/app/models/calagator/venue.rb +161 -0
- data/app/models/calagator/venue/geocoder.rb +51 -0
- data/app/models/calagator/venue/search.rb +63 -0
- data/app/models/calagator/venue/search_engine.rb +24 -0
- data/app/models/calagator/venue/search_engine/apache_sunspot.rb +85 -0
- data/app/models/calagator/venue/search_engine/sql.rb +68 -0
- data/app/models/event/search_engine/base.rb +0 -0
- data/app/observers/calagator/cache_observer.rb +37 -0
- data/app/views/calagator/admin/events.html.erb +28 -0
- data/app/views/calagator/admin/index.html.erb +8 -0
- data/app/views/calagator/events/_feed_item.html.erb +62 -0
- data/app/views/calagator/events/_form.html.erb +63 -0
- data/app/views/calagator/events/_gcal_reminder.html.erb +1 -0
- data/app/views/calagator/events/_hcal.html.erb +41 -0
- data/app/views/calagator/events/_item.html.erb +120 -0
- data/app/views/calagator/events/_list.html.erb +30 -0
- data/app/views/calagator/events/_list_item.html.erb +37 -0
- data/app/views/calagator/events/_search_section.html.erb +15 -0
- data/app/views/calagator/events/_subnav.html.erb +13 -0
- data/app/views/calagator/events/_table.html.erb +74 -0
- data/app/views/calagator/events/duplicates.html.erb +58 -0
- data/app/views/calagator/events/edit.html.erb +3 -0
- data/app/views/calagator/events/index.atom.builder +32 -0
- data/app/views/calagator/events/index.html.erb +51 -0
- data/app/views/calagator/events/index.kml.erb +20 -0
- data/app/views/calagator/events/new.html.erb +7 -0
- data/app/views/calagator/events/search.html.erb +25 -0
- data/app/views/calagator/events/show.html.erb +81 -0
- data/app/views/calagator/site/_appropriateness_message.html.erb +15 -0
- data/app/views/calagator/site/_description.html.erb +3 -0
- data/app/views/calagator/site/about.html.erb +7 -0
- data/app/views/calagator/site/defunct.html.erb +15 -0
- data/app/views/calagator/site/export.html.erb +4 -0
- data/app/views/calagator/site/index.html.erb +40 -0
- data/app/views/calagator/site/opensearch.xml.builder +8 -0
- data/app/views/calagator/sources/_subnav.html.erb +0 -0
- data/app/views/calagator/sources/edit.html.erb +12 -0
- data/app/views/calagator/sources/import.html.erb +10 -0
- data/app/views/calagator/sources/index.html.erb +22 -0
- data/app/views/calagator/sources/new.html.erb +32 -0
- data/app/views/calagator/sources/show.html.erb +16 -0
- data/app/views/calagator/venues/_form.html.erb +57 -0
- data/app/views/calagator/venues/_subnav.html.erb +10 -0
- data/app/views/calagator/venues/duplicates.html.erb +65 -0
- data/app/views/calagator/venues/edit.html.erb +3 -0
- data/app/views/calagator/venues/index.html.erb +93 -0
- data/app/views/calagator/venues/index.kml.erb +15 -0
- data/app/views/calagator/venues/map.html.erb +4 -0
- data/app/views/calagator/venues/new.html.erb +5 -0
- data/app/views/calagator/venues/show.html.erb +113 -0
- data/app/views/calagator/versions/_chooser.html.erb +28 -0
- data/app/views/calagator/versions/_edit_with_chooser.html.erb +16 -0
- data/app/views/layouts/calagator/application.html.erb +110 -0
- data/config/deploy/local.rb +37 -0
- data/config/deploy/lucca.rb +33 -0
- data/config/initializers/dates.rb +7 -0
- data/config/initializers/formtastic.rb +82 -0
- data/config/initializers/geokit.rb +74 -0
- data/config/initializers/ics_renderer.rb +6 -0
- data/config/initializers/load_tag_model_extensions.rb +3 -0
- data/config/initializers/mime_types.rb +9 -0
- data/config/initializers/observers.rb +1 -0
- data/config/initializers/search_engine.rb +4 -0
- data/config/initializers/set_default_url_host.rb +5 -0
- data/config/initializers/time_get_zone.rb +8 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +55 -0
- data/config/secrets.yml.blag +75 -0
- data/config/sunspot.yml +23 -0
- data/db/development.sqlite3 +0 -0
- data/db/development.sqlite3.bak +0 -0
- data/db/development.sqlite3.old +0 -0
- data/db/development~20111112@110950.sqlite3 +0 -0
- data/db/migrate/001_create_events.rb +17 -0
- data/db/migrate/002_create_venues.rb +17 -0
- data/db/migrate/003_create_sources.rb +16 -0
- data/db/migrate/004_add_detailed_fields_to_venue.rb +19 -0
- data/db/migrate/005_add_end_time_to_events.rb +9 -0
- data/db/migrate/006_add_source_id_to_events.rb +9 -0
- data/db/migrate/008_add_source_id_to_venues.rb +10 -0
- data/db/migrate/009_add_duplicate_of_column_to_venues.rb +9 -0
- data/db/migrate/010_add_duplicate_of_column_to_events.rb +9 -0
- data/db/migrate/011_change_lat_long_type.rb +12 -0
- data/db/migrate/012_add_source_reimport.rb +9 -0
- data/db/migrate/013_change_end_time_to_duration.rb +11 -0
- data/db/migrate/014_remove_format_type_from_source.rb +9 -0
- data/db/migrate/015_create_updates.rb +15 -0
- data/db/migrate/016_remove_next_update_from_source.rb +9 -0
- data/db/migrate/20080705163959_change_duration_to_end_time.rb +11 -0
- data/db/migrate/20080705164959_create_tags_and_taggings.rb +28 -0
- data/db/migrate/20081011181519_create_versioned_events.rb +25 -0
- data/db/migrate/20081011193124_create_versioned_venues.rb +32 -0
- data/db/migrate/20081115190515_add_rrule_to_events.rb +15 -0
- data/db/migrate/20090912082129_create_versions.rb +18 -0
- data/db/migrate/20110219205156_add_closed_flag_to_venues.rb +9 -0
- data/db/migrate/20110220001008_add_wifi_flag_to_venues.rb +9 -0
- data/db/migrate/20110220011427_add_access_notes_to_venues.rb +9 -0
- data/db/migrate/20110220031117_add_events_count_to_venues.rb +8 -0
- data/db/migrate/20110604174521_add_venue_details_to_events.rb +9 -0
- data/db/migrate/20110717231316_acts_as_taggable_on_migration.rb +50 -0
- data/db/migrate/20120709092821_cleanup.rb +14 -0
- data/db/migrate/20120831234448_specify_venues_latitude_and_longitude_precision.rb +11 -0
- data/db/migrate/20150206085809_remove_updates.rb +13 -0
- data/db/migrate/20150207231355_add_locked_status_to_events.rb +5 -0
- data/db/production.sqlite3 +0 -0
- data/db/schema.rb +102 -0
- data/db/seeds.rb +16 -0
- data/db/test.sqlite3 +0 -0
- data/db/test2.sqlite3 +0 -0
- data/lib/calagator.rb +30 -0
- data/lib/calagator/blacklist_validator.rb +69 -0
- data/lib/calagator/decode_html_entities_hack.rb +33 -0
- data/lib/calagator/duplicate_checking.rb +133 -0
- data/lib/calagator/duplicate_checking/controller_actions.rb +38 -0
- data/lib/calagator/duplicate_checking/duplicate_finder.rb +83 -0
- data/lib/calagator/duplicate_checking/duplicate_squasher.rb +74 -0
- data/lib/calagator/engine.rb +30 -0
- data/lib/calagator/strip_whitespace.rb +19 -0
- data/lib/calagator/tag_model_extensions.rb +104 -0
- data/lib/calagator/url_prefixer.rb +9 -0
- data/lib/calagator/version.rb +3 -0
- data/lib/generators/calagator/install_generator.rb +39 -0
- data/lib/generators/calagator/templates/config/calagator.rb +26 -0
- data/lib/generators/calagator/templates/config/secrets.yml.sample +83 -0
- data/lib/secrets_reader.rb +76 -0
- data/lib/tasks/spec_db.rake +53 -0
- data/lib/tasks/sunspot_reindex_calagator.rake +6 -0
- data/lib/tasks/sunspot_solr_restart_enhancements.rake +19 -0
- data/lib/tasks/update_counter_caches.rake +13 -0
- data/lib/templates/erb/scaffold/_form.html.erb +11 -0
- data/lib/theme_reader.rb +17 -0
- data/lib/wait_for_solr.rb +25 -0
- data/spec/controllers/calagator/application_controller_spec.rb +47 -0
- data/spec/controllers/calagator/events_controller_spec.rb +794 -0
- data/spec/controllers/calagator/site_controller_spec.rb +59 -0
- data/spec/controllers/calagator/sources_controller_spec.rb +439 -0
- data/spec/controllers/calagator/venues_controller_spec.rb +319 -0
- data/spec/controllers/calagator/versions_controller_spec.rb +82 -0
- data/spec/controllers/squash_many_duplicates_examples.rb +49 -0
- data/spec/dummy/Gemfile +39 -0
- data/spec/dummy/Gemfile.lock +195 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/images/rails.png +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +16 -0
- data/spec/dummy/app/assets/stylesheets/application.css +14 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +62 -0
- data/spec/dummy/config/boot.rb +6 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/calagator.rb +26 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +59 -0
- data/spec/dummy/config/secrets.yml +83 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20150309023304_create_events.calagator.rb +18 -0
- data/spec/dummy/db/migrate/20150309023305_create_venues.calagator.rb +18 -0
- data/spec/dummy/db/migrate/20150309023306_create_sources.calagator.rb +17 -0
- data/spec/dummy/db/migrate/20150309023307_add_detailed_fields_to_venue.calagator.rb +20 -0
- data/spec/dummy/db/migrate/20150309023308_add_end_time_to_events.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023309_add_source_id_to_events.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023310_add_source_id_to_venues.calagator.rb +11 -0
- data/spec/dummy/db/migrate/20150309023311_add_duplicate_of_column_to_venues.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023312_add_duplicate_of_column_to_events.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023313_change_lat_long_type.calagator.rb +13 -0
- data/spec/dummy/db/migrate/20150309023314_add_source_reimport.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023315_change_end_time_to_duration.calagator.rb +12 -0
- data/spec/dummy/db/migrate/20150309023316_remove_format_type_from_source.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023317_create_updates.calagator.rb +16 -0
- data/spec/dummy/db/migrate/20150309023318_remove_next_update_from_source.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023319_change_duration_to_end_time.calagator.rb +12 -0
- data/spec/dummy/db/migrate/20150309023320_create_tags_and_taggings.calagator.rb +29 -0
- data/spec/dummy/db/migrate/20150309023321_create_versioned_events.calagator.rb +26 -0
- data/spec/dummy/db/migrate/20150309023322_create_versioned_venues.calagator.rb +33 -0
- data/spec/dummy/db/migrate/20150309023323_add_rrule_to_events.calagator.rb +16 -0
- data/spec/dummy/db/migrate/20150309023324_create_versions.calagator.rb +19 -0
- data/spec/dummy/db/migrate/20150309023325_add_closed_flag_to_venues.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023326_add_wifi_flag_to_venues.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023327_add_access_notes_to_venues.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023328_add_events_count_to_venues.calagator.rb +9 -0
- data/spec/dummy/db/migrate/20150309023329_add_venue_details_to_events.calagator.rb +10 -0
- data/spec/dummy/db/migrate/20150309023330_acts_as_taggable_on_migration.calagator.rb +51 -0
- data/spec/dummy/db/migrate/20150309023331_cleanup.calagator.rb +15 -0
- data/spec/dummy/db/migrate/20150309023332_specify_venues_latitude_and_longitude_precision.calagator.rb +12 -0
- data/spec/dummy/db/migrate/20150309023333_remove_updates.calagator.rb +14 -0
- data/spec/dummy/db/migrate/20150309023334_add_locked_status_to_events.calagator.rb +6 -0
- data/spec/dummy/db/schema.rb +95 -0
- data/spec/dummy/db/seeds.rb +7 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/doc/README_FOR_APP +2 -0
- data/spec/dummy/log/development.log +273 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/robots.txt +5 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/test/performance/browsing_test.rb +12 -0
- data/spec/dummy/test/test_helper.rb +13 -0
- data/spec/factories.rb +93 -0
- data/spec/features/add_event_spec.rb +99 -0
- data/spec/features/add_venue_spec.rb +34 -0
- data/spec/features/admin_auth_spec.rb +22 -0
- data/spec/features/admin_lock_event_spec.rb +41 -0
- data/spec/features/import_events_from_feed_spec.rb +43 -0
- data/spec/features/managing_event_spec.rb +111 -0
- data/spec/features/managing_venue_spec.rb +71 -0
- data/spec/features/search_event_spec.rb +27 -0
- data/spec/helpers/calagator/application_helper_spec.rb +82 -0
- data/spec/helpers/calagator/events_helper_spec.rb +172 -0
- data/spec/helpers/calagator/google_event_export_helper_spec.rb +70 -0
- data/spec/helpers/calagator/sources_helper_spec.rb +12 -0
- data/spec/helpers/calagator/tags_helper_spec.rb +85 -0
- data/spec/helpers/calagator/time_range_helper_spec.rb +59 -0
- data/spec/lib/calagator/blacklist_validator_spec.rb +65 -0
- data/spec/lib/calagator/decode_html_entities_hack_spec.rb +54 -0
- data/spec/lib/calagator/settings_spec.rb +20 -0
- data/spec/lib/calagator/url_prefixer_spec.rb +33 -0
- data/spec/lib/secrets_reader_spec.rb +65 -0
- data/spec/models/calagator/event/cloner_spec.rb +43 -0
- data/spec/models/calagator/event/overview_spec.rb +79 -0
- data/spec/models/calagator/event/search_spec.rb +103 -0
- data/spec/models/calagator/event_search_spec.rb +149 -0
- data/spec/models/calagator/event_spec.rb +859 -0
- data/spec/models/calagator/source/parser_facebook_spec.rb +73 -0
- data/spec/models/calagator/source/parser_hcal_spec.rb +69 -0
- data/spec/models/calagator/source/parser_ical_non_standard_spec.rb +91 -0
- data/spec/models/calagator/source/parser_ical_spec.rb +322 -0
- data/spec/models/calagator/source/parser_meetup_spec.rb +69 -0
- data/spec/models/calagator/source/parser_plancast_spec.rb +53 -0
- data/spec/models/calagator/source/parser_spec.rb +238 -0
- data/spec/models/calagator/source_spec.rb +135 -0
- data/spec/models/calagator/venue/search_spec.rb +92 -0
- data/spec/models/calagator/venue_search_spec.rb +124 -0
- data/spec/models/calagator/venue_spec.rb +346 -0
- data/spec/models/tag_spec.rb +35 -0
- data/spec/rails_helper.rb +39 -0
- data/spec/spec_helper.rb +140 -0
- data/spec/support/disable_geocoding.rb +1 -0
- data/spec/support/http_samples.rb +5 -0
- data/spec/support/samples/facebook.json +23 -0
- data/spec/support/samples/hcal_basic.xml +6 -0
- data/spec/support/samples/hcal_dup_event_dup_venue.xml +13 -0
- data/spec/support/samples/hcal_event_duplicates_fixture.xml +13 -0
- data/spec/support/samples/hcal_event_wo_lat_and_long.xml +14 -0
- data/spec/support/samples/hcal_multiple.xml +16 -0
- data/spec/support/samples/hcal_same_event_twice_with_different_venues.xml +12 -0
- data/spec/support/samples/hcal_single.xml +8 -0
- data/spec/support/samples/hcal_two_identical_events.xml +14 -0
- data/spec/support/samples/hcal_upcoming_v1.html +412 -0
- data/spec/support/samples/hcal_upcoming_v2.html +749 -0
- data/spec/support/samples/hcal_upcoming_v3.html +685 -0
- data/spec/support/samples/hcal_upcoming_v4.html +761 -0
- data/spec/support/samples/ical_apple.ics +22 -0
- data/spec/support/samples/ical_apple_v3.ics +37 -0
- data/spec/support/samples/ical_basic.ics +15 -0
- data/spec/support/samples/ical_basic_with_duration.ics +16 -0
- data/spec/support/samples/ical_event_with_squashed_venue.ics +12 -0
- data/spec/support/samples/ical_eventful_many.ics +504 -0
- data/spec/support/samples/ical_gmt.ics +12 -0
- data/spec/support/samples/ical_google.ics +786 -0
- data/spec/support/samples/ical_multiple_calendars.ics +111 -0
- data/spec/support/samples/ical_upcoming.ics +36 -0
- data/spec/support/samples/ical_upcoming_many.ics +682 -0
- data/spec/support/samples/ical_upcoming_v2.ics +43 -0
- data/spec/support/samples/ical_z.ics +10 -0
- data/spec/support/samples/meetup.ics +16 -0
- data/spec/support/samples/meetup.json +31 -0
- data/spec/support/samples/plancast.ics +59 -0
- data/spec/support/samples/plancast.json +51 -0
- data/spec/support/samples/plancast_with_missing_venue.json +39 -0
- data/spec/support/samples/upcoming_v1.xml +8 -0
- data/spec/support/samples/upcoming_v2_with_invalid_utc_dates.xml +8 -0
- data/spec/support/time_convenience_methods.rb +8 -0
- data/spec/support/time_zones.rb +12 -0
- data/spec/support/url_helpers.rb +5 -0
- data/spec/support/wait_for_ajax.rb +15 -0
- data/spec/support/webmock.rb +8 -0
- data/spec/travis_spec.rb +7 -0
- metadata +1194 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module Calagator
|
|
2
|
+
|
|
3
|
+
class SourcesController < ApplicationController
|
|
4
|
+
# POST /import
|
|
5
|
+
# POST /import.xml
|
|
6
|
+
def import
|
|
7
|
+
@importer = Source::Importer.new(params[:source])
|
|
8
|
+
respond_to do |format|
|
|
9
|
+
if @importer.import
|
|
10
|
+
format.html { redirect_to events_path, flash: { success: render_to_string(layout: false) } }
|
|
11
|
+
format.xml { render xml: @importer.source, events: @importer.events }
|
|
12
|
+
else
|
|
13
|
+
format.html { redirect_to new_source_path(url: @importer.source.url), flash: { failure: @importer.failure_message } }
|
|
14
|
+
format.xml { render xml: @importer.source.errors, status: :unprocessable_entity }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# GET /sources
|
|
20
|
+
# GET /sources.xml
|
|
21
|
+
def index
|
|
22
|
+
@sources = Source.listing
|
|
23
|
+
|
|
24
|
+
respond_to do |format|
|
|
25
|
+
format.html { @sources = @sources.paginate(page: params[:page], per_page: params[:per_page]) }
|
|
26
|
+
format.xml { render xml: @sources }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# GET /sources/1
|
|
31
|
+
# GET /sources/1.xml
|
|
32
|
+
def show
|
|
33
|
+
@source = Source.find(params[:id], include: [:events, :venues])
|
|
34
|
+
respond_to do |format|
|
|
35
|
+
format.html # show.html.erb
|
|
36
|
+
format.xml { render xml: @source }
|
|
37
|
+
end
|
|
38
|
+
rescue ActiveRecord::RecordNotFound => error
|
|
39
|
+
flash[:failure] = error.to_s if params[:id] != "import"
|
|
40
|
+
redirect_to new_source_path
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# GET /sources/new
|
|
44
|
+
def new
|
|
45
|
+
@source = Source.new
|
|
46
|
+
@source.url = params[:url] if params[:url].present?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# GET /sources/1/edit
|
|
50
|
+
def edit
|
|
51
|
+
@source = Source.find(params[:id])
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# POST /sources
|
|
55
|
+
# POST /sources.xml
|
|
56
|
+
def create
|
|
57
|
+
@source = Source.new
|
|
58
|
+
create_or_update
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# PUT /sources/1
|
|
62
|
+
# PUT /sources/1.xml
|
|
63
|
+
def update
|
|
64
|
+
@source = Source.find(params[:id])
|
|
65
|
+
create_or_update
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def create_or_update
|
|
69
|
+
respond_to do |format|
|
|
70
|
+
if @source.update_attributes(params[:source])
|
|
71
|
+
format.html { redirect_to @source, notice: 'Source was successfully saved.' }
|
|
72
|
+
format.xml { render xml: @source, status: :created, location: @source }
|
|
73
|
+
else
|
|
74
|
+
format.html { render action: @source.new_record? ? "new" : "edit" }
|
|
75
|
+
format.xml { render xml: @source.errors, status: :unprocessable_entity }
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
private :create_or_update
|
|
80
|
+
|
|
81
|
+
# DELETE /sources/1
|
|
82
|
+
# DELETE /sources/1.xml
|
|
83
|
+
def destroy
|
|
84
|
+
@source = Source.find(params[:id])
|
|
85
|
+
@source.destroy
|
|
86
|
+
|
|
87
|
+
respond_to do |format|
|
|
88
|
+
format.html { redirect_to sources_url }
|
|
89
|
+
format.xml { head :ok }
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
require "calagator/duplicate_checking/controller_actions"
|
|
2
|
+
|
|
3
|
+
module Calagator
|
|
4
|
+
|
|
5
|
+
class VenuesController < ApplicationController
|
|
6
|
+
# Provides #duplicates and #squash_many_duplicates
|
|
7
|
+
include DuplicateChecking::ControllerActions
|
|
8
|
+
require_admin only: [:duplicates, :squash_many_duplicates]
|
|
9
|
+
|
|
10
|
+
# GET /venues
|
|
11
|
+
# GET /venues.xml
|
|
12
|
+
def index
|
|
13
|
+
@search = Venue::Search.new(params)
|
|
14
|
+
@venues = @search.venues
|
|
15
|
+
|
|
16
|
+
respond_to do |format|
|
|
17
|
+
format.html # index.html.erb
|
|
18
|
+
format.kml # index.kml.erb
|
|
19
|
+
format.xml { render :xml => @venues }
|
|
20
|
+
format.json { render :json => @venues, :callback => params[:callback] }
|
|
21
|
+
format.js { render :json => @venues, :callback => params[:callback] }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def autocomplete
|
|
26
|
+
@venues = Venue
|
|
27
|
+
.non_duplicates
|
|
28
|
+
.in_business
|
|
29
|
+
.where(["LOWER(title) LIKE ?", "%#{params[:term]}%".downcase])
|
|
30
|
+
.order('LOWER(title)')
|
|
31
|
+
|
|
32
|
+
respond_to do |format|
|
|
33
|
+
format.json { render :json => @venues, :callback => params[:callback] }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# GET /venues/map
|
|
38
|
+
def map
|
|
39
|
+
@venues = Venue.non_duplicates.in_business
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# GET /venues/1
|
|
43
|
+
# GET /venues/1.xml
|
|
44
|
+
def show
|
|
45
|
+
@venue = Venue.find(params[:id], include: :source)
|
|
46
|
+
|
|
47
|
+
return redirect_to @venue.duplicate_of if @venue.duplicate?
|
|
48
|
+
|
|
49
|
+
respond_to do |format|
|
|
50
|
+
format.html
|
|
51
|
+
format.xml { render xml: @venue }
|
|
52
|
+
format.json { render json: @venue, callback: params[:callback] }
|
|
53
|
+
format.ics { render ics: @venue.events.order("start_time ASC").non_duplicates }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
rescue ActiveRecord::RecordNotFound => e
|
|
57
|
+
flash[:failure] = e.to_s
|
|
58
|
+
redirect_to venues_path
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# GET /venues/new
|
|
62
|
+
# GET /venues/new.xml
|
|
63
|
+
def new
|
|
64
|
+
@venue = Venue.new
|
|
65
|
+
render layout: params[:layout] != "false"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# GET /venues/1/edit
|
|
69
|
+
def edit
|
|
70
|
+
@venue = Venue.find(params[:id])
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# POST /venues
|
|
74
|
+
# POST /venues.xml
|
|
75
|
+
def create
|
|
76
|
+
@venue = Venue.new
|
|
77
|
+
create_or_update
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# PUT /venues/1
|
|
81
|
+
# PUT /venues/1.xml
|
|
82
|
+
def update
|
|
83
|
+
@venue = Venue.find(params[:id])
|
|
84
|
+
create_or_update
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def create_or_update
|
|
88
|
+
@venue.attributes = params[:venue]
|
|
89
|
+
respond_to do |format|
|
|
90
|
+
if !evil_robot? && @venue.save
|
|
91
|
+
format.html { redirect_to from_event || @venue, flash: { success: "Venue was successfully saved." } }
|
|
92
|
+
format.xml { render xml: @venue, status: :created, location: @venue }
|
|
93
|
+
else
|
|
94
|
+
format.html { render action: @venue.new_record? ? "new" : "edit" }
|
|
95
|
+
format.xml { render xml: @venue.errors, status: :unprocessable_entity }
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# DELETE /venues/1
|
|
101
|
+
# DELETE /venues/1.xml
|
|
102
|
+
def destroy
|
|
103
|
+
@venue = Venue.find(params[:id])
|
|
104
|
+
|
|
105
|
+
if @venue.events.any?
|
|
106
|
+
message = "Cannot destroy venue that has associated events, you must reassociate all its events first."
|
|
107
|
+
respond_to do |format|
|
|
108
|
+
format.html { redirect_to @venue, flash: { failure: message } }
|
|
109
|
+
format.xml { render xml: message, status: :unprocessable_entity }
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
@venue.destroy
|
|
113
|
+
respond_to do |format|
|
|
114
|
+
format.html { redirect_to venues_path, flash: { success: %("#{@venue.title}" has been deleted) } }
|
|
115
|
+
format.xml { head :ok }
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
|
|
122
|
+
def evil_robot?
|
|
123
|
+
if params[:trap_field].present?
|
|
124
|
+
flash[:failure] = "<h3>Evil Robot</h3> We didn't save this venue because we think you're an evil robot. If you're really not an evil robot, look at the form instructions more carefully. If this doesn't work please file a bug report and let us know."
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def from_event
|
|
129
|
+
Event.find_by_id(params[:from_event])
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Calagator
|
|
2
|
+
|
|
3
|
+
class VersionsController < ApplicationController
|
|
4
|
+
def edit
|
|
5
|
+
@version = Version.find(params[:id])
|
|
6
|
+
@record = @version.next.try(:reify) || @version.item || @version.reify
|
|
7
|
+
|
|
8
|
+
singular = @record.class.name.singularize.underscore.split("/").last
|
|
9
|
+
plural = @record.class.name.pluralize.underscore.split("/").last
|
|
10
|
+
self.instance_variable_set("@#{singular}", @record)
|
|
11
|
+
|
|
12
|
+
if request.xhr?
|
|
13
|
+
render :partial => "calagator/#{plural}/form", :locals => { singular.to_sym => @record }
|
|
14
|
+
else
|
|
15
|
+
render "calagator/#{plural}/edit", :locals => { singular.to_sym => @record }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Methods added to this helper will be available to all templates in the application.
|
|
2
|
+
module Calagator
|
|
3
|
+
|
|
4
|
+
module ApplicationHelper
|
|
5
|
+
include TimeRangeHelper
|
|
6
|
+
|
|
7
|
+
# Returns HTML string of an event or venue description for display in a view.
|
|
8
|
+
def format_description(string)
|
|
9
|
+
sanitize(auto_link(upgrade_br(markdown(string))))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def markdown(text)
|
|
13
|
+
BlueCloth.new(text, :relaxed => true).to_html
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Return a HTML string with the BR tags converted to XHTML compliant markup.
|
|
17
|
+
def upgrade_br(content)
|
|
18
|
+
content.gsub('<br>','<br />')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
FLASH_TYPES = [:success, :failure]
|
|
22
|
+
|
|
23
|
+
def render_flash
|
|
24
|
+
FLASH_TYPES.map{|type|
|
|
25
|
+
next unless flash[type].present?
|
|
26
|
+
content_tag(:div, :class => "flash #{type} flash_#{type}") do
|
|
27
|
+
"#{type == :failure ? 'ERROR: ' : ''}#{flash[type]}".html_safe
|
|
28
|
+
end
|
|
29
|
+
}.compact.join.html_safe
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def datetime_format(time,format)
|
|
33
|
+
format = format.gsub(/(%[dHImU])/,'*\1')
|
|
34
|
+
time.strftime(format).gsub(/\*0*/,'').html_safe
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.source_code_version_raw
|
|
38
|
+
# Return a string describing the source code version being used
|
|
39
|
+
return "" unless system("git status 2>&1 >/dev/null")
|
|
40
|
+
" - Git timestamp: #{`git log -1 --format=format:"%ad" 2>&1`}"
|
|
41
|
+
rescue Errno::ENOENT
|
|
42
|
+
# Fail quietly if that didn't work; we don't want to get in the way.
|
|
43
|
+
""
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
Calagator::ApplicationController::SOURCE_CODE_VERSION = self.source_code_version_raw
|
|
47
|
+
|
|
48
|
+
def source_code_version
|
|
49
|
+
Calagator::ApplicationController::SOURCE_CODE_VERSION
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# returns html markup with source (if any), imported/created time, and - if modified - modified time
|
|
53
|
+
def datestamp(item)
|
|
54
|
+
stamp = "This item was "
|
|
55
|
+
if item.source.nil?
|
|
56
|
+
stamp << "added directly to #{Calagator.title}"
|
|
57
|
+
else
|
|
58
|
+
stamp << "imported from " << link_to(truncate(item.source.name, :length => 40), url_for(item.source))
|
|
59
|
+
end
|
|
60
|
+
stamp << " <br />" << content_tag(:strong, normalize_time(item.created_at, :format => :html) )
|
|
61
|
+
if item.updated_at > item.created_at
|
|
62
|
+
stamp << " and last updated <br />" << content_tag(:strong, normalize_time(item.updated_at, :format => :html) )
|
|
63
|
+
end
|
|
64
|
+
stamp << "."
|
|
65
|
+
stamp.html_safe
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Caches +block+ in view only if the +condition+ is true.
|
|
69
|
+
# http://skionrails.wordpress.com/2008/05/22/conditional-fragment-caching/
|
|
70
|
+
def cache_if(condition, name={}, &block)
|
|
71
|
+
if condition
|
|
72
|
+
cache(name, &block)
|
|
73
|
+
else
|
|
74
|
+
block.call
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Insert a chunk of +javascript+ into the page, and execute it when the document is ready.
|
|
79
|
+
def insert_javascript(javascript)
|
|
80
|
+
content_for(:javascript_insert) do
|
|
81
|
+
(<<-HERE).html_safe
|
|
82
|
+
<script>
|
|
83
|
+
$(document).ready(function() {
|
|
84
|
+
#{javascript}
|
|
85
|
+
});
|
|
86
|
+
</script>
|
|
87
|
+
HERE
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Focus cursor on DOM element specified by +xpath_query+ using JavaScript, e.g.:
|
|
92
|
+
#
|
|
93
|
+
# <% focus_on '#search_field' %>
|
|
94
|
+
def focus_on(xpath_query)
|
|
95
|
+
insert_javascript "$('#{xpath_query}').focus();"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Set the first tabindex to DOM element specified by +xpath_query+.
|
|
99
|
+
def tabindex_on(xpath_query)
|
|
100
|
+
#insert_javascript "$('#{xpath_query}')[0].tabindex = 1;"
|
|
101
|
+
#insert_javascript "$('#{xpath_query}')[0].attributes['tabindex'] = 1;"
|
|
102
|
+
# TODO Figure out how to set tabindex, because neither of these work right.
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Returns a string with safely encoded entities thanks to #h, while preserving any existing HTML entities.
|
|
106
|
+
def cleanse(string)
|
|
107
|
+
return escape_once(string)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def subnav_class_for(controller_name, action_name)
|
|
111
|
+
return [
|
|
112
|
+
"#{controller.controller_name}_#{controller.action_name}_subnav",
|
|
113
|
+
controller.controller_name == controller_name && controller.action_name == action_name ?
|
|
114
|
+
"active" :
|
|
115
|
+
nil
|
|
116
|
+
].compact.join(" ")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# String name of the mobile preference cookie's name, e.g. "calagator_mobile".
|
|
120
|
+
MOBILE_COOKIE_NAME = "#{SECRETS.session_name}_mobile"
|
|
121
|
+
|
|
122
|
+
# CGI escape a string-like object. The issue is that CGI::escape fails if used on a RailsXss SafeBuffer: https://github.com/rails/rails_xss/issues/8
|
|
123
|
+
def cgi_escape(data)
|
|
124
|
+
return CGI::escape(data.to_str)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
end
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
module Calagator
|
|
2
|
+
|
|
3
|
+
module EventsHelper
|
|
4
|
+
include TimeRangeHelper # provides normalize_time
|
|
5
|
+
|
|
6
|
+
def today_tomorrow_or_weekday(record)
|
|
7
|
+
if record.ongoing?
|
|
8
|
+
"Started #{record.start_time.strftime('%A')}"
|
|
9
|
+
else
|
|
10
|
+
record.start_time.strftime('%A')
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# calculate rowspans for an array of events
|
|
15
|
+
# argument: array of events
|
|
16
|
+
# returns: rowspans, an array in which each entry corresponds to an event in events;
|
|
17
|
+
# each entry is number of rows spanned by today_tomorrow_weekday entry, if any, to left of event
|
|
18
|
+
# entry will be > 0 for first event of day, 0 for other events
|
|
19
|
+
def calculate_rowspans(events)
|
|
20
|
+
previous_start_time = nil
|
|
21
|
+
rowspans = Array.new(events.size, 0)
|
|
22
|
+
first_event_of_day = 0
|
|
23
|
+
|
|
24
|
+
events.each_with_index do |event, index|
|
|
25
|
+
new_day = previous_start_time.nil? || (previous_start_time.to_date != event.start_time.to_date)
|
|
26
|
+
if new_day
|
|
27
|
+
first_event_of_day = index
|
|
28
|
+
end
|
|
29
|
+
rowspans[first_event_of_day] += 1
|
|
30
|
+
previous_start_time = event.start_time
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
return rowspans
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def google_maps_url(address)
|
|
37
|
+
return "http://maps.google.com/maps?q=#{cgi_escape(address)}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
#---[ Event sorting ]----------------------------------------------------
|
|
41
|
+
|
|
42
|
+
# Return a link for sorting by +key+ (e.g., "name").
|
|
43
|
+
def events_sort_link(key)
|
|
44
|
+
if key.present?
|
|
45
|
+
link_to(sorting_label_for(key, @tag.present?), url_for(params.merge(:order => key)))
|
|
46
|
+
else
|
|
47
|
+
link_to('Default', url_for(params.tap { |o| o.delete :order }))
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Return a human-readable label describing what the sorting +key+ is.
|
|
52
|
+
def events_sort_label(key)
|
|
53
|
+
if key.present? or @tag.present?
|
|
54
|
+
sanitize " by <strong>#{sorting_label_for(key, @tag.present?)}.</strong>"
|
|
55
|
+
else
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#---[ Feed links ]------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
# Returns a URL for an events feed.
|
|
63
|
+
#
|
|
64
|
+
# @param [Hash] filter Options for filtering. If values are defined, returns
|
|
65
|
+
# a link to all events. If a :query is defined, returns a link to search
|
|
66
|
+
# events' text by that query. If a :tag is defined, returns a link to search
|
|
67
|
+
# events with that tag.
|
|
68
|
+
# @param [Hash] common Options for the URL helper, such as :protocol, :format
|
|
69
|
+
# and such.
|
|
70
|
+
#
|
|
71
|
+
# @raise [ArgumentError] Raised if given invalid filter options.
|
|
72
|
+
#
|
|
73
|
+
# @return [String] URL
|
|
74
|
+
def _events_feed_linker(filter={}, common={})
|
|
75
|
+
# Delete blank filter options because this method is typically called with
|
|
76
|
+
# both a :tag and :query filter, but only one will actually be set.
|
|
77
|
+
filter.delete_if { |key, value| value.blank? }
|
|
78
|
+
|
|
79
|
+
if (unknown = filter.keys - [:query, :tag]).present?
|
|
80
|
+
raise ArgumentError, "Unknown option(s): #{unknown.inspect}"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
return filter.present? ?
|
|
84
|
+
search_events_url(common.merge(filter)) :
|
|
85
|
+
events_url(common)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
GOOGLE_EVENT_SUBSCRIBE_BASE = "http://www.google.com/calendar/render?cid="
|
|
89
|
+
|
|
90
|
+
# Returns a Google Calendar subscription URL.
|
|
91
|
+
#
|
|
92
|
+
# @see #_events_feed_linker for details on parameters and exceptions.
|
|
93
|
+
def google_events_subscription_link(filter={})
|
|
94
|
+
link = _events_feed_linker(filter, :format => "ics")
|
|
95
|
+
return "#{GOOGLE_EVENT_SUBSCRIBE_BASE}#{CGI::escape(link)}"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Returns an iCalendar subscription URL.
|
|
99
|
+
#
|
|
100
|
+
# @see #_events_feed_linker for details on parameters and exceptions.
|
|
101
|
+
def icalendar_feed_link(filter={})
|
|
102
|
+
return _events_feed_linker(filter, :protocol => "webcal", :format => "ics")
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Returns an iCalendar export URL.
|
|
106
|
+
#
|
|
107
|
+
# @see #_events_feed_linker for details on parameters and exceptions.
|
|
108
|
+
def icalendar_export_link(filter={})
|
|
109
|
+
return _events_feed_linker(filter, :format => "ics")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Returns an ATOM subscription URL.
|
|
113
|
+
#
|
|
114
|
+
# @see #_events_feed_linker for details on parameters and exceptions.
|
|
115
|
+
def atom_feed_link(filter={})
|
|
116
|
+
return _events_feed_linker(filter, :format => "atom")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
#--[ Sharing buttons ]-----------------------------------------
|
|
120
|
+
|
|
121
|
+
# Tweet button text
|
|
122
|
+
|
|
123
|
+
def tweet_text(event)
|
|
124
|
+
lengths = tweet_text_sizer(event)
|
|
125
|
+
|
|
126
|
+
result = []
|
|
127
|
+
result << "#{truncate(event.title, :length => lengths[:title])} -"
|
|
128
|
+
result << event.start_time.strftime("%I:%M%p %m.%d.%Y") # "04:00PM 08.01.2012"
|
|
129
|
+
result << "@ #{truncate(event.venue.title, :length => lengths[:venue])}" if event.venue
|
|
130
|
+
|
|
131
|
+
return result.join(" ")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Will increase the maximum length of either the event title or venue
|
|
135
|
+
# if one of the two is shorter than the maximum: 46
|
|
136
|
+
|
|
137
|
+
def tweet_text_sizer(event)
|
|
138
|
+
title_length = event.title.length
|
|
139
|
+
venue_length = (event.venue.try(:title) || "").length
|
|
140
|
+
title_length = tweet_length(title_length, venue_length)
|
|
141
|
+
venue_length = tweet_length(venue_length, title_length)
|
|
142
|
+
{ title: title_length, venue: title_length }
|
|
143
|
+
end
|
|
144
|
+
private :tweet_text_sizer
|
|
145
|
+
|
|
146
|
+
def tweet_length length_a, length_b
|
|
147
|
+
if length_a > 46
|
|
148
|
+
length_a = 46
|
|
149
|
+
length_a += (46-length_b) if length_b < 46
|
|
150
|
+
end
|
|
151
|
+
length_a
|
|
152
|
+
end
|
|
153
|
+
private :tweet_length
|
|
154
|
+
|
|
155
|
+
def shareable_event_url(event)
|
|
156
|
+
event_url(event) if event.persisted?
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
#---[ Sort labels ]-------------------------------------------
|
|
160
|
+
|
|
161
|
+
# Return the label for the +sorting_key+ (e.g. 'score'). Optionally set the
|
|
162
|
+
# +is_searching_by_tag+, to constrain options available for tag searches.
|
|
163
|
+
def sorting_label_for(sorting_key=nil, is_searching_by_tag=false)
|
|
164
|
+
sorting_key = sorting_key.to_s
|
|
165
|
+
if sorting_key.present? and SORTING_LABELS.has_key?(sorting_key)
|
|
166
|
+
SORTING_LABELS[sorting_key]
|
|
167
|
+
elsif is_searching_by_tag
|
|
168
|
+
SORTING_LABELS['date']
|
|
169
|
+
else
|
|
170
|
+
SORTING_LABELS['score']
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Labels displayed for sorting options:
|
|
175
|
+
SORTING_LABELS = {
|
|
176
|
+
'name' => 'Event Name',
|
|
177
|
+
'venue' => 'Location',
|
|
178
|
+
'score' => 'Relevance',
|
|
179
|
+
'date' => 'Date',
|
|
180
|
+
}
|
|
181
|
+
private_constant :SORTING_LABELS
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
end
|