diff --git a/Gemfile b/Gemfile index ae38ebd..7435644 100644 --- a/Gemfile +++ b/Gemfile @@ -65,3 +65,5 @@ group :test do gem "capybara" gem "selenium-webdriver" end + +gem "icalendar", "~> 2.10" diff --git a/Gemfile.lock b/Gemfile.lock index 4096fda..b1800b7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -105,6 +105,9 @@ GEM activesupport (>= 6.1) i18n (1.14.1) concurrent-ruby (~> 1.0) + icalendar (2.10.1) + ice_cube (~> 0.16) + ice_cube (0.16.4) importmap-rails (2.0.1) actionpack (>= 6.0.0) activesupport (>= 6.0.0) @@ -262,6 +265,7 @@ DEPENDENCIES bootsnap capybara debug + icalendar (~> 2.10) importmap-rails jbuilder puma (>= 5.0) diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index 007bdb3..53ee762 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -6,6 +6,15 @@ def index @events = Event.all end + def import + files = params[:ics_files].reject(&:blank?) + files.each do |file| + Event.create_from_ics(file) + end + + redirect_to events_path, notice: "Events imported!" + end + # GET /events/1 or /events/1.json def show end diff --git a/app/models/event.rb b/app/models/event.rb index f21036b..9d4ae0b 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,2 +1,15 @@ class Event < ApplicationRecord + def self.create_from_ics(file_path) + file = File.open(file_path) + calendars = Icalendar::Calendar.parse(file) + event = calendars.first.events.first + Event.create( + starts_at: event.dtstart, + ends_at: event.dtend, + location: event.location, + summary: event.summary.strip, + description: event.description, + url: event.url + ) + end end diff --git a/app/views/events/index.html.erb b/app/views/events/index.html.erb index 9cac572..046eafb 100644 --- a/app/views/events/index.html.erb +++ b/app/views/events/index.html.erb @@ -1,5 +1,10 @@

<%= notice %>

+<%= form_with url: import_events_path, method: :post do |form| %> + <%= form.file_field :ics_files, multiple: true %> + <%= form.submit %> +<% end %> +

Events

diff --git a/config/routes.rb b/config/routes.rb index aaffdbe..453d88b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,9 @@ Rails.application.routes.draw do - resources :events + resources :events do + collection do + post :import + end + end # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. diff --git a/test/fixtures/files/Sunday+morning+yoga+in+Antibes+.ics b/test/fixtures/files/Sunday+morning+yoga+in+Antibes+.ics new file mode 100644 index 0000000..0cde37e --- /dev/null +++ b/test/fixtures/files/Sunday+morning+yoga+in+Antibes+.ics @@ -0,0 +1,49 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Meetup//RemoteApi//EN +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-ORIGINAL-URL:https://www.meetup.com/englishspeakingyoganiceantibes/even + ts/299417408/ical/Sunday+morning+yoga+in+Antibes+.ics +X-WR-CALNAME:Events - Sunday morning yoga in Antibes .ics +X-MS-OLK-FORCEINSPECTOROPEN:TRUE +BEGIN:VTIMEZONE +TZID:Europe/Paris +TZURL:http://tzurl.org/zoneinfo-outlook/Europe/Paris +X-LIC-LOCATION:Europe/Paris +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTAMP:20240302T205200Z +DTSTART;TZID=Europe/Paris:20240303T103000 +DTEND;TZID=Europe/Paris:20240303T113000 +STATUS:CONFIRMED +SUMMARY:Sunday morning yoga in Antibes +DESCRIPTION:English Yoga | Nice/Antibes/Monaco\nSunday\, March 3 at 10:30 + AM\n\nJoin us for some yoga on Sunday morning in Antibes! 🌞✨Accessible + to all levels of experience 🙏🏻Price: 15€\n\nhttps://www.meetup.com/en + glishspeakingyoganiceantibes/events/299417408/ +CLASS:PUBLIC +CREATED:20240225T133601Z +GEO:43.70;7.26 +LOCATION:Plage de la Gravette\, Antibes (Small beach behind Port Vauban\, + Antibes\, France) +URL:https://www.meetup.com/englishspeakingyoganiceantibes/events/29941740 + 8/ +LAST-MODIFIED:20240225T133630Z +UID:event_299417408@meetup.com +END:VEVENT +END:VCALENDAR diff --git a/test/fixtures/files/Wednesday+5+km+or+more.ics b/test/fixtures/files/Wednesday+5+km+or+more.ics new file mode 100644 index 0000000..b2b52c2 --- /dev/null +++ b/test/fixtures/files/Wednesday+5+km+or+more.ics @@ -0,0 +1,48 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Meetup//RemoteApi//EN +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-ORIGINAL-URL:https://www.meetup.com/nice-runners/events/299443075/ical/ + Wednesday+5+km+or+more.ics +X-WR-CALNAME:Events - Wednesday 5 km or more.ics +X-MS-OLK-FORCEINSPECTOROPEN:TRUE +BEGIN:VTIMEZONE +TZID:Europe/Paris +TZURL:http://tzurl.org/zoneinfo-outlook/Europe/Paris +X-LIC-LOCATION:Europe/Paris +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTAMP:20240302T205210Z +DTSTART;TZID=Europe/Paris:20240304T193000 +DTEND;TZID=Europe/Paris:20240304T210000 +STATUS:CONFIRMED +SUMMARY:Wednesday 5 km or more +DESCRIPTION:Nice Runners\nMonday\, March 4 at 7:30 PM\n\nwe meet and run + 5 to 10 km. in the group there are different speeds and different levels + of preparation and everyone makes the distance they feel. in ...\n\nhtt + ps://www.meetup.com/nice-runners/events/299443075/ +CLASS:PUBLIC +CREATED:20240226T173204Z +GEO:43.70;7.26 +LOCATION:Ma Nolan's Irish Pub at - Vieux\, Nice (2 Rue Saint François De + Paule (Cours Saleya)\, Nice\, France) +URL:https://www.meetup.com/nice-runners/events/299443075/ +LAST-MODIFIED:20240226T173204Z +UID:event_jlvnktygcfbgb@meetup.com +END:VEVENT +END:VCALENDAR diff --git a/test/models/event_test.rb b/test/models/event_test.rb index c8465c1..45e8edb 100644 --- a/test/models/event_test.rb +++ b/test/models/event_test.rb @@ -1,7 +1,9 @@ require "test_helper" class EventTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end + test "create_from_ics" do + file_path = "test/fixtures/files/Sunday+morning+yoga+in+Antibes+.ics" + event = Event.create_from_ics(file_path) + assert_equal "Sunday morning yoga in Antibes", event.summary + end end