Sprankelprachtig aan/afmeldsysteem

person.rb 5.2KB

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