From 98de79e744f6c16b22d7165514d58437fd907368 Mon Sep 17 00:00:00 2001 From: Travis Grathwell Date: Sun, 6 Dec 2015 17:24:01 -0800 Subject: [PATCH] Clone all existing Regions into Chapters This is to facilitate a different meaning between 'region' and 'chapter'. A "region" is a collection of locations. Attendees can subscribe to emails for events that take place in their region, and will (currently) be mailed regardless of whether the event belongs to "RailsBridge" or "MobileBridge" A "chapter" represents the organizing group who caused that event to happen. Every "event" belongs to one "chapter". Chapters also belong to one "organization", like "RailsBridge" or "MobileBridge" An event now requires a Chapter to be created, but there is not yet any UI to create one. --- app/models/chapter.rb | 7 ++ app/models/event.rb | 4 +- app/models/external_event.rb | 1 + app/models/organization.rb | 3 + app/views/events/_form.html.erb | 21 +++++- config/before-travis.sh | 3 + .../20151207004328_create_organizations.rb | 8 +++ ...151207004402_seed_initial_organizations.rb | 10 +++ db/migrate/20151207004523_create_chapters.rb | 13 ++++ ...151207004629_seed_chapters_from_regions.rb | 67 +++++++++++++++++++ db/schema.rb | 25 ++++++- db/seeds.rb | 7 +- db/seeds/seed_chapter.rb | 9 +++ db/seeds/seed_event.rb | 10 ++- db/seeds/seed_region.rb | 10 +-- spec/controllers/events_controller_spec.rb | 2 + spec/factories.rb | 10 +++ spec/features/announcing_an_event_spec.rb | 19 ++---- spec/features/event_listing_request_spec.rb | 4 ++ spec/features/new_event_request_spec.rb | 1 + spec/models/event_spec.rb | 2 +- spec/support/event_form_helper.rb | 1 + 22 files changed, 209 insertions(+), 28 deletions(-) create mode 100644 app/models/chapter.rb create mode 100644 app/models/organization.rb create mode 100644 db/migrate/20151207004328_create_organizations.rb create mode 100644 db/migrate/20151207004402_seed_initial_organizations.rb create mode 100644 db/migrate/20151207004523_create_chapters.rb create mode 100644 db/migrate/20151207004629_seed_chapters_from_regions.rb create mode 100644 db/seeds/seed_chapter.rb diff --git a/app/models/chapter.rb b/app/models/chapter.rb new file mode 100644 index 000000000..5fa87c54c --- /dev/null +++ b/app/models/chapter.rb @@ -0,0 +1,7 @@ +class Chapter < ActiveRecord::Base + belongs_to :organization + has_many :events, counter_cache: true + has_many :external_events, counter_cache: true + + validates_presence_of :organization +end diff --git a/app/models/event.rb b/app/models/event.rb index 77961a7d3..50a2aa5ed 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,5 +1,5 @@ class Event < ActiveRecord::Base - PERMITTED_ATTRIBUTES = [:title, :target_audience, :location_id, :details, :time_zone, :volunteer_details, :public_email, :starts_at, :ends_at, :student_rsvp_limit, :volunteer_rsvp_limit, :course_id, :allow_student_rsvp, :student_details, :plus_one_host_toggle, :email_on_approval, :has_childcare, :restrict_operating_systems, + PERMITTED_ATTRIBUTES = [:title, :target_audience, :location_id, :chapter_id, :details, :time_zone, :volunteer_details, :public_email, :starts_at, :ends_at, :student_rsvp_limit, :volunteer_rsvp_limit, :course_id, :allow_student_rsvp, :student_details, :plus_one_host_toggle, :email_on_approval, :has_childcare, :restrict_operating_systems, :survey_greeting] serialize :allowed_operating_system_ids, JSON @@ -14,6 +14,7 @@ class Event < ActiveRecord::Base end belongs_to :location, counter_cache: true + belongs_to :chapter, counter_cache: true extend ActiveHash::Associations::ActiveRecordExtensions belongs_to_active_hash :course @@ -46,6 +47,7 @@ class Event < ActiveRecord::Base validates_presence_of :title validates_presence_of :time_zone + validates_presence_of :chapter validates_inclusion_of :time_zone, in: ActiveSupport::TimeZone.all.map(&:name), allow_blank: true validates :allowed_operating_system_ids, array_of_ids: OperatingSystem.all.map(&:id), if: :restrict_operating_systems? validates_presence_of :target_audience, unless: :historical?, if: [:allow_student_rsvp?, :target_audience_required?] diff --git a/app/models/external_event.rb b/app/models/external_event.rb index dd9566fd2..d50f8e8a3 100644 --- a/app/models/external_event.rb +++ b/app/models/external_event.rb @@ -2,6 +2,7 @@ class ExternalEvent < ActiveRecord::Base PERMITTED_ATTRIBUTES = [:city, :ends_at, :location, :name, :organizers, :starts_at, :url, :region_id] belongs_to :region, counter_cache: true + belongs_to :chapter, counter_cache: true validates_presence_of :name, :starts_at, :location diff --git a/app/models/organization.rb b/app/models/organization.rb new file mode 100644 index 000000000..988090fc7 --- /dev/null +++ b/app/models/organization.rb @@ -0,0 +1,3 @@ +class Organization < ActiveRecord::Base + has_many :chapters +end diff --git a/app/views/events/_form.html.erb b/app/views/events/_form.html.erb index b4931a95f..12a8bdad0 100644 --- a/app/views/events/_form.html.erb +++ b/app/views/events/_form.html.erb @@ -36,8 +36,25 @@ $('#event_location_id').select2();

- If your location isn't in this list, head over to the <%= link_to 'locations page', locations_path %> and add - it before you continue. + If your location isn't in this list, head over to the <%= link_to 'locations page', locations_path %> and add it before you continue. +

+ + +
+
+ <%= f.label :chapter_id %> +
+ <%= collection_select(:event, + :chapter_id, + Chapter.all, + :id, + :name, + {prompt: true}) %> + +

+ If your chapter isn't in this list, contact an admin to get it added before you continue.

diff --git a/config/before-travis.sh b/config/before-travis.sh index 74e790350..29e44e733 100755 --- a/config/before-travis.sh +++ b/config/before-travis.sh @@ -1,2 +1,5 @@ bundle exec rake db:create:all +# ensure that migrations can run successfully bundle exec rake db:migrate +# re-load from schema to ensure DB is empty +bundle exec rake db:reset diff --git a/db/migrate/20151207004328_create_organizations.rb b/db/migrate/20151207004328_create_organizations.rb new file mode 100644 index 000000000..267323a60 --- /dev/null +++ b/db/migrate/20151207004328_create_organizations.rb @@ -0,0 +1,8 @@ +class CreateOrganizations < ActiveRecord::Migration + def change + create_table :organizations do |t| + t.string :name + t.timestamps null: false + end + end +end diff --git a/db/migrate/20151207004402_seed_initial_organizations.rb b/db/migrate/20151207004402_seed_initial_organizations.rb new file mode 100644 index 000000000..82328ab72 --- /dev/null +++ b/db/migrate/20151207004402_seed_initial_organizations.rb @@ -0,0 +1,10 @@ +class SeedInitialOrganizations < ActiveRecord::Migration + class Organization < ActiveRecord::Base; end + + def change + Organization.create(name: 'RailsBridge') + Organization.create(name: 'MobileBridge') + Organization.create(name: 'GoBridge') + Organization.create(name: 'ClojureBridge') + end +end diff --git a/db/migrate/20151207004523_create_chapters.rb b/db/migrate/20151207004523_create_chapters.rb new file mode 100644 index 000000000..174e41ade --- /dev/null +++ b/db/migrate/20151207004523_create_chapters.rb @@ -0,0 +1,13 @@ +class CreateChapters < ActiveRecord::Migration + def change + create_table :chapters do |t| + t.string :name + t.integer :events_count + t.integer :external_events_count + t.references :organization, null: false + + t.timestamps null: false + end + add_foreign_key :chapters, :organizations + end +end diff --git a/db/migrate/20151207004629_seed_chapters_from_regions.rb b/db/migrate/20151207004629_seed_chapters_from_regions.rb new file mode 100644 index 000000000..d8f44f34b --- /dev/null +++ b/db/migrate/20151207004629_seed_chapters_from_regions.rb @@ -0,0 +1,67 @@ +class SeedChaptersFromRegions < ActiveRecord::Migration + class Chapter < ActiveRecord::Base + belongs_to :organization + has_many :events + has_many :external_events + end + + class Location < ActiveRecord::Base + has_many :events + end + + class Region < ActiveRecord::Base + has_many :locations + has_many :events, through: :locations + has_many :external_events + end + + class Event < ActiveRecord::Base + belongs_to :region + belongs_to :chapter + end + + class ExternalEvent < ActiveRecord::Base + belongs_to :region + belongs_to :chapter + end + + def up + add_column :events, :chapter_id, :integer + add_column :external_events, :chapter_id, :integer + + rb_org = Organization.find_by(name: 'RailsBridge') + + Region.find_each do |region| + chapter_name = region.name + chapter_name = "RailsBridge #{chapter_name}" unless chapter_name.match('RailsBridge') + chapter = Chapter.create(name: chapter_name, organization: rb_org) + region.events.update_all(chapter_id: chapter.id) + end + + sf_chapter = Chapter.find_by(name: 'RailsBridge San Francisco') + if sf_chapter + Event.where('chapter_id IS NULL').update_all(chapter_id: sf_chapter.id) + end + + ExternalEvent.find_each do |external_event| + if external_event.region + chapter_name = external_event.region.name + chapter_name = "RailsBridge #{chapter_name}" unless chapter_name.match('RailsBridge') + chapter = Chapter.find_or_create_by(name: chapter_name, organization: rb_org) + external_event.update_attributes(chapter_id: chapter.id) + else + end + end + + change_column_null :events, :chapter_id, false + add_index :events, :chapter_id + add_foreign_key :events, :chapters + + add_index :external_events, :chapter_id + add_foreign_key :external_events, :chapters + end + + def down + remove_column :events, :chapter_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 35e404fb7..7d4d2092d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151201070911) do +ActiveRecord::Schema.define(version: 20151207004629) do create_table "authentications", force: :cascade do |t| t.integer "user_id" @@ -21,6 +21,15 @@ t.datetime "updated_at", null: false end + create_table "chapters", force: :cascade do |t| + t.string "name" + t.integer "events_count" + t.integer "external_events_count" + t.integer "organization_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "dietary_restrictions", force: :cascade do |t| t.string "restriction" t.integer "rsvp_id" @@ -95,8 +104,11 @@ t.datetime "announcement_email_sent_at" t.integer "current_state", default: 0 t.string "external_event_data" + t.integer "chapter_id", null: false end + add_index "events", ["chapter_id"], name: "index_events_on_chapter_id" + create_table "external_events", force: :cascade do |t| t.string "name" t.string "url" @@ -108,8 +120,10 @@ t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "region_id" + t.integer "chapter_id" end + add_index "external_events", ["chapter_id"], name: "index_external_events_on_chapter_id" add_index "external_events", ["region_id"], name: "index_external_events_on_region_id" create_table "locations", force: :cascade do |t| @@ -138,6 +152,12 @@ t.datetime "updated_at", null: false end + create_table "organizations", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "profiles", force: :cascade do |t| t.integer "user_id" t.boolean "childcaring" @@ -265,13 +285,16 @@ add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true add_foreign_key "authentications", "users" + add_foreign_key "chapters", "organizations" add_foreign_key "dietary_restrictions", "rsvps" add_foreign_key "event_email_recipients", "event_emails" add_foreign_key "event_email_recipients", "rsvps", column: "recipient_rsvp_id" add_foreign_key "event_emails", "events" add_foreign_key "event_emails", "users", column: "sender_id" add_foreign_key "event_sessions", "events" + add_foreign_key "events", "chapters" add_foreign_key "events", "locations" + add_foreign_key "external_events", "chapters" add_foreign_key "external_events", "regions" add_foreign_key "locations", "regions" add_foreign_key "profiles", "users" diff --git a/db/seeds.rb b/db/seeds.rb index ee31433f0..9b4bca646 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,9 +1,10 @@ -require Rails.root.join('db', 'seeds', 'seed_region') -require Rails.root.join('db', 'seeds', 'admin_user') -require Rails.root.join('db', 'seeds', 'seed_event') +Dir[Rails.root.join('db', 'seeds', '*.rb')].each do |seed_file| + require seed_file +end if Rails.env.development? Seeder::seed_region + Seeder::seed_chapter Seeder::admin_user Seeder::seed_event end diff --git a/db/seeds/seed_chapter.rb b/db/seeds/seed_chapter.rb new file mode 100644 index 000000000..1d4eeacbe --- /dev/null +++ b/db/seeds/seed_chapter.rb @@ -0,0 +1,9 @@ +module Seeder + def self.seed_chapter + org = Organization.find_or_create_by(name: 'RailsBridge') + + Chapter.find_or_create_by(name: 'RailsBridge Seattle', organization: org) + Chapter.find_or_create_by(name: 'RailsBridge San Francisco', organization: org) + Chapter.find_or_create_by(name: 'RailsBridge Tulsa', organization: org) + end +end diff --git a/db/seeds/seed_event.rb b/db/seeds/seed_event.rb index 9a08ff64a..e29645406 100644 --- a/db/seeds/seed_event.rb +++ b/db/seeds/seed_event.rb @@ -54,6 +54,11 @@ def self.destroy_event event region.destroy if region.events.count == 1 event.location.destroy end + if event.chapter.present? + organization = event.chapter.organization + organization.destroy if organization.chapters.count == 1 + event.chapter.destroy + end event.destroy end @@ -62,7 +67,9 @@ def self.seed_event(options={}) old_event = Event.where(title: 'Seeded Test Event').first destroy_event(old_event) if old_event.present? - region = Region.where(name: 'RailsBridge San Francisco').first_or_create! + organization = Organization.find_or_create_by(name: 'RailsBridge') + region = Region.find_or_create_by(name: 'San Francisco') + chapter = Chapter.find_or_create_by(name: 'RailsBridge San Francisco', organization: organization) location = Location.create!( region_id: region.id, @@ -81,6 +88,7 @@ def self.seed_event(options={}) time_zone: 'Pacific Time (US & Canada)', course_id: Course::RAILS.id, location: location, + chapter: chapter, current_state: :published, target_audience: 'women', details: <<-DETAILS.strip_heredoc diff --git a/db/seeds/seed_region.rb b/db/seeds/seed_region.rb index 8f73c5d86..4f04a6ddd 100644 --- a/db/seeds/seed_region.rb +++ b/db/seeds/seed_region.rb @@ -1,11 +1,7 @@ module Seeder def self.seed_region - # seeds the database with an admin user - region = Region.where(name: 'RailsBridge Seattle').first_or_initialize - region.save! - region = Region.where(name: 'RailsBridge San Francisco').first_or_initialize - region.save! - region = Region.where(name: 'RailsBridge Tulsa').first_or_initialize - region.save! + Region.find_or_create_by(name: 'Seattle') + Region.find_or_create_by(name: 'San Francisco') + Region.find_or_create_by(name: 'Tulsa') end end diff --git a/spec/controllers/events_controller_spec.rb b/spec/controllers/events_controller_spec.rb index 74ae65604..8b6095ad1 100644 --- a/spec/controllers/events_controller_spec.rb +++ b/spec/controllers/events_controller_spec.rb @@ -247,6 +247,7 @@ def make_request(params = {}) end describe "with valid params" do + let!(:chapter) { create(:chapter) } let(:create_params) { next_year = Date.current.year + 1 { @@ -271,6 +272,7 @@ def make_request(params = {}) } }, "location_id" => "1", + "chapter_id" => chapter.id, "details" => "sdfasdfasdf" } } diff --git a/spec/factories.rb b/spec/factories.rb index 76edc4d68..b19ba7cf8 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -33,6 +33,7 @@ student_rsvp_limit 100 volunteer_rsvp_limit 75 location + chapter course_id Course::RAILS.id volunteer_details "I am some details for volunteers." student_details "I am some details for students." @@ -57,6 +58,15 @@ sequence(:name) { |n| "Region #{n}" } end + factory :chapter do + sequence(:name) { |n| "Region #{n}" } + organization + end + + factory :organization do + sequence(:name) { |n| "Organization #{n}" } + end + factory :event_session do sequence(:name) { |n| "Test Session #{n}" } starts_at 1.day.from_now diff --git a/spec/features/announcing_an_event_spec.rb b/spec/features/announcing_an_event_spec.rb index ed4727e3f..061b84cf9 100644 --- a/spec/features/announcing_an_event_spec.rb +++ b/spec/features/announcing_an_event_spec.rb @@ -4,6 +4,8 @@ let(:user_organizer) { create(:user, email: "organizer@mail.com", first_name: "Sam", last_name: "Spade") } let(:admin) { create(:user, admin: true) } let(:event_location) { create(:location) } + let(:send_email_text) { 'Send Announcement Email' } + let!(:chapter) { create(:chapter) } before do sign_in_as(user_organizer) @@ -22,7 +24,7 @@ context "before approval" do it "will not allow the announcement email to be sent by an organizer" do click_on "Organizer Console" - expect(page).to have_no_content "Send Announcement Email" + expect(page).to have_no_content(send_email_text) end end @@ -41,7 +43,7 @@ visit '/' click_on good_event_title click_on "Organizer Console" - expect(page).to have_no_content "Send Announcement Email" + expect(page).to have_no_content(send_email_text) end end end @@ -55,7 +57,7 @@ context "before approval" do it "will not allow the announcement email to be sent by an organizer" do click_on "Organizer Console" - expect(page).to have_no_content "Send Announcement Email" + expect(page).to have_no_content(send_email_text) end end @@ -74,16 +76,9 @@ visit '/' click_on good_event_title click_on "Organizer Console" - click_on "Send Announcement Email" + click_on send_email_text expect(page).to have_content "Your announcement email was sent!" - end - - it "will not allow an announcement email to be sent more than once by an organizer" do - visit '/' - click_on good_event_title - click_on "Organizer Console" - click_on "Send Announcement Email" - expect(page).to have_no_content "Send Announcement Email" + expect(page).to have_no_content(send_email_text) end end end diff --git a/spec/features/event_listing_request_spec.rb b/spec/features/event_listing_request_spec.rb index 510843a02..b895f6a0c 100644 --- a/spec/features/event_listing_request_spec.rb +++ b/spec/features/event_listing_request_spec.rb @@ -60,6 +60,8 @@ end context 'when organizing an event', js: true do + let!(:chapter) { create(:chapter) } + before do visit events_path click_link "Organize Event" @@ -94,6 +96,7 @@ fill_in "Title", with: "Volunteer Work Day" fill_in "event_target_audience", :with => "women" choose "Just Volunteers" + select Chapter.first.name, from: "event_chapter_id" within ".event-sessions" do fill_in "Session Name", with: 'Do Awesome Stuff' @@ -122,6 +125,7 @@ fill_in "event_target_audience", :with => "women" select "Front End", :from => "event_course_id" fill_in "Student RSVP limit", with: 100 + select Chapter.first.name, from: "event_chapter_id" within ".event-sessions" do fill_in "Session Name", with: good_event_session_name diff --git a/spec/features/new_event_request_spec.rb b/spec/features/new_event_request_spec.rb index c45d38f11..0de76dec9 100644 --- a/spec/features/new_event_request_spec.rb +++ b/spec/features/new_event_request_spec.rb @@ -3,6 +3,7 @@ describe "New Event" do before do @user_organizer = create(:user, email: "organizer@mail.com", first_name: "Sam", last_name: "Spade") + @chapter = create(:chapter) 3.times { create(:location) } @archived = Location.last.tap { |l| l.archive! } diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index f59efcfb9..10b4068ce 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -175,7 +175,7 @@ "ends_at(5i)" => "45" } }) - event = Event.create(attrs) + event = Event.create(attrs.merge(chapter_id: create(:chapter).id)) expect(event.starts_at).to eq(event.event_sessions.first.starts_at) expect(event.ends_at).to eq(event.event_sessions.first.ends_at) end diff --git a/spec/support/event_form_helper.rb b/spec/support/event_form_helper.rb index facf67645..03331926e 100644 --- a/spec/support/event_form_helper.rb +++ b/spec/support/event_form_helper.rb @@ -2,6 +2,7 @@ def fill_in_good_event_details fill_in 'Title', with: good_event_title select "Ruby on Rails", from: "event_course_id" fill_in "Student RSVP limit", with: 100 + select Chapter.first.name, from: "event_chapter_id" within ".event-sessions" do fill_in "Session Name", with: good_event_session_name