diff --git a/app/abilities/ability.rb b/app/abilities/ability.rb
index 6ef72ea3c0c..805b68f8e8c 100644
--- a/app/abilities/ability.rb
+++ b/app/abilities/ability.rb
@@ -63,6 +63,8 @@ def initialize(user)
can [:create, :destroy], CommunityMember, :user_id => user.id
can [:destroy, :edit, :update], CommunityMember, :community => user_is_community_organizer
can [:create, :edit, :new, :update], Event, :community => user_is_community_organizer
+ can [:create], EventAttendance
+ can [:update], EventAttendance, :user_id => user.id
can [:close, :reopen], Note
can [:show, :edit, :update], :preference
can [:edit, :update], :profile
diff --git a/app/controllers/event_attendances_controller.rb b/app/controllers/event_attendances_controller.rb
new file mode 100644
index 00000000000..ed02e0382aa
--- /dev/null
+++ b/app/controllers/event_attendances_controller.rb
@@ -0,0 +1,40 @@
+class EventAttendancesController < ApplicationController
+ layout "site"
+ before_action :authorize_web
+ before_action :set_event_attendance, :only => [:update]
+
+ authorize_resource
+
+ def create
+ attendance = EventAttendance.new(event_attendance_params)
+ if attendance.save
+ redirect_to event_path(attendance.event), :notice => t(".success")
+ else
+ redirect_to event_path(attendance.event), :alert => t(".failure")
+ end
+ end
+
+ def update
+ respond_to do |format|
+ if @event_attendance.update(update_params)
+ format.html { redirect_to @event_attendance.event, :notice => t(".success") }
+ else
+ format.html { redirect_to :edit, :alert => t(".failure") }
+ end
+ end
+ end
+
+ private
+
+ def set_event_attendance
+ @event_attendance = EventAttendance.find(params[:id])
+ end
+
+ def event_attendance_params
+ params.require(:event_attendance).permit(:event_id, :user_id, :intention)
+ end
+
+ def update_params
+ params.require(:event_attendance).permit(:intention)
+ end
+end
diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb
index c100c092f22..17971e97140 100644
--- a/app/controllers/events_controller.rb
+++ b/app/controllers/events_controller.rb
@@ -27,6 +27,13 @@ def index
# GET /events/1.json
def show
@community = Community.friendly.find(params[:community_id]) if params[:community_id]
+ @my_attendance = EventAttendance.find_or_initialize_by(:event_id => @event.id, :user_id => current_user&.id)
+ @yes_check = @my_attendance.intention == EventAttendance::Intentions::YES ? "✓" : ""
+ @no_check = @my_attendance.intention == EventAttendance::Intentions::NO ? "✓" : ""
+ @maybe_check = @my_attendance.intention == EventAttendance::Intentions::MAYBE ? "✓" : ""
+ @yes_disabled = @my_attendance.intention == EventAttendance::Intentions::YES
+ @no_disabled = @my_attendance.intention == EventAttendance::Intentions::NO
+ @maybe_disabled = @my_attendance.intention == EventAttendance::Intentions::MAYBE
rescue ActiveRecord::RecordNotFound
@not_found_community = params[:community_id]
render :template => "communities/no_such_community", :status => :not_found
diff --git a/app/models/event.rb b/app/models/event.rb
index 3e78cd1eb46..4a7e9704cc2 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -26,6 +26,7 @@
class Event < ApplicationRecord
belongs_to :community
has_many :event_organizers
+ has_many :event_attendances
scope :future, -> { where(:moment => Time.now.utc..) }
scope :past, -> { where(:moment => ...Time.now.utc) }
@@ -63,4 +64,20 @@ def organizers
def past?
moment < Time.now.utc
end
+
+ def attendees(intention)
+ EventAttendance.where(:event_id => id, :intention => intention)
+ end
+
+ def yes_attendees
+ attendees(EventAttendance::Intentions::YES)
+ end
+
+ def no_attendees
+ attendees(EventAttendance::Intentions::NO)
+ end
+
+ def maybe_attendees
+ attendees(EventAttendance::Intentions::MAYBE)
+ end
end
diff --git a/app/models/event_attendance.rb b/app/models/event_attendance.rb
new file mode 100644
index 00000000000..030c8868714
--- /dev/null
+++ b/app/models/event_attendance.rb
@@ -0,0 +1,35 @@
+# == Schema Information
+#
+# Table name: event_attendances
+#
+# id :bigint(8) not null, primary key
+# user_id :bigint(8) not null
+# event_id :bigint(8) not null
+# intention :enum not null
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+# Indexes
+#
+# index_event_attendances_on_event_id (event_id)
+# index_event_attendances_on_user_id (user_id)
+# index_event_attendances_on_user_id_and_event_id (user_id,event_id) UNIQUE
+#
+# Foreign Keys
+#
+# fk_rails_... (event_id => events.id)
+# fk_rails_... (user_id => users.id)
+#
+
+class EventAttendance < ApplicationRecord
+ module Intentions
+ YES = "Yes".freeze
+ NO = "No".freeze
+ MAYBE = "Maybe".freeze
+ ALL_INTENTIONS = [YES, NO, MAYBE].freeze
+ end
+ validates :intention, :inclusion => { :in => Intentions::ALL_INTENTIONS }
+
+ belongs_to :event
+ belongs_to :user
+end
diff --git a/app/views/events/show.html.erb b/app/views/events/show.html.erb
index e94febe980a..199c456c38a 100644
--- a/app/views/events/show.html.erb
+++ b/app/views/events/show.html.erb
@@ -27,6 +27,24 @@
<%= render :partial => "events/event_property", :locals => { :name => t(".description"), :value => @event.description } %>
+
+
<%= t(".people_are_going", :count => @event.yes_attendees.size) %>
+
<%= t(".are_you_going") %>
+ <% if current_user %>
+ <%= form_with :model => @my_attendance do |form| %>
+ <%= form.hidden_field(:event_id, :value => @event.id) %>
+ <%= form.hidden_field(:user_id, :value => current_user&.id) %>
+ <%= form.submit :name => "event_attendance[intention]", :value => @yes_check + t(".going_yes"), :disabled => @yes_disabled %>
+ <%= form.submit :name => "event_attendance[intention]", :value => @no_check + t(".going_no"), :disabled => @no_disabled %>
+ <%= form.submit :name => "event_attendance[intention]", :value => @maybe_check + t(".going_maybe"), :disabled => @maybe_disabled %>
+ <% end %>
+ <% else %>
+
+ <%# TODO: Use login_path %>
+ <%= t(".login_to_rsvp") %>
+
+ <% end %>
+
<%= tag.div "",
@@ -43,3 +61,27 @@
+
+
+
+
<%= t(".who_yes") %>
+
+ <% @event.yes_attendees.each do |attendance| %>
+ <%= render :partial => "users/user_card", :locals => { :user => attendance.user } %>
+ <% end %>
+
+
<%= t(".who_maybe") %>
+
+ <% @event.maybe_attendees.each do |attendance| %>
+ <%= render :partial => "users/user_card", :locals => { :user => attendance.user } %>
+ <% end %>
+
+
<%= t(".who_no") %>
+
+ <% @event.no_attendees.each do |attendance| %>
+ <%= render :partial => "users/user_card", :locals => { :user => attendance.user } %>
+ <% end %>
+
+
+
+
diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb
index 1abcb8e329e..dfa51829a41 100644
--- a/app/views/layouts/_header.html.erb
+++ b/app/views/layouts/_header.html.erb
@@ -72,7 +72,7 @@
<% end %>
<%= link_to t("layouts.gps_traces"), traces_path, :class => "dropdown-item" %>
<%= link_to t("layouts.user_diaries"), diary_entries_path, :class => "dropdown-item" %>
- <%= link_to t("layouts.communities"), communities_path, :class => "dropdown-item" %>
+ <%= link_to t("layouts.communities"), communities_index_path, :class => "dropdown-item" %>
<%= link_to t("layouts.copyright"), copyright_path, :class => "dropdown-item" %>
<%= link_to t("layouts.help"), help_path, :class => "dropdown-item" %>
<%= link_to t("layouts.about"), about_path, :class => "dropdown-item" %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index d40d4cb1114..445e9a91ec7 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -774,6 +774,13 @@ en:
not_found:
title: File not found
description: Couldn't find a file/directory/API operation by that name on the OpenStreetMap server (HTTP 404)
+ event_attendances:
+ create:
+ success: Attendance was successfully saved.
+ failure: Attendance could not be saved.
+ update:
+ success: Attendance was successfully updated.
+ failure: Attendance could not be updated.
events:
create:
success: Event was created successfully.
@@ -795,14 +802,27 @@ en:
new:
new: "New Event"
show:
+ are_you_going: "Are you going?"
description: "Description"
directions_to: "Directions to this location."
edit: "Edit"
+ going_maybe: "Maybe"
+ going_no: "No"
+ going_yes: "Yes"
hosted_by: "Hosted by"
location: "Location"
+ login_to_rsvp: "Login to RSVP."
organized_by: "Organized by"
past: "Event is in the past."
+ people_are_going:
+ 0: "" # TODO: Not working, but can't use "zero" due to lint.
+ 1: "1 person is going." # TODO: Not working.
+ one: "1 person is going."
+ other: "%{count} people are going"
when: "When"
+ who_yes: "Going"
+ who_no: "Not Going"
+ who_maybe: "Might Go"
update:
success: "The event was successfully updated."
failure: "The event was not updated."
@@ -1717,6 +1737,9 @@ en:
home: Go to Home Location
logout: Log Out
log_in: Log In
+ log_in_tooltip: Log in with an existing account
+ communities: Communities
+ events: Events
sign_up: Sign Up
start_mapping: Start Mapping
edit: Edit
diff --git a/config/routes.rb b/config/routes.rb
index 1e19b1517c3..acfe0e2983d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -357,6 +357,7 @@
resources :community_members, :only => [:create, :destroy, :edit, :new, :update]
get "/community_members" => "community_members#create", :as => "login_to_join"
resources :events
+ resources :event_attendances
# errors
match "/400", :to => "errors#bad_request", :via => :all
diff --git a/db/migrate/20240730234421_create_event_attendances.rb b/db/migrate/20240730234421_create_event_attendances.rb
new file mode 100644
index 00000000000..c21a584ea76
--- /dev/null
+++ b/db/migrate/20240730234421_create_event_attendances.rb
@@ -0,0 +1,18 @@
+class CreateEventAttendances < ActiveRecord::Migration[7.0]
+ def up
+ create_enum :event_attendances_intention_enum, %w[Maybe No Yes]
+ create_table :event_attendances do |t|
+ t.references :user, :foreign_key => true, :null => false, :index => true
+ t.references :event, :foreign_key => true, :null => false, :index => true
+ t.column :intention, :event_attendances_intention_enum, :null => false
+
+ t.timestamps
+ end
+ add_index :event_attendances, [:user_id, :event_id], :unique => true
+ end
+
+ def down
+ drop_table :event_attendances
+ drop_enum :event_attendances_intention_enum
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index b782d3a81f0..6393e58c321 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -33,6 +33,17 @@ CREATE TYPE public.community_member_role_enum AS ENUM (
);
+--
+-- Name: event_attendances_intention_enum; Type: TYPE; Schema: public; Owner: -
+--
+
+CREATE TYPE public.event_attendances_intention_enum AS ENUM (
+ 'Maybe',
+ 'No',
+ 'Yes'
+);
+
+
--
-- Name: format_enum; Type: TYPE; Schema: public; Owner: -
--
@@ -912,6 +923,39 @@ CREATE TABLE public.diary_entry_subscriptions (
);
+--
+-- Name: event_attendances; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.event_attendances (
+ id bigint NOT NULL,
+ user_id bigint NOT NULL,
+ event_id bigint NOT NULL,
+ intention public.event_attendances_intention_enum NOT NULL,
+ created_at timestamp(6) without time zone NOT NULL,
+ updated_at timestamp(6) without time zone NOT NULL
+);
+
+
+--
+-- Name: event_attendances_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE public.event_attendances_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+--
+-- Name: event_attendances_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE public.event_attendances_id_seq OWNED BY public.event_attendances.id;
+
+
--
-- Name: event_organizers; Type: TABLE; Schema: public; Owner: -
--
@@ -2017,6 +2061,13 @@ ALTER TABLE ONLY public.diary_comments ALTER COLUMN id SET DEFAULT nextval('publ
ALTER TABLE ONLY public.diary_entries ALTER COLUMN id SET DEFAULT nextval('public.diary_entries_id_seq'::regclass);
+--
+-- Name: event_attendances id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.event_attendances ALTER COLUMN id SET DEFAULT nextval('public.event_attendances_id_seq'::regclass);
+
+
--
-- Name: event_organizers id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -2370,6 +2421,14 @@ ALTER TABLE ONLY public.diary_entry_subscriptions
ADD CONSTRAINT diary_entry_subscriptions_pkey PRIMARY KEY (user_id, diary_entry_id);
+--
+-- Name: event_attendances event_attendances_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.event_attendances
+ ADD CONSTRAINT event_attendances_pkey PRIMARY KEY (id);
+
+
--
-- Name: event_organizers event_organizers_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -2957,6 +3016,27 @@ CREATE INDEX index_community_members_on_user_id ON public.community_members USIN
CREATE INDEX index_diary_entry_subscriptions_on_diary_entry_id ON public.diary_entry_subscriptions USING btree (diary_entry_id);
+--
+-- Name: index_event_attendances_on_event_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX index_event_attendances_on_event_id ON public.event_attendances USING btree (event_id);
+
+
+--
+-- Name: index_event_attendances_on_user_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX index_event_attendances_on_user_id ON public.event_attendances USING btree (user_id);
+
+
+--
+-- Name: index_event_attendances_on_user_id_and_event_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX index_event_attendances_on_user_id_and_event_id ON public.event_attendances USING btree (user_id, event_id);
+
+
--
-- Name: index_event_organizers_on_event_id; Type: INDEX; Schema: public; Owner: -
--
@@ -3593,6 +3673,14 @@ ALTER TABLE ONLY public.user_mutes
ADD CONSTRAINT fk_rails_591dad3359 FOREIGN KEY (owner_id) REFERENCES public.users(id);
+--
+-- Name: event_attendances fk_rails_64ad6920ae; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.event_attendances
+ ADD CONSTRAINT fk_rails_64ad6920ae FOREIGN KEY (user_id) REFERENCES public.users(id);
+
+
--
-- Name: oauth_access_tokens fk_rails_732cb83ab7; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -3665,6 +3753,14 @@ ALTER TABLE ONLY public.oauth_applications
ADD CONSTRAINT fk_rails_cc886e315a FOREIGN KEY (owner_id) REFERENCES public.users(id) NOT VALID;
+--
+-- Name: event_attendances fk_rails_d082d0d206; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.event_attendances
+ ADD CONSTRAINT fk_rails_d082d0d206 FOREIGN KEY (event_id) REFERENCES public.events(id);
+
+
--
-- Name: user_mutes fk_rails_e9dd4fb6c3; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -4028,6 +4124,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('23'),
('22'),
('21'),
+('20240730234421'),
('20240728224134'),
('20240728144036'),
('20240618193051'),
diff --git a/test/controllers/event_attendances_controller_test.rb b/test/controllers/event_attendances_controller_test.rb
new file mode 100644
index 00000000000..e9f6c8f222d
--- /dev/null
+++ b/test/controllers/event_attendances_controller_test.rb
@@ -0,0 +1,98 @@
+require "test_helper"
+
+class EventAttendancesControllerTest < ActionDispatch::IntegrationTest
+ def test_routes
+ assert_routing(
+ { :path => "/event_attendances/1", :method => :put },
+ { :controller => "event_attendances", :action => "update", :id => "1" }
+ )
+ assert_routing(
+ { :path => "/event_attendances", :method => :post },
+ { :controller => "event_attendances", :action => "create" }
+ )
+ end
+
+ def test_create_when_save_works
+ cm = create(:community_member)
+ ev = create(:event, :community => cm.community)
+ ea_orig = build(:event_attendance, :user => cm.user, :event => ev)
+ form = ea_orig.attributes.except("id", "created_at", "updated_at")
+ session_for(cm.user)
+
+ assert_difference "EventAttendance.count", 1 do
+ post event_attendances_url, :params => { :event_attendance => form.as_json }, :xhr => true
+ end
+
+ assert_redirected_to event_path(ev)
+ ea_new_id = EventAttendance.maximum(:id)
+ assert_equal I18n.t("event_attendances.create.success"), flash[:notice]
+ ea_new = EventAttendance.find(ea_new_id)
+ # Assign the new id to the original object, so we can do an equality test easily.
+ ea_orig.id = ea_new.id
+ assert_equal(ea_orig, ea_new)
+ end
+
+ def test_update_as_wrong_user
+ cm = create(:community_member)
+ ev = create(:event, :community => cm.community)
+ ea1 = create(:event_attendance, :user => cm.user, :event => ev) # original object
+ u2 = create(:user)
+ ea2 = build(:event_attendance, :user => u2, :event => ev) # new data
+ form = ea2.attributes.except("id", "created_at", "updated_at")
+ session_for(u2)
+
+ # Update ea1 with the values from ea2.
+ put event_attendance_url(ea1), :params => { :event_attendance => form }, :xhr => true
+
+ assert_redirected_to :controller => :errors, :action => :forbidden
+ end
+
+ def test_create_when_save_fails
+ cm = create(:community_member, :organizer)
+ session_for(cm.user)
+
+ e = create(:event, :community => cm.community)
+ ea = build(:event_attendance, :event => e, :user => cm.user, :intention => "Invalid")
+ form = ea.attributes.except("id", "created_at", "updated_at")
+
+ assert_no_difference "EventAttendance.count", 0 do
+ post event_attendances_path, :params => { :event_attendance => form }
+ end
+ end
+
+ def test_update_success
+ cm = create(:community_member)
+ ev = create(:event, :community => cm.community)
+ ea1 = create(:event_attendance, :user => cm.user, :event => ev, :intention => "Yes") # original object
+ ea2 = build(:event_attendance, :user => cm.user, :event => ev, :intention => "No") # new data
+ form = ea2.attributes.except("id", "created_at", "updated_at")
+ session_for(cm.user)
+
+ # Update m1 with the values from m2.
+ put event_attendance_url(ea1), :params => { :event_attendance => form.as_json }, :xhr => true
+
+ assert_redirected_to event_path(ev)
+ assert_equal I18n.t("event_attendances.update.success"), flash[:notice]
+ ea1.reload
+ # Assign the id of object 1 to object 2, so we can do an equality test easily.
+ ea2.id = ea1.id
+ assert_equal(ea2, ea1)
+ end
+
+ def test_update_when_save_fails
+ cm = create(:community_member)
+ ev = create(:event, :community => cm.community)
+ session_for(cm.user)
+
+ ea = create(:event_attendance, :user => cm.user, :event => ev) # original object
+ form = ea.attributes.except("id", "created_at", "updated_at")
+ form["intention"] = "Invalid" # Force "save" to fail.
+
+ assert_difference "EventAttendance.count", 0 do
+ put event_attendance_url(ea), :params => { :event_attendance => form.as_json }, :xhr => true
+ end
+
+ follow_redirect!
+ assert_equal I18n.t("event_attendances.update.failure"), flash[:alert]
+ end
+end
diff --git a/test/factories/event_attendances.rb b/test/factories/event_attendances.rb
new file mode 100644
index 00000000000..89c1336c911
--- /dev/null
+++ b/test/factories/event_attendances.rb
@@ -0,0 +1,15 @@
+FactoryBot.define do
+ factory :event_attendance do
+ user
+ event
+ intention { "Maybe" }
+
+ trait :no do
+ intention { "No" }
+ end
+
+ trait :yes do
+ intention { "Yes" }
+ end
+ end
+end
diff --git a/test/models/event_attendance_test.rb b/test/models/event_attendance_test.rb
new file mode 100644
index 00000000000..dd8c492497c
--- /dev/null
+++ b/test/models/event_attendance_test.rb
@@ -0,0 +1,7 @@
+require "test_helper"
+
+class EventAttendanceTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/models/event_test.rb b/test/models/event_test.rb
index 537ec6dc1fd..bb63a9ae68a 100644
--- a/test/models/event_test.rb
+++ b/test/models/event_test.rb
@@ -33,4 +33,60 @@ def test_validations
validate({ :longitude => -180 }, true)
validate({ :longitude => -180.00001 }, false)
end
+
+ def test_attendees
+ # Zero
+ event = create(:event)
+ assert_equal(0, event.maybe_attendees.length)
+ assert_equal(0, event.no_attendees.length)
+ assert_equal(0, event.yes_attendees.length)
+
+ # 1 Maybe
+ ea = create(:event_attendance)
+ assert_equal(1, ea.event.maybe_attendees.length)
+ assert_equal(0, ea.event.no_attendees.length)
+ assert_equal(0, ea.event.yes_attendees.length)
+ assert_equal("Maybe", ea.event.event_attendances[0].intention)
+ assert_equal(ea.user.display_name, ea.event.event_attendances[0].user.display_name)
+
+ # 1 No
+ ea = create(:event_attendance, :no)
+ assert_equal(0, ea.event.maybe_attendees.length)
+ assert_equal(1, ea.event.no_attendees.length)
+ assert_equal(0, ea.event.yes_attendees.length)
+ assert_equal("No", ea.event.event_attendances[0].intention)
+ assert_equal(ea.user.display_name, ea.event.event_attendances[0].user.display_name)
+
+ # 1 Yes
+ ea = create(:event_attendance, :yes)
+ assert_equal(0, ea.event.maybe_attendees.length)
+ assert_equal(0, ea.event.no_attendees.length)
+ assert_equal(1, ea.event.yes_attendees.length)
+ assert_equal("Yes", ea.event.event_attendances[0].intention)
+ assert_equal(ea.user.display_name, ea.event.event_attendances[0].user.display_name)
+
+ # 2 Yes
+ event = create(:event)
+ u1 = create(:user)
+ ea1 = EventAttendance.new(:event => event, :user => u1, :intention => EventAttendance::Intentions::YES)
+ ea1.save
+ u2 = create(:user)
+ ea2 = EventAttendance.new(:event => event, :user => u2, :intention => EventAttendance::Intentions::YES)
+ ea2.save
+ assert_equal(2, event.yes_attendees.length)
+ assert_equal(u1.display_name, event.yes_attendees[0].user.display_name)
+ assert_equal(u2.display_name, event.yes_attendees[1].user.display_name)
+
+ # 1 Yes and 1 No
+ event = create(:event)
+ u1 = create(:user)
+ ea1 = EventAttendance.new(:event => event, :user => u1, :intention => EventAttendance::Intentions::NO)
+ ea1.save
+ u2 = create(:user)
+ ea2 = EventAttendance.new(:event => event, :user => u2, :intention => EventAttendance::Intentions::YES)
+ ea2.save
+ assert_equal(1, event.yes_attendees.length)
+ assert_equal(1, event.no_attendees.length)
+ assert_equal(u2.display_name, event.yes_attendees[0].user.display_name)
+ end
end