From 9b10cc12d2c73e32c8f22fda1c0cb9e54ccd6f17 Mon Sep 17 00:00:00 2001 From: Malaber Date: Mon, 4 May 2026 14:43:20 +0200 Subject: [PATCH] feat(tournaments): add metadata fields Add typed tournament metadata to API payloads and follower sync. --- app/controllers/tournaments_controller.rb | 1 + app/models/tournament.rb | 18 +++++ .../simple_tournament_serializer.rb | 10 ++- app/services/tournament_snapshot_builder.rb | 2 + app/services/tournament_snapshot_importer.rb | 6 ++ app/services/tournament_sync_schema.rb | 6 ++ ...60504100000_add_metadata_to_tournaments.rb | 14 ++++ db/schema.rb | 8 +- .../tournaments_controller_spec.rb | 79 +++++++++++++++++++ spec/e2e/http/api_surface_spec.rb | 30 +++++++ spec/e2e/http/tournament_follow_sync_spec.rb | 30 +++++++ spec/e2e/http/tournament_sync_test_spec.rb | 14 +++- .../tournament_snapshot_importer_spec.rb | 18 +++++ 13 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20260504100000_add_metadata_to_tournaments.rb diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index f878c77..5d05a5f 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -285,6 +285,7 @@ class TournamentsController < ApplicationController params.slice( :name, :description, :public, :teams, :group_stage, :playoff_teams_amount, :instant_finalists_amount, :intermediate_round_participants_amount, + :location, :starts_at, :ends_at, :organizer_name, :contact_email, :website_url, :read_only_mode, :sync_target_url, :sync_auth_token ).permit! end diff --git a/app/models/tournament.rb b/app/models/tournament.rb index 4063d27..2b2f2d8 100644 --- a/app/models/tournament.rb +++ b/app/models/tournament.rb @@ -6,6 +6,7 @@ require 'openssl' class Tournament < ApplicationRecord TIMER_MODES = %w[countdown countup].freeze TIMER_REASONS = %w[tournament_start playoff_start match_end custom].freeze + METADATA_STRING_ATTRIBUTES = %i[location organizer_name contact_email website_url].freeze belongs_to :user belongs_to :owner, class_name: 'User', foreign_key: :user_id @@ -20,14 +21,18 @@ class Tournament < ApplicationRecord validates :timer_mode, inclusion: { in: TIMER_MODES }, allow_nil: true validates :timer_reason, inclusion: { in: TIMER_REASONS }, allow_nil: true validates :sync_target_url, format: URI::DEFAULT_PARSER.make_regexp(%w[http https]), allow_blank: true + validates :website_url, format: URI::DEFAULT_PARSER.make_regexp(%w[http https]), allow_blank: true + validates :contact_email, format: URI::MailTo::EMAIL_REGEXP, allow_blank: true validate :sync_configuration_is_complete validate :playoff_teams_amount_is_positive_power_of_two validate :timer_reason_text_matches_reason + validate :ends_at_is_after_starts_at after_initialize :generate_code after_create_commit :ensure_default_beamer! before_validation :normalize_timer_reason + before_validation :normalize_metadata before_validation :protect_follower_sync_token before_validation :clear_follower_sync_token_when_disabling_read_only_mode after_commit :broadcast_timer_state_change, if: :saved_change_to_timer_state? @@ -154,6 +159,19 @@ class Tournament < ApplicationRecord end end + def normalize_metadata + METADATA_STRING_ATTRIBUTES.each do |attribute| + self[attribute] = self[attribute]&.strip&.presence + end + end + + def ends_at_is_after_starts_at + return if starts_at.blank? || ends_at.blank? + return if ends_at > starts_at + + errors.add(:ends_at, 'must be after starts_at') + end + def saved_change_to_timer_state? saved_change_to_timestamp? || saved_change_to_timer_mode? || diff --git a/app/serializers/simple_tournament_serializer.rb b/app/serializers/simple_tournament_serializer.rb index 0d88639..6bb26e4 100644 --- a/app/serializers/simple_tournament_serializer.rb +++ b/app/serializers/simple_tournament_serializer.rb @@ -1,5 +1,13 @@ # frozen_string_literal: true class SimpleTournamentSerializer < ApplicationSerializer - attributes :name, :code, :public + attributes :name, :code, :public, :location, :organizer_name, :contact_email, :website_url + + attribute :starts_at do + object.starts_at&.iso8601 + end + + attribute :ends_at do + object.ends_at&.iso8601 + end end diff --git a/app/services/tournament_snapshot_builder.rb b/app/services/tournament_snapshot_builder.rb index 0975a78..148c76e 100644 --- a/app/services/tournament_snapshot_builder.rb +++ b/app/services/tournament_snapshot_builder.rb @@ -22,6 +22,8 @@ class TournamentSnapshotBuilder def build payload = tournament.attributes.symbolize_keys.slice(*ROOT_ATTRIBUTES) + payload[:starts_at] = tournament.starts_at&.iso8601 + payload[:ends_at] = tournament.ends_at&.iso8601 payload[:timestamp] = tournament.timestamp&.iso8601 payload[:timer_mode] = tournament.timer_mode payload[:timer_reason] = tournament.timer_reason diff --git a/app/services/tournament_snapshot_importer.rb b/app/services/tournament_snapshot_importer.rb index c2868da..0b443f3 100644 --- a/app/services/tournament_snapshot_importer.rb +++ b/app/services/tournament_snapshot_importer.rb @@ -6,6 +6,10 @@ class TournamentSnapshotImporter code description public + location + organizer_name + contact_email + website_url playoff_teams_amount instant_finalists_amount intermediate_round_participants_amount @@ -67,6 +71,8 @@ class TournamentSnapshotImporter def update_tournament! root_attrs = snapshot.slice(*ROOT_ATTRIBUTES) root_attrs[:code] = tournament.code if code_taken_by_another_tournament?(root_attrs[:code]) + root_attrs[:starts_at] = parse_time(snapshot[:starts_at]) + root_attrs[:ends_at] = parse_time(snapshot[:ends_at]) root_attrs[:timestamp] = parse_time(snapshot[:timestamp]) root_attrs[:timer_mode] = snapshot[:timer_mode] root_attrs[:timer_reason] = snapshot[:timer_reason] diff --git a/app/services/tournament_sync_schema.rb b/app/services/tournament_sync_schema.rb index ee0a9ac..7c9f436 100644 --- a/app/services/tournament_sync_schema.rb +++ b/app/services/tournament_sync_schema.rb @@ -9,6 +9,12 @@ class TournamentSyncSchema code description public + location + starts_at + ends_at + organizer_name + contact_email + website_url playoff_teams_amount instant_finalists_amount intermediate_round_participants_amount diff --git a/db/migrate/20260504100000_add_metadata_to_tournaments.rb b/db/migrate/20260504100000_add_metadata_to_tournaments.rb new file mode 100644 index 0000000..5d10c4e --- /dev/null +++ b/db/migrate/20260504100000_add_metadata_to_tournaments.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class AddMetadataToTournaments < ActiveRecord::Migration[7.0] + def change + change_table :tournaments, bulk: true do |t| + t.string :location + t.datetime :starts_at + t.datetime :ends_at + t.string :organizer_name + t.string :contact_email + t.string :website_url + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 773e654..766e949 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[8.1].define(version: 2026_04_30_121000) do +ActiveRecord::Schema[8.1].define(version: 2026_05_04_100000) do create_table "beamers", force: :cascade do |t| t.json "config", default: {}, null: false t.datetime "created_at", null: false @@ -163,14 +163,19 @@ ActiveRecord::Schema[8.1].define(version: 2026_04_30_121000) do create_table "tournaments", force: :cascade do |t| t.string "code", null: false + t.string "contact_email" t.datetime "created_at", precision: nil, null: false t.string "description" + t.datetime "ends_at" t.integer "instant_finalists_amount", default: 0 t.integer "intermediate_round_participants_amount", default: 0 + t.string "location" t.string "name", null: false + t.string "organizer_name" t.integer "playoff_teams_amount", default: 0 t.boolean "public", default: true t.boolean "read_only_mode", default: false, null: false + t.datetime "starts_at" t.string "sync_auth_token" t.string "sync_auth_token_digest" t.datetime "sync_last_imported_snapshot_at" @@ -184,6 +189,7 @@ ActiveRecord::Schema[8.1].define(version: 2026_04_30_121000) do t.datetime "timestamp" t.datetime "updated_at", precision: nil, null: false t.integer "user_id", null: false + t.string "website_url" t.index ["code"], name: "index_tournaments_on_code", unique: true t.index ["user_id"], name: "index_tournaments_on_user_id" end diff --git a/spec/controllers/tournaments_controller_spec.rb b/spec/controllers/tournaments_controller_spec.rb index 4f396b3..fdbc7d2 100644 --- a/spec/controllers/tournaments_controller_spec.rb +++ b/spec/controllers/tournaments_controller_spec.rb @@ -105,6 +105,7 @@ RSpec.describe TournamentsController, type: :controller do expected_keys = %i[ id name code public description playoff_teams_amount instant_finalists_amount intermediate_round_participants_amount + location starts_at ends_at organizer_name contact_email website_url timestamp timer_mode timer_reason timer_reason_text owner_username stages teams team_action_lists ] expect(json.keys).to match_array(expected_keys) @@ -407,6 +408,29 @@ RSpec.describe TournamentsController, type: :controller do end.to change(Tournament, :count).by(1) end + it 'stores tournament metadata' do + starts_at = '2030-06-01T10:00:00+02:00' + ends_at = '2030-06-01T18:00:00+02:00' + + post :create, params: create_playoff_tournament_data.merge( + location: 'Stadtpark Halle', + starts_at: starts_at, + ends_at: ends_at, + organizer_name: 'BPWSTR Crew', + contact_email: 'orga@example.com', + website_url: 'https://example.com/tournaments/summer-cup' + ) + + expect(response).to have_http_status(:created) + tournament = Tournament.find(deserialize_response(response)[:id]) + expect(tournament.location).to eq('Stadtpark Halle') + expect(tournament.starts_at.iso8601).to eq(Time.iso8601(starts_at).utc.iso8601) + expect(tournament.ends_at.iso8601).to eq(Time.iso8601(ends_at).utc.iso8601) + expect(tournament.organizer_name).to eq('BPWSTR Crew') + expect(tournament.contact_email).to eq('orga@example.com') + expect(tournament.website_url).to eq('https://example.com/tournaments/summer-cup') + end + it 'associates the new tournament with the authenticated user' do expect do post :create, params: create_playoff_tournament_data @@ -587,6 +611,49 @@ RSpec.describe TournamentsController, type: :controller do expect(@tournament.name).to eq(valid_update[:name]) end + it 'updates tournament metadata' do + starts_at = '2030-06-01T10:00:00+02:00' + ends_at = '2030-06-01T18:00:00+02:00' + + put :update, params: { + id: @tournament.to_param, + location: 'Arena Nord', + starts_at: starts_at, + ends_at: ends_at, + organizer_name: 'Turniere Ops', + contact_email: 'ops@example.com', + website_url: 'https://example.com/events/arena-nord' + } + + expect(response).to have_http_status(:ok) + @tournament.reload + json = deserialize_response(response) + expect(@tournament.location).to eq('Arena Nord') + expect(@tournament.starts_at.iso8601).to eq(Time.iso8601(starts_at).utc.iso8601) + expect(@tournament.ends_at.iso8601).to eq(Time.iso8601(ends_at).utc.iso8601) + expect(@tournament.organizer_name).to eq('Turniere Ops') + expect(@tournament.contact_email).to eq('ops@example.com') + expect(@tournament.website_url).to eq('https://example.com/events/arena-nord') + expect(json[:starts_at]).to eq(@tournament.starts_at.iso8601) + expect(json[:ends_at]).to eq(@tournament.ends_at.iso8601) + end + + it 'rejects invalid tournament metadata' do + put :update, params: { + id: @tournament.to_param, + starts_at: '2030-06-01T18:00:00+02:00', + ends_at: '2030-06-01T10:00:00+02:00', + contact_email: 'not-an-email', + website_url: 'notaurl' + } + + expect(response).to have_http_status(:unprocessable_content) + json = deserialize_response(response) + expect(json[:ends_at]).to include('must be after starts_at') + expect(json[:contact_email]).to include('is invalid') + expect(json[:website_url]).to include('is invalid') + end + it 'renders a JSON response with the tournament' do put :update, params: { id: @tournament.to_param }.merge(valid_update) expect(response).to have_http_status(:ok) @@ -810,6 +877,12 @@ RSpec.describe TournamentsController, type: :controller do code: 'abc123', description: 'Synced description', public: true, + location: 'Synced Arena', + starts_at: '2030-06-01T10:00:00+02:00', + ends_at: '2030-06-01T18:00:00+02:00', + organizer_name: 'Synced Crew', + contact_email: 'sync@example.com', + website_url: 'https://example.com/synced', playoff_teams_amount: 4, instant_finalists_amount: 4, intermediate_round_participants_amount: 0, @@ -827,6 +900,12 @@ RSpec.describe TournamentsController, type: :controller do @tournament.reload expect(@tournament.sync_source_tournament_id).to eq(123) expect(@tournament.name).to eq('Synced Tournament') + expect(@tournament.location).to eq('Synced Arena') + expect(@tournament.starts_at.iso8601).to eq(Time.iso8601('2030-06-01T10:00:00+02:00').utc.iso8601) + expect(@tournament.ends_at.iso8601).to eq(Time.iso8601('2030-06-01T18:00:00+02:00').utc.iso8601) + expect(@tournament.organizer_name).to eq('Synced Crew') + expect(@tournament.contact_email).to eq('sync@example.com') + expect(@tournament.website_url).to eq('https://example.com/synced') expect(@tournament.teams.pluck(:name)).to eq(['Alpha']) expect(deserialize_response(response)).not_to have_key(:sync_auth_token) expect(deserialize_response(response)).not_to have_key(:sync_auth_token_digest) diff --git a/spec/e2e/http/api_surface_spec.rb b/spec/e2e/http/api_surface_spec.rb index f8600d7..a92fbac 100644 --- a/spec/e2e/http/api_surface_spec.rb +++ b/spec/e2e/http/api_surface_spec.rb @@ -82,6 +82,12 @@ RSpec.describe 'Backend API surface HTTP E2E' do expect(full_show[:status]).to eq(200) expect(full_show.dig(:json, :stages)).to be_an(Array) expect(full_show.dig(:json, :teams)).to be_an(Array) + expect(full_show.dig(:json, :location)).to start_with('Venue') + expect(full_show.dig(:json, :starts_at)).to eq('2030-06-01T08:00:00Z') + expect(full_show.dig(:json, :ends_at)).to eq('2030-06-01T16:00:00Z') + expect(full_show.dig(:json, :organizer_name)).to eq('Turniere E2E') + expect(full_show.dig(:json, :contact_email)).to eq('events@example.com') + expect(full_show.dig(:json, :website_url)).to eq('https://example.com/turniere-e2e') expect(invalid_index[:status]).to eq(400) expect(invalid_index.dig(:json, :error)).to eq('invalid type') @@ -119,6 +125,12 @@ RSpec.describe 'Backend API surface HTTP E2E' do update_response = owner_client.patch("/tournaments/#{tournament.fetch(:id)}", body: { name: "Renamed #{unique_suffix}", + location: 'Updated E2E Arena', + starts_at: '2030-07-01T10:00:00+02:00', + ends_at: '2030-07-01T18:00:00+02:00', + organizer_name: 'Updated E2E Org', + contact_email: 'updated-events@example.com', + website_url: 'https://example.com/updated-turniere-e2e', playoff_teams_amount: 8, instant_finalists_amount: 8, intermediate_round_participants_amount: 0 @@ -172,6 +184,12 @@ RSpec.describe 'Backend API surface HTTP E2E' do expect(update_response[:status]).to eq(200) expect(update_response.dig(:json, :name)).to start_with('Renamed') + expect(update_response.dig(:json, :location)).to eq('Updated E2E Arena') + expect(update_response.dig(:json, :starts_at)).to eq('2030-07-01T08:00:00Z') + expect(update_response.dig(:json, :ends_at)).to eq('2030-07-01T16:00:00Z') + expect(update_response.dig(:json, :organizer_name)).to eq('Updated E2E Org') + expect(update_response.dig(:json, :contact_email)).to eq('updated-events@example.com') + expect(update_response.dig(:json, :website_url)).to eq('https://example.com/updated-turniere-e2e') expect(auto_recalc_response[:status]).to eq(200) expect(auto_recalc_response.dig(:json, :playoff_teams_amount)).to eq(4) @@ -511,6 +529,12 @@ RSpec.describe 'Backend API surface HTTP E2E' do name: "#{name_prefix} #{unique_suffix}", description: 'HTTP API surface E2E group-stage tournament', public: public, + location: "Venue #{name_prefix}", + starts_at: '2030-06-01T10:00:00+02:00', + ends_at: '2030-06-01T18:00:00+02:00', + organizer_name: 'Turniere E2E', + contact_email: 'events@example.com', + website_url: 'https://example.com/turniere-e2e', group_stage: true, playoff_teams_amount: 8, teams: 4.times.flat_map do |group_index| @@ -567,6 +591,12 @@ RSpec.describe 'Backend API surface HTTP E2E' do name: "#{name_prefix} #{unique_suffix}", description: 'HTTP API surface E2E playoff tournament', public: public, + location: "Venue #{name_prefix}", + starts_at: '2030-06-01T10:00:00+02:00', + ends_at: '2030-06-01T18:00:00+02:00', + organizer_name: 'Turniere E2E', + contact_email: 'events@example.com', + website_url: 'https://example.com/turniere-e2e', teams: 4.times.map do |index| { name: "#{name_prefix.tr(' ', '')}-S#{index + 1}" } end diff --git a/spec/e2e/http/tournament_follow_sync_spec.rb b/spec/e2e/http/tournament_follow_sync_spec.rb index aa3f87c..7560aed 100644 --- a/spec/e2e/http/tournament_follow_sync_spec.rb +++ b/spec/e2e/http/tournament_follow_sync_spec.rb @@ -111,6 +111,12 @@ RSpec.describe 'Tournament follower sync HTTP E2E' do log_phase!('tighten playoff cutoff and rename teams') update_cutoff = source_owner_client.patch("/tournaments/#{source.fetch(:id)}", body: { + location: 'Source Updated Arena', + starts_at: '2030-07-01T10:00:00+02:00', + ends_at: '2030-07-01T18:00:00+02:00', + organizer_name: 'Updated Sync Crew', + contact_email: 'updated-sync@example.com', + website_url: 'https://example.com/updated-sync-source', playoff_teams_amount: 4, instant_finalists_amount: 4, intermediate_round_participants_amount: 0 @@ -233,6 +239,12 @@ RSpec.describe 'Tournament follower sync HTTP E2E' do name: "#{name_prefix} #{unique_suffix}", description: 'Follower sync source tournament', public: public, + location: "Source Venue #{name_prefix}", + starts_at: '2030-06-01T10:00:00+02:00', + ends_at: '2030-06-01T18:00:00+02:00', + organizer_name: 'Sync Source Crew', + contact_email: 'sync-source@example.com', + website_url: 'https://example.com/sync-source', group_stage: true, playoff_teams_amount: 8, teams: 4.times.flat_map do |group_index| @@ -255,6 +267,12 @@ RSpec.describe 'Tournament follower sync HTTP E2E' do name: "#{name_prefix} #{unique_suffix}", description: 'Unrelated playoff tournament', public: public, + location: "Noise Venue #{name_prefix}", + starts_at: '2030-06-01T10:00:00+02:00', + ends_at: '2030-06-01T18:00:00+02:00', + organizer_name: 'Noise Crew', + contact_email: 'noise@example.com', + website_url: 'https://example.com/noise', teams: 4.times.map do |index| { name: "#{name_prefix.tr(' ', '')}-S#{index + 1}" } end @@ -270,6 +288,12 @@ RSpec.describe 'Tournament follower sync HTTP E2E' do name: "#{name_prefix} #{unique_suffix}", description: 'Follower tournament', public: public, + location: "Follower Venue #{name_prefix}", + starts_at: '2030-05-01T10:00:00+02:00', + ends_at: '2030-05-01T18:00:00+02:00', + organizer_name: 'Follower Crew', + contact_email: 'follower@example.com', + website_url: 'https://example.com/follower', read_only_mode: true, sync_auth_token: sync_token }) @@ -500,6 +524,12 @@ RSpec.describe 'Tournament follower sync HTTP E2E' do { name: tournament.fetch(:name), public: tournament.fetch(:public), + location: tournament[:location], + starts_at: tournament[:starts_at], + ends_at: tournament[:ends_at], + organizer_name: tournament[:organizer_name], + contact_email: tournament[:contact_email], + website_url: tournament[:website_url], playoff_teams_amount: tournament.fetch(:playoff_teams_amount), instant_finalists_amount: tournament.fetch(:instant_finalists_amount), intermediate_round_participants_amount: tournament.fetch(:intermediate_round_participants_amount), diff --git a/spec/e2e/http/tournament_sync_test_spec.rb b/spec/e2e/http/tournament_sync_test_spec.rb index a1d26f9..8df3498 100644 --- a/spec/e2e/http/tournament_sync_test_spec.rb +++ b/spec/e2e/http/tournament_sync_test_spec.rb @@ -33,7 +33,13 @@ RSpec.describe 'Tournament sync test HTTP E2E' do rename = client.patch("/tournaments/#{leader.fetch(:id)}", body: { name: "Leader Renamed #{SecureRandom.hex(3)}", - description: 'Roundtrip sync test' + description: 'Roundtrip sync test', + location: 'Sync Test Arena', + starts_at: '2030-08-01T10:00:00+02:00', + ends_at: '2030-08-01T18:00:00+02:00', + organizer_name: 'Sync Test Org', + contact_email: 'sync-test@example.com', + website_url: 'https://example.com/sync-test' }) expect(rename[:status]).to eq(200) @@ -52,6 +58,12 @@ RSpec.describe 'Tournament sync test HTTP E2E' do expect(after_follower.fetch(:name)).to eq(after_leader.fetch(:name)) expect(after_follower.fetch(:description)).to eq(after_leader.fetch(:description)) + expect(after_follower.fetch(:location)).to eq(after_leader.fetch(:location)) + expect(after_follower.fetch(:starts_at)).to eq(after_leader.fetch(:starts_at)) + expect(after_follower.fetch(:ends_at)).to eq(after_leader.fetch(:ends_at)) + expect(after_follower.fetch(:organizer_name)).to eq(after_leader.fetch(:organizer_name)) + expect(after_follower.fetch(:contact_email)).to eq(after_leader.fetch(:contact_email)) + expect(after_follower.fetch(:website_url)).to eq(after_leader.fetch(:website_url)) expect(after_follower.fetch(:teams).map { |team| team.fetch(:name) }) .to match_array(after_leader.fetch(:teams).map { |team| team.fetch(:name) }) end diff --git a/spec/services/tournament_snapshot_importer_spec.rb b/spec/services/tournament_snapshot_importer_spec.rb index b86e6fe..f9b563b 100644 --- a/spec/services/tournament_snapshot_importer_spec.rb +++ b/spec/services/tournament_snapshot_importer_spec.rb @@ -7,6 +7,12 @@ RSpec.describe TournamentSnapshotImporter do it 'replaces follower tournament graph using source ids as stable mapping keys' do source = create(:group_stage_tournament, group_count: 2, match_factory: :filled_group_match) source.update!( + location: 'Court 4', + starts_at: Time.utc(2026, 4, 24, 9, 0, 0), + ends_at: Time.utc(2026, 4, 24, 18, 30, 0), + organizer_name: 'Sync Ops', + contact_email: 'sync-ops@example.com', + website_url: 'https://example.com/sync-cup', timestamp: Time.utc(2026, 4, 24, 10, 15, 0), timer_mode: 'countdown', timer_reason: 'custom', @@ -28,6 +34,12 @@ RSpec.describe TournamentSnapshotImporter do follower.reload expect(follower.sync_source_tournament_id).to eq(source.id) expect(follower.name).to eq(source.name) + expect(follower.location).to eq(source.location) + expect(follower.starts_at).to eq(source.starts_at) + expect(follower.ends_at).to eq(source.ends_at) + expect(follower.organizer_name).to eq(source.organizer_name) + expect(follower.contact_email).to eq(source.contact_email) + expect(follower.website_url).to eq(source.website_url) expect(follower.timer_mode).to eq(source.timer_mode) expect(follower.timer_reason).to eq(source.timer_reason) expect(follower.timer_reason_text).to eq(source.timer_reason_text) @@ -197,6 +209,12 @@ RSpec.describe TournamentSnapshotImporter do { name: tournament.name, public: tournament.public, + location: tournament.location, + starts_at: tournament.starts_at&.iso8601, + ends_at: tournament.ends_at&.iso8601, + organizer_name: tournament.organizer_name, + contact_email: tournament.contact_email, + website_url: tournament.website_url, playoff_teams_amount: tournament.playoff_teams_amount, instant_finalists_amount: tournament.instant_finalists_amount, intermediate_round_participants_amount: tournament.intermediate_round_participants_amount,