Sprankelprachtig aan/afmeldsysteem

person.rb 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. # A person represents a human being. A Person may be a Member in one or more
  2. # Groups, and be a Participant in any number of events of those Groups.
  3. # A Person may access the system by creating a User, and may have at most one
  4. # User.
  5. class Person < ApplicationRecord
  6. include Rails.application.routes.url_helpers
  7. # @!attribute first_name
  8. # @return [String]
  9. # the person's first name. ('Vincent' in 'Vincent van Gogh'.)
  10. #
  11. # @!attribute infix
  12. # @return [String]
  13. # the part of a person's surname that is not taken into account when
  14. # sorting by surname. ('van' in 'Vincent van Gogh'.)
  15. #
  16. # @!attribute last_name
  17. # @return [String]
  18. # the person's surname. ('Gogh' in 'Vincent van Gogh'.)
  19. #
  20. # @!attribute birth_date
  21. # @return [Date]
  22. # the person's birth date.
  23. #
  24. # @!attribute email
  25. # @return [String]
  26. # the person's email address.
  27. #
  28. # @!attribute calendar_token
  29. # @return [String]
  30. # the calendar token that can be used to open this Person's events as an
  31. # ICAL file.
  32. #
  33. # @!attribute is_admin
  34. # @return [Boolean]
  35. # whether or not the person has administrative rights.
  36. has_one :user
  37. has_many :members,
  38. dependent: :destroy
  39. has_many :participants,
  40. dependent: :destroy
  41. has_many :groups, through: :members
  42. has_many :activities, through: :participants
  43. has_secure_token :calendar_token
  44. validates :email, uniqueness: true
  45. validates :first_name, presence: true
  46. validates :last_name, presence: true
  47. validate :birth_date_cannot_be_in_future
  48. before_validation :not_admin_if_nil
  49. before_save :update_user_email, if: :email_changed?
  50. # The person's full name.
  51. def full_name
  52. if self.infix&.present?
  53. [self.first_name, self.infix, self.last_name].join(' ')
  54. else
  55. [self.first_name, self.last_name].join(' ')
  56. end
  57. end
  58. # The person's reversed name, to sort by surname.
  59. def reversed_name
  60. if self.infix
  61. [self.last_name, self.infix, self.first_name].join(', ')
  62. else
  63. [self.last_name, self.first_name].join(', ')
  64. end
  65. end
  66. # All activities where this person is an organizer.
  67. def organized_activities
  68. self.participants.includes(:activity).where(is_organizer: true)
  69. end
  70. # Create multiple Persons from data found in a csv file, return those.
  71. def self.from_csv(content)
  72. reader = CSV.parse(content, { headers: true, skip_blanks: true })
  73. result = []
  74. reader.each do |row|
  75. p = Person.find_by(email: row['email'])
  76. if not p
  77. p = Person.new
  78. p.first_name = row['first_name']
  79. p.infix = row['infix']
  80. p.last_name = row['last_name']
  81. p.email = row['email']
  82. p.birth_date = Date.strptime(row['birth_date']) unless row['birth_date'].blank?
  83. p.save!
  84. end
  85. result << p
  86. end
  87. return result
  88. end
  89. # @return [String]
  90. # the URL to access this person's calendar.
  91. def calendar_url
  92. person_calendar_url self.calendar_token
  93. end
  94. # @return [Icalendar::Calendar]
  95. # this Person's upcoming activities feed.
  96. def calendar_feed(skip_absent = false)
  97. cal = Icalendar::Calendar.new
  98. cal.x_wr_calname = 'Aardbei'
  99. tzid = 1.seconds.since.time_zone.tzinfo.name
  100. selection = self
  101. .participants
  102. .joins(:activity)
  103. .where('"end" > ?', 3.months.ago)
  104. if skip_absent
  105. selection = selection
  106. .where.not(attending: false)
  107. end
  108. selection.each do |p|
  109. a = p.activity
  110. description_items = []
  111. # The description consists of the following parts:
  112. # - The Participant's response and notes (if set),
  113. # - The Activity's description (if not empty),
  114. # - The names of the organizers,
  115. # - Subgroup information, if applicable,
  116. # - The URL.
  117. # Response
  118. yourresponse = "#{I18n.t 'activities.participant.yourresponse'}: #{p.human_attending}"
  119. if p.notes.present?
  120. yourresponse << " (#{p.notes})"
  121. end
  122. description_items << yourresponse
  123. # Description
  124. description_items << a.description if a.description.present?
  125. # Organizers
  126. orgi = a.organizer_names
  127. orgi_names = orgi.join ', '
  128. orgi_line = case orgi.count
  129. when 0 then I18n.t 'activities.organizers.no_organizers'
  130. when 1 then "#{I18n.t 'activities.organizers.one'}: #{orgi_names}"
  131. else "#{I18n.t 'activities.organizers.other'}: #{orgi_names}"
  132. end
  133. description_items << orgi_line
  134. # Subgroups
  135. if a.subgroups.any?
  136. if p.subgroup
  137. description_items << "#{I18n.t 'activities.participant.yoursubgroup'}: #{p.subgroup}"
  138. end
  139. subgroup_names = a.subgroups.map(&:name).join ', '
  140. description_items << "#{I18n.t 'activerecord.models.subgroup.other'}: #{subgroup_names}"
  141. end
  142. # URL
  143. a_url = group_activity_url a.group, a
  144. description_items << a_url
  145. cal.event do |e|
  146. e.uid = a_url
  147. e.dtstart = Icalendar::Values::DateTime.new a.start, tzid: tzid
  148. e.dtend = Icalendar::Values::DateTime.new a.end, tzid: tzid
  149. e.status = p.ical_attending
  150. e.summary = a.name
  151. e.location = a.location
  152. e.description = description_items.join "\n"
  153. e.url = a_url
  154. end
  155. end
  156. cal.publish
  157. cal
  158. end
  159. private
  160. # Assert that the person's birth date, if any, lies in the past.
  161. def birth_date_cannot_be_in_future
  162. if self.birth_date && self.birth_date > Date.today
  163. errors.add(:birth_date, I18n.t('person.errors.cannot_future'))
  164. end
  165. end
  166. # Explicitly force nil to false in the admin field.
  167. def not_admin_if_nil
  168. self.is_admin ||= false
  169. end
  170. # Ensure the person's user email is updated at the same time as the person's
  171. # email.
  172. def update_user_email
  173. if not self.user.nil?
  174. self.user.update!(email: self.email)
  175. end
  176. end
  177. end