|
@@ -3,6 +3,7 @@
|
3
|
3
|
# A Person may access the system by creating a User, and may have at most one
|
4
|
4
|
# User.
|
5
|
5
|
class Person < ApplicationRecord
|
|
6
|
+ include Rails.application.routes.url_helpers
|
6
|
7
|
# @!attribute first_name
|
7
|
8
|
# @return [String]
|
8
|
9
|
# the person's first name. ('Vincent' in 'Vincent van Gogh'.)
|
|
@@ -102,6 +103,93 @@ class Person < ApplicationRecord
|
102
|
103
|
person_calendar_url self.calendar_token
|
103
|
104
|
end
|
104
|
105
|
|
|
106
|
+ # @return [Icalendar::Calendar]
|
|
107
|
+ # this Person's upcoming activities feed.
|
|
108
|
+ def calendar_feed(skip_absent = false)
|
|
109
|
+ cal = Icalendar::Calendar.new
|
|
110
|
+ cal.x_wr_calname = 'Aardbei'
|
|
111
|
+
|
|
112
|
+ tzid = 1.seconds.since.time_zone.tzinfo.name
|
|
113
|
+
|
|
114
|
+ selection = self
|
|
115
|
+ .participants
|
|
116
|
+ .joins(:activity)
|
|
117
|
+ .where('"end" > ?', 3.months.ago)
|
|
118
|
+
|
|
119
|
+ if skip_absent
|
|
120
|
+ selection = selection
|
|
121
|
+ .where.not(attending: false)
|
|
122
|
+ end
|
|
123
|
+
|
|
124
|
+ selection.each do |p|
|
|
125
|
+ a = p.activity
|
|
126
|
+
|
|
127
|
+ description_items = []
|
|
128
|
+ # The description consists of the following parts:
|
|
129
|
+ # - The Participant's response and notes (if set),
|
|
130
|
+ # - The Activity's description (if not empty),
|
|
131
|
+ # - The names of the organizers,
|
|
132
|
+ # - Subgroup information, if applicable,
|
|
133
|
+ # - The URL.
|
|
134
|
+
|
|
135
|
+ # Response
|
|
136
|
+ yourresponse = "#{I18n.t 'activities.participant.yourresponse'}: #{p.human_attending}"
|
|
137
|
+
|
|
138
|
+ if p.notes.present?
|
|
139
|
+ yourresponse << " (#{p.notes})"
|
|
140
|
+ end
|
|
141
|
+
|
|
142
|
+ description_items << yourresponse
|
|
143
|
+
|
|
144
|
+ # Description
|
|
145
|
+ description_items << a.description if a.description.present?
|
|
146
|
+
|
|
147
|
+ # Organizers
|
|
148
|
+ orgi = a.organizer_names
|
|
149
|
+ orgi_names = orgi.join ', '
|
|
150
|
+ orgi_line = case orgi.count
|
|
151
|
+ when 0 then I18n.t 'activities.organizers.no_organizers'
|
|
152
|
+ when 1 then "#{I18n.t 'activities.organizers.one'}: #{orgi_names}"
|
|
153
|
+ else "#{I18n.t 'activities.organizers.other'}: #{orgi_names}"
|
|
154
|
+ end
|
|
155
|
+
|
|
156
|
+ description_items << orgi_line
|
|
157
|
+
|
|
158
|
+ # Subgroups
|
|
159
|
+ if a.subgroups.any?
|
|
160
|
+ if p.subgroup
|
|
161
|
+ description_items << "#{I18n.t 'activities.participant.yoursubgroup'}: #{p.subgroup}"
|
|
162
|
+ end
|
|
163
|
+
|
|
164
|
+ subgroup_names = a.subgroups.map(&:name).join ', '
|
|
165
|
+ description_items << "#{I18n.t 'activerecord.models.subgroup.other'}: #{subgroup_names}"
|
|
166
|
+
|
|
167
|
+ end
|
|
168
|
+
|
|
169
|
+ # URL
|
|
170
|
+ a_url = group_activity_url a.group, a
|
|
171
|
+ description_items << a_url
|
|
172
|
+
|
|
173
|
+ cal.event do |e|
|
|
174
|
+ e.uid = a_url
|
|
175
|
+ e.dtstart = Icalendar::Values::DateTime.new a.start, tzid: tzid
|
|
176
|
+ e.dtend = Icalendar::Values::DateTime.new a.end, tzid: tzid
|
|
177
|
+
|
|
178
|
+ e.status = p.ical_attending
|
|
179
|
+
|
|
180
|
+ e.summary = a.name
|
|
181
|
+ e.location = a.location
|
|
182
|
+
|
|
183
|
+ e.description = description_items.join "\n"
|
|
184
|
+
|
|
185
|
+ e.url = a_url
|
|
186
|
+ end
|
|
187
|
+ end
|
|
188
|
+
|
|
189
|
+ cal.publish
|
|
190
|
+ cal
|
|
191
|
+ end
|
|
192
|
+
|
105
|
193
|
private
|
106
|
194
|
# Assert that the person's birth date, if any, lies in the past.
|
107
|
195
|
def birth_date_cannot_be_in_future
|