From dc0964bfc6fce488bfcf5e91905fb5926a4c6352 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Wed, 28 Aug 2024 21:26:04 +0200 Subject: [PATCH 01/13] Add ics integration for events --- Gemfile | 3 +++ Gemfile.lock | 7 ++++++ app/controllers/events_controller.rb | 13 +++++++++-- app/models/calendar.rb | 32 ++++++++++++++++++++++++++++ app/views/events/_event.html.erb | 1 - app/views/events/_layout.html.erb | 18 ++++++++++++++++ app/views/events/index.html.erb | 28 ++++++------------------ app/views/events/show.html.erb | 5 +++++ config/initializers/mime_types.rb | 1 + config/routes.rb | 2 +- 10 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 app/models/calendar.rb create mode 100644 app/views/events/_layout.html.erb create mode 100644 app/views/events/show.html.erb create mode 100644 config/initializers/mime_types.rb diff --git a/Gemfile b/Gemfile index 20fa022..5029e0d 100644 --- a/Gemfile +++ b/Gemfile @@ -46,6 +46,9 @@ gem 'bootsnap', require: false # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] # gem "image_processing", "~> 1.2" +# Internet calendaring, Ruby style +gem 'icalendar', '~> 2.10' + group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem gem 'debug', platforms: %i[mri windows] diff --git a/Gemfile.lock b/Gemfile.lock index a4c46fc..1438552 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -97,6 +97,9 @@ GEM honeybadger (5.11.2) i18n (1.14.5) concurrent-ruby (~> 1.0) + icalendar (2.10.2) + ice_cube (~> 0.16) + ice_cube (0.17.0) io-console (0.7.2) irb (1.13.1) rdoc (>= 4.0.0) @@ -131,6 +134,8 @@ GEM nio4r (2.7.3) nokogiri (1.16.6-arm64-darwin) racc (~> 1.4) + nokogiri (1.16.6-x86_64-darwin) + racc (~> 1.4) nokogiri (1.16.6-x86_64-linux) racc (~> 1.4) pg (1.5.6) @@ -216,6 +221,7 @@ GEM PLATFORMS arm64-darwin-23 + x86_64-darwin-22 x86_64-linux DEPENDENCIES @@ -223,6 +229,7 @@ DEPENDENCIES cssbundling-rails debug honeybadger (~> 5.6) + icalendar (~> 2.10) jbuilder jsbundling-rails pg diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index 7de10e6..09488ed 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -1,12 +1,21 @@ class EventsController < ApplicationController - # GET /events or /events.json + # GET /events def index @events = Event.upcoming end + # GET /events/all or /events/all.ics def all @events = Event.all - render :index + + respond_to do |format| + format.html { render :index } + format.ics { render plain: Calendar.new(@events).to_ical} + end + end + + def show + @event = Event.find(params[:id]) end def past diff --git a/app/models/calendar.rb b/app/models/calendar.rb new file mode 100644 index 0000000..8f68222 --- /dev/null +++ b/app/models/calendar.rb @@ -0,0 +1,32 @@ +require "icalendar" + +class Calendar + def initialize(events) + @events = events + end + + def publish + calendar = Icalendar::Calendar.new + + calendar.timezone do |timezone| + timezone.tzid = "UTC" + end + + @events.each do |event| + calendar.event do |e| + e.dtstart = Icalendar::Values::DateTime.new(event.start_at.utc) + e.dtend = Icalendar::Values::DateTime.new((event.start_at + 2.hours).utc) + e.summary = event.name + e.description = event.presentation + e.location = "Toronto, Canada" # TODO: Use event.location, but it's too long for the calendar with all the details and instructions + e.url = event.rsvp_link || "https://toronto-ruby.com/events/#{event.id}" + end + end + + calendar.publish + end + + def to_ical + publish.to_ical + end +end diff --git a/app/views/events/_event.html.erb b/app/views/events/_event.html.erb index aa1fc20..b1224f5 100644 --- a/app/views/events/_event.html.erb +++ b/app/views/events/_event.html.erb @@ -50,4 +50,3 @@ - diff --git a/app/views/events/_layout.html.erb b/app/views/events/_layout.html.erb new file mode 100644 index 0000000..fd8cb3e --- /dev/null +++ b/app/views/events/_layout.html.erb @@ -0,0 +1,18 @@ +
+
+
+

+ Monthly meetups for Toronto's Ruby community +

+ +

We're a group of Ruby developers who meet up to talk about programming, the industry, and life. We're working to strengthen the local Ruby community and provide a positive space for everyone to connect.

+
+
+ <%= yield(:event_content) %> +
+
+ <%= render 'newsletter_form' %> +
+ <%= render 'supporting_companies' %> +
+
diff --git a/app/views/events/index.html.erb b/app/views/events/index.html.erb index 76bf715..e8b59d2 100644 --- a/app/views/events/index.html.erb +++ b/app/views/events/index.html.erb @@ -1,26 +1,11 @@ -
-
-
-

- Monthly meetups for Toronto's Ruby community -

+<%= content_for :event_content do %> + <%# For an upcoming event, make a "past_event" and use the partial here %> + <%# Otherwise, use the placeholder partial %> -

We're a group of Ruby developers who meet up to talk about programming, the industry, and life. We're working to strengthen the local Ruby community and provide a positive space for everyone to connect.

-
-
- <%# For an upcoming event, make a "past_event" and use the partial here %> - <%# Otherwise, use the placeholder partial %> + <%= render partial: "event", collection: @events %> - <%= render partial: "event", collection: @events %> - - -
-
- <%= render 'newsletter_form' %> -
- <%= render 'supporting_companies' %> -
-
+ +<% end %> <% content_for :page_title do %> Home @@ -30,3 +15,4 @@ Home Toronto Ruby is about building a community for Ruby users in the GTA and providing a positive space for everyone to connect, learn and grow. We're looking forward to seeing you! <% end %> +<%= render partial: "events/layout" %> diff --git a/app/views/events/show.html.erb b/app/views/events/show.html.erb new file mode 100644 index 0000000..806080e --- /dev/null +++ b/app/views/events/show.html.erb @@ -0,0 +1,5 @@ +<%= content_for :event_content do %> + <%= render partial: "event", locals: { event: @event } %> +<% end %> + +<%= render partial: "events/layout" %> diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 0000000..107f298 --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1 @@ +Mime::Type.register("text/calendar", :ics) diff --git a/config/routes.rb b/config/routes.rb index 093c4c5..51bb9f8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,5 @@ Rails.application.routes.draw do - resources :events, only: [:index] do + resources :events, only: [:index, :show] do collection do get 'past', to: 'events#past' get 'all', to: 'events#all' From 0da03883d3c7c01e6407a7271ad8b45329c5c59f Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Wed, 28 Aug 2024 22:03:37 +0200 Subject: [PATCH 02/13] Add 'Calendar' page --- .../controllers/clipboard_controller.js | 41 +++++++++++++++++++ .../controllers/hello_controller.js | 7 ---- app/javascript/controllers/index.js | 4 +- app/views/layouts/common/_navigation.html.erb | 1 + app/views/static/calendar.html.erb | 32 +++++++++++++++ config/routes.rb | 3 +- 6 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 app/javascript/controllers/clipboard_controller.js delete mode 100644 app/javascript/controllers/hello_controller.js create mode 100644 app/views/static/calendar.html.erb diff --git a/app/javascript/controllers/clipboard_controller.js b/app/javascript/controllers/clipboard_controller.js new file mode 100644 index 0000000..905c11f --- /dev/null +++ b/app/javascript/controllers/clipboard_controller.js @@ -0,0 +1,41 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = ["button", "source"] + + static values = { + successContent: String, + successDuration: { + type: Number, + default: 2000, + } + } + + connect() { + if (!this.hasButtonTarget) return + + this.originalContent = this.buttonTarget.innerHTML + } + + copy(event) { + event.preventDefault() + + const text = this.sourceTarget.innerHTML || this.sourceTarget.value + + navigator.clipboard.writeText(text).then(() => this.copied()) + } + + copied() { + if (!this.hasButtonTarget) return + + if (this.timeout) { + clearTimeout(this.timeout) + } + + this.buttonTarget.innerHTML = this.successContentValue + + this.timeout = setTimeout(() => { + this.buttonTarget.innerHTML = this.originalContent + }, this.successDurationValue) + } +} diff --git a/app/javascript/controllers/hello_controller.js b/app/javascript/controllers/hello_controller.js deleted file mode 100644 index 5975c07..0000000 --- a/app/javascript/controllers/hello_controller.js +++ /dev/null @@ -1,7 +0,0 @@ -import { Controller } from "@hotwired/stimulus" - -export default class extends Controller { - connect() { - this.element.textContent = "Hello World!" - } -} diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index d0685d3..c4d0fd2 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -4,5 +4,5 @@ import { application } from "./application" -import HelloController from "./hello_controller" -application.register("hello", HelloController) +import ClipboardController from "./clipboard_controller" +application.register("clipboard", ClipboardController) diff --git a/app/views/layouts/common/_navigation.html.erb b/app/views/layouts/common/_navigation.html.erb index cf99794..9ea03f9 100644 --- a/app/views/layouts/common/_navigation.html.erb +++ b/app/views/layouts/common/_navigation.html.erb @@ -6,6 +6,7 @@ Propose a talk <% end %> <%= link_to 'About', about_path %> + <%= link_to 'Calendar', calendar_path %> <%= link_to 'https://www.youtube.com/@TorontoRuby', class: 'flex gap-1 justify-center items-center' do %> Youtube <% end %> diff --git a/app/views/static/calendar.html.erb b/app/views/static/calendar.html.erb new file mode 100644 index 0000000..56f817f --- /dev/null +++ b/app/views/static/calendar.html.erb @@ -0,0 +1,32 @@ +
+
+
+

+ Icalendar Integration +

+ +

+ Add the Toronto Ruby events as a calendar subscription to your own calendar. +

+ +

+ Copy the following URL and import the calendar: +

+ +
+ + +
+
+
+
+ +<% content_for :page_title do %> +Calendar +<% end %> + +<% content_for :page_description do %> +Add the Toronto Ruby events as a calendar subscription to your own calendar. +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 51bb9f8..785675d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,7 @@ resources :events, only: [:index, :show] do collection do get 'past', to: 'events#past' - get 'all', to: 'events#all' + get 'all', to: 'events#all', as: :all get 'next', to: 'events#next' end end @@ -25,4 +25,5 @@ get 'past_events', to: redirect('/events/past') get 'chat', to: 'static#chat' get 'about', to: 'static#about' + get 'calendar', to: 'static#calendar' end From 7d13925879fd7429ad3d0f266dc508744826eb05 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Sun, 1 Sep 2024 00:51:49 +0200 Subject: [PATCH 03/13] Use `America/Toronto` timezone and add test for it --- .github/workflows/tests.yml | 37 ++++++++++++++++++++++ app/models/calendar.rb | 24 ++++++++++++-- config/database.yml | 5 +++ test/controllers/events_controller_test.rb | 25 +++++++++++++++ test/test_helper.rb | 15 +++++++++ 5 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/tests.yml create mode 100644 test/controllers/events_controller_test.rb create mode 100644 test/test_helper.rb diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..ccfb2ad --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,37 @@ +name: Tests + +on: [push, pull_request] + +jobs: + tests: + runs-on: ubuntu-latest + name: Tests + + services: + postgres: + image: postgres:15.0-alpine + + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + + ports: + - 5432:5432 + + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + + - name: Setup Test Database + run: bundle exec rails db:setup + env: + RAILS_ENV: test + + - name: Run tests + run: bundle exec rails test diff --git a/app/models/calendar.rb b/app/models/calendar.rb index 8f68222..8707d30 100644 --- a/app/models/calendar.rb +++ b/app/models/calendar.rb @@ -9,13 +9,13 @@ def publish calendar = Icalendar::Calendar.new calendar.timezone do |timezone| - timezone.tzid = "UTC" + timezone.tzid = timezone_identifier end @events.each do |event| calendar.event do |e| - e.dtstart = Icalendar::Values::DateTime.new(event.start_at.utc) - e.dtend = Icalendar::Values::DateTime.new((event.start_at + 2.hours).utc) + e.dtstart = ical_time(event.start_at) + e.dtend = ical_time(event.start_at + 2.hours) e.summary = event.name e.description = event.presentation e.location = "Toronto, Canada" # TODO: Use event.location, but it's too long for the calendar with all the details and instructions @@ -29,4 +29,22 @@ def publish def to_ical publish.to_ical end + + private + + def timezone_identifier + "America/Toronto" + end + + def timezone + @timezone ||= TZInfo::Timezone.get(timezone_identifier) + end + + def ical_timezone + timezone.ical_timezone(timezone.now) + end + + def ical_time(datetime) + Icalendar::Values::DateTime.new(datetime, tzid: timezone_identifier) + end end diff --git a/config/database.yml b/config/database.yml index d1f45d0..2bf56ed 100644 --- a/config/database.yml +++ b/config/database.yml @@ -56,6 +56,11 @@ development: test: <<: *default database: site_v2_test + username: postgres + password: postgres + port: 5432 + host: localhost + encoding: utf8 # As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is diff --git a/test/controllers/events_controller_test.rb b/test/controllers/events_controller_test.rb new file mode 100644 index 0000000..a3c7bf1 --- /dev/null +++ b/test/controllers/events_controller_test.rb @@ -0,0 +1,25 @@ +require "test_helper" + +class EventsControllerTest < ActionController::TestCase + def setup + begining = Date.parse("2024-01-01").beginning_of_year + dates = 12.times.map { |i| begining + i.months + rand(1..10).days } + @events = dates.map { |date| Event.create!(start_at: date, name: "Toronto.rb #{date.strftime("%B %Y")}", location: "Toronto, Canada", presentation: "Presentation #{date}") } + end + + test "all events in ics format" do + get :all, format: :ics + assert_response :success + assert_equal "text/calendar; charset=utf-8", response.content_type + + calendar = Icalendar::Calendar.parse(response.body).first + events = calendar.events + + assert_equal 12, events.count + assert_equal @events.map(&:start_at).map(&:to_date).sort, events.map(&:dtstart).map(&:to_date).sort + assert_equal @events.map(&:start_at).map { |date| "Toronto.rb #{date.strftime("%B %Y")}" }, events.map(&:summary) + assert_equal @events.map(&:id).map { |id| "https://toronto-ruby.com/events/#{id}" }, events.map(&:url).map(&:to_s) + assert_equal ["Toronto, Canada"], events.map(&:location).uniq + assert_equal ["EST", "EST", "EST", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EST", "EST"], events.map(&:dtstart).map(&:zone) + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..62f75b9 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,15 @@ +ENV["RAILS_ENV"] ||= "test" +require_relative "../config/environment" +require "rails/test_help" + +module ActiveSupport + class TestCase + # Run tests in parallel with specified workers + parallelize(workers: :number_of_processors) + + # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. + # fixtures :all + + # Add more helper methods to be used by all tests here... + end +end From bcf97814ed7f6828001ba2c3fa402fc79e21f197 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Sun, 1 Sep 2024 01:02:24 +0200 Subject: [PATCH 04/13] Use fake credentials for admin controllers in test --- app/controllers/admin/base_controller.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index ca5079d..a457645 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -1,6 +1,8 @@ module Admin class BaseController < ApplicationController - http_basic_authenticate_with name: Rails.application.credentials.auth.user, - password: Rails.application.credentials.auth.password + http_basic_authenticate_with( + name: Rails.env.test? ? "admin" : Rails.application.credentials.auth.user, + password: Rails.env.test? ? "admin" : Rails.application.credentials.auth.password + ) end end From 0a366ce41db9989dd7eaf8c0a18234c6cac7095c Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Sun, 1 Sep 2024 01:05:24 +0200 Subject: [PATCH 05/13] Destroy all events before EventsControllerTest --- test/controllers/events_controller_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/controllers/events_controller_test.rb b/test/controllers/events_controller_test.rb index a3c7bf1..0fa81a3 100644 --- a/test/controllers/events_controller_test.rb +++ b/test/controllers/events_controller_test.rb @@ -2,6 +2,7 @@ class EventsControllerTest < ActionController::TestCase def setup + Event.destroy_all begining = Date.parse("2024-01-01").beginning_of_year dates = 12.times.map { |i| begining + i.months + rand(1..10).days } @events = dates.map { |date| Event.create!(start_at: date, name: "Toronto.rb #{date.strftime("%B %Y")}", location: "Toronto, Canada", presentation: "Presentation #{date}") } From 04c176a1a48c1cbdf619290e32a4128cfd99ac2b Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Tue, 3 Sep 2024 22:51:01 +0200 Subject: [PATCH 06/13] Add Slugs --- app/controllers/events_controller.rb | 2 +- app/models/event.rb | 4 ++++ config/routes.rb | 2 +- db/migrate/20240903203347_add_slug_to_event.rb | 7 +++++++ db/schema.rb | 2 ++ 5 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20240903203347_add_slug_to_event.rb diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index 09488ed..d64a1d6 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -15,7 +15,7 @@ def all end def show - @event = Event.find(params[:id]) + @event = Event.find_by(slug: params[:slug]) end def past diff --git a/app/models/event.rb b/app/models/event.rb index 7535e46..e89100d 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -13,4 +13,8 @@ def start_time def self.statuses_for_select statuses.map { |k, _v| [k.titleize, k] } end + + def to_param + slug + end end diff --git a/config/routes.rb b/config/routes.rb index 785675d..ee7fa6b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,5 @@ Rails.application.routes.draw do - resources :events, only: [:index, :show] do + resources :events, only: [:index, :show], param: :slug do collection do get 'past', to: 'events#past' get 'all', to: 'events#all', as: :all diff --git a/db/migrate/20240903203347_add_slug_to_event.rb b/db/migrate/20240903203347_add_slug_to_event.rb new file mode 100644 index 0000000..ad53039 --- /dev/null +++ b/db/migrate/20240903203347_add_slug_to_event.rb @@ -0,0 +1,7 @@ +class AddSlugToEvent < ActiveRecord::Migration[7.1] + def change + add_column :events, :slug, :string, null: false, as: %(lower(regexp_replace(regexp_replace(name, '\s+', '-', 'g'), '[^a-zA-Z0-9\-]', '', 'g'))), stored: true + + add_index :events, :slug, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index fa5f7a0..8dd7b3f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -27,6 +27,8 @@ t.datetime "start_at", precision: nil t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.virtual "slug", type: :string, null: false, as: "lower(regexp_replace(regexp_replace((name)::text, ' +'::text, '-'::text, 'g'::text), '[^a-zA-Z0-9-]'::text, ''::text, 'g'::text))", stored: true + t.index ["slug"], name: "index_events_on_slug", unique: true end end From 6463af2ae3e87a5a4c819da0d1ed7a57857ee225 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Tue, 3 Sep 2024 22:51:31 +0200 Subject: [PATCH 07/13] Add city column to event --- app/models/calendar.rb | 38 +++++++++++++++++-- config/environments/development.rb | 2 + config/environments/production.rb | 2 + .../20240903202825_add_city_to_event.rb | 5 +++ db/schema.rb | 3 +- 5 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20240903202825_add_city_to_event.rb diff --git a/app/models/calendar.rb b/app/models/calendar.rb index 8707d30..8879632 100644 --- a/app/models/calendar.rb +++ b/app/models/calendar.rb @@ -1,6 +1,8 @@ require "icalendar" class Calendar + include Rails.application.routes.url_helpers + def initialize(events) @events = events end @@ -16,10 +18,38 @@ def publish calendar.event do |e| e.dtstart = ical_time(event.start_at) e.dtend = ical_time(event.start_at + 2.hours) - e.summary = event.name - e.description = event.presentation - e.location = "Toronto, Canada" # TODO: Use event.location, but it's too long for the calendar with all the details and instructions - e.url = event.rsvp_link || "https://toronto-ruby.com/events/#{event.id}" + e.summary = "Toronto Ruby - #{event.name}" + e.location = event.city + e.url = event.rsvp_link || event_url(event) + + sponsor = event.sponsor ? <<~SPONSOR : nil + Sponsor: + #{event.sponsor} (#{event.sponsor_link}) + SPONSOR + + rsvp_link = event.rsvp_link ? <<~RSVP : nil + RSVP: + #{event.rsvp_link} + RSVP + + e.description = <<~DESCRIPTION + Toronto Ruby - #{event.name} + + Location: + #{event.location} + + Presenter: + #{event.presenter} + + Presentation: + #{event.presentation} + + Event-Site: + #{event_url(event)} + + #{rsvp_link} + #{sponsor} + DESCRIPTION end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 2e7fb48..645becb 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,5 +1,7 @@ require "active_support/core_ext/integer/time" +Rails.application.default_url_options = { host: "localhost", protocol: "http", port: 3000 } + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. diff --git a/config/environments/production.rb b/config/environments/production.rb index 5759cb1..51fde67 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,5 +1,7 @@ require "active_support/core_ext/integer/time" +Rails.application.default_url_options = { host: "toronto-ruby.com", protocol: "https" } + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. diff --git a/db/migrate/20240903202825_add_city_to_event.rb b/db/migrate/20240903202825_add_city_to_event.rb new file mode 100644 index 0000000..509b46c --- /dev/null +++ b/db/migrate/20240903202825_add_city_to_event.rb @@ -0,0 +1,5 @@ +class AddCityToEvent < ActiveRecord::Migration[7.1] + def change + add_column :events, :city, :string, null: false, default: "Toronto, Canada" + end +end diff --git a/db/schema.rb b/db/schema.rb index 8dd7b3f..058a076 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_06_13_220002) do +ActiveRecord::Schema[7.1].define(version: 2024_09_03_203347) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -27,6 +27,7 @@ t.datetime "start_at", precision: nil t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "city", default: "Toronto, Canada", null: false t.virtual "slug", type: :string, null: false, as: "lower(regexp_replace(regexp_replace((name)::text, ' +'::text, '-'::text, 'g'::text), '[^a-zA-Z0-9-]'::text, ''::text, 'g'::text))", stored: true t.index ["slug"], name: "index_events_on_slug", unique: true end From 6a787479ae1273f35824c62c5669023c4ef989db Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Tue, 3 Sep 2024 22:59:24 +0200 Subject: [PATCH 08/13] Update tests --- config/environments/test.rb | 2 ++ test/controllers/events_controller_test.rb | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/environments/test.rb b/config/environments/test.rb index 0dda9f9..0aca27f 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -5,6 +5,8 @@ # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! +Rails.application.default_url_options = { host: "test-env.toronto-ruby.com", protocol: "http", port: 3000 } + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. diff --git a/test/controllers/events_controller_test.rb b/test/controllers/events_controller_test.rb index 0fa81a3..904543b 100644 --- a/test/controllers/events_controller_test.rb +++ b/test/controllers/events_controller_test.rb @@ -5,7 +5,7 @@ def setup Event.destroy_all begining = Date.parse("2024-01-01").beginning_of_year dates = 12.times.map { |i| begining + i.months + rand(1..10).days } - @events = dates.map { |date| Event.create!(start_at: date, name: "Toronto.rb #{date.strftime("%B %Y")}", location: "Toronto, Canada", presentation: "Presentation #{date}") } + @events = dates.map { |date| Event.create!(start_at: date, name: "Event #{date.strftime("%B %Y")}", location: "Some Office", city: "Toronto, Canada", presentation: "Presentation #{date}") } end test "all events in ics format" do @@ -18,8 +18,8 @@ def setup assert_equal 12, events.count assert_equal @events.map(&:start_at).map(&:to_date).sort, events.map(&:dtstart).map(&:to_date).sort - assert_equal @events.map(&:start_at).map { |date| "Toronto.rb #{date.strftime("%B %Y")}" }, events.map(&:summary) - assert_equal @events.map(&:id).map { |id| "https://toronto-ruby.com/events/#{id}" }, events.map(&:url).map(&:to_s) + assert_equal @events.map(&:start_at).map { |date| "Toronto Ruby - Event #{date.strftime("%B %Y")}" }, events.map(&:summary) + assert_equal @events.map(&:slug).map { |slug| "http://test-env.toronto-ruby.com:3000/events/#{slug}" }, events.map(&:url).map(&:to_s) assert_equal ["Toronto, Canada"], events.map(&:location).uniq assert_equal ["EST", "EST", "EST", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EST", "EST"], events.map(&:dtstart).map(&:zone) end From 48262e7ae28ee49ff877e369172ae3fb7484d68f Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Tue, 3 Sep 2024 23:00:20 +0200 Subject: [PATCH 09/13] format --- app/controllers/events_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index d64a1d6..9b4365e 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -10,7 +10,7 @@ def all respond_to do |format| format.html { render :index } - format.ics { render plain: Calendar.new(@events).to_ical} + format.ics { render plain: Calendar.new(@events).to_ical } end end From 73433ddc38ae8d104002c5e2537cb4c186e8ee51 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Tue, 3 Sep 2024 23:02:44 +0200 Subject: [PATCH 10/13] Link to event show page --- app/views/events/_event.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/events/_event.html.erb b/app/views/events/_event.html.erb index b1224f5..daee5d8 100644 --- a/app/views/events/_event.html.erb +++ b/app/views/events/_event.html.erb @@ -2,7 +2,7 @@ <% future = Time.zone.now < event.start_at %>
-

<%= event.name %>

+

<%= link_to event.name, event %>

<%= event.start_time %>

<%= simple_format(event.location) %> From 2b92d701660a0192abacc274b3500be4938f186f Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Tue, 3 Sep 2024 23:07:07 +0200 Subject: [PATCH 11/13] Only show published events in /all --- app/controllers/events_controller.rb | 2 +- test/controllers/events_controller_test.rb | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index 9b4365e..3852a46 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -6,7 +6,7 @@ def index # GET /events/all or /events/all.ics def all - @events = Event.all + @events = Event.published respond_to do |format| format.html { render :index } diff --git a/test/controllers/events_controller_test.rb b/test/controllers/events_controller_test.rb index 904543b..dc63fa2 100644 --- a/test/controllers/events_controller_test.rb +++ b/test/controllers/events_controller_test.rb @@ -5,7 +5,7 @@ def setup Event.destroy_all begining = Date.parse("2024-01-01").beginning_of_year dates = 12.times.map { |i| begining + i.months + rand(1..10).days } - @events = dates.map { |date| Event.create!(start_at: date, name: "Event #{date.strftime("%B %Y")}", location: "Some Office", city: "Toronto, Canada", presentation: "Presentation #{date}") } + @events = dates.map { |date| Event.create!(start_at: date, name: "Event #{date.strftime("%B %Y")}", location: "Some Office", city: "Toronto, Canada", presentation: "Presentation #{date}", status: :published) } end test "all events in ics format" do @@ -23,4 +23,17 @@ def setup assert_equal ["Toronto, Canada"], events.map(&:location).uniq assert_equal ["EST", "EST", "EST", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EST", "EST"], events.map(&:dtstart).map(&:zone) end + + test "shouldn't show draft events" do + Event.update_all(status: :draft) + + get :all, format: :ics + assert_response :success + assert_equal "text/calendar; charset=utf-8", response.content_type + + calendar = Icalendar::Calendar.parse(response.body).first + events = calendar.events + + assert_equal 0, events.count + end end From 12025b6bb29384493faafb8a7952cd345acf6fa3 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Wed, 4 Sep 2024 16:29:47 +0200 Subject: [PATCH 12/13] Fix tests --- test/controllers/events_controller_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/controllers/events_controller_test.rb b/test/controllers/events_controller_test.rb index dc63fa2..92cc806 100644 --- a/test/controllers/events_controller_test.rb +++ b/test/controllers/events_controller_test.rb @@ -4,7 +4,7 @@ class EventsControllerTest < ActionController::TestCase def setup Event.destroy_all begining = Date.parse("2024-01-01").beginning_of_year - dates = 12.times.map { |i| begining + i.months + rand(1..10).days } + dates = 12.times.map { |i| begining + i.months } @events = dates.map { |date| Event.create!(start_at: date, name: "Event #{date.strftime("%B %Y")}", location: "Some Office", city: "Toronto, Canada", presentation: "Presentation #{date}", status: :published) } end @@ -21,7 +21,7 @@ def setup assert_equal @events.map(&:start_at).map { |date| "Toronto Ruby - Event #{date.strftime("%B %Y")}" }, events.map(&:summary) assert_equal @events.map(&:slug).map { |slug| "http://test-env.toronto-ruby.com:3000/events/#{slug}" }, events.map(&:url).map(&:to_s) assert_equal ["Toronto, Canada"], events.map(&:location).uniq - assert_equal ["EST", "EST", "EST", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EST", "EST"], events.map(&:dtstart).map(&:zone) + assert_equal ["EST", "EST", "EST", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EDT", "EST"], events.map(&:dtstart).map(&:zone) end test "shouldn't show draft events" do From e426f6d054312604544ccd1db0713696ac4fa920 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Wed, 4 Sep 2024 17:12:03 +0200 Subject: [PATCH 13/13] Order events by start_at --- app/controllers/events_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index 3852a46..f7b2e95 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -10,7 +10,7 @@ def all respond_to do |format| format.html { render :index } - format.ics { render plain: Calendar.new(@events).to_ical } + format.ics { render plain: Calendar.new(@events.order(start_at: :asc)).to_ical } end end