fiedl/your_platform

View on GitHub
app/models/event.rb

Summary

Maintainability
B
4 hrs
Test Coverage
class Event < ApplicationRecord

  validates :start_at, presence: true
  before_validation -> { self.start_at ||= self.created_at || Time.zone.now }

  has_dag_links ancestor_class_names: %w(Group Page), descendant_class_names: %w(Group Page Post), link_class_name: 'DagLink'
  has_many :attachments, as: :parent, dependent: :destroy

  scope :important, -> { where(publish_on_global_website: true) }
  scope :commers, -> { where("name like ? or name like ?", "%commers%", "%kommers%") }
  scope :wartburgfest, -> { where("name like ?", "%wartburgfest%") }
  scope :wingolfsseminar, -> { where("name like ?", "%wingolfsseminar%") }
  scope :bundesconvent, -> { where_like name: ["Chargiertenconvent", "Vertreterconvent"] }


  include Structureable
  include EventGraph
  include Navable
  include EventGroups
  include EventContactPeople
  include EventAttendees
  include EventAvatar


  # General Properties
  # ==========================================================================================

  def as_json(options = {})
    super(options).merge({
      group_id: group_id,
      # contact_person_id: contact_person_id  # FIXME: Add this back when we have a more performant association for contact people.
    })
  end

  # The title, i.e. the caption of the event is its name.
  def title
    name
  end

  def to_param
    if start_at
      "#{id} #{name} #{start_at.year}-#{start_at.month}-#{start_at.day}".parameterize
    else
      "#{id} #{name}".parameterize
    end
  end

  def public?
    publish_on_local_website || publish_on_global_website
  end

  # This is used to find the event's place in the navigational structure.
  #
  def parent
    self.group
  end
  def parents
    parent ? [parent] : []
  end

  def empty?
    empty_title? && empty_description? && empty_attendees?
  end

  def non_empty?
    (! empty_description?) || (! empty_title?) || (! empty_attendees?)
  end

  def empty_title?
    self.name.in? [nil, "", I18n.t(:enter_name_of_event_here), "Neue Veranstaltung"]
  end

  def empty_description?
    self.description.blank?
  end

  def empty_attendees?
    not self.find_attendees_group.try(:members).try(:any?)
  end

  def group_name
    self.group.try(:name)
  end

  def corporation_name
    self.group.try(:corporation).try(:name)
  end

  def corporation_id
    self.group.try(:corporation).try(:id)
  end

  def avatar_url
    self.group.try(:avatar_url) || self.group.try(:corporation).try(:avatar_url)
  end

  def groups
    Group.where(id: [group_id] + parent_group_ids)
  end

  def corporations
    groups.map(&:corporation) - [nil]
  end


  # Times
  # ==========================================================================================

  def localized_start_at
    I18n.localize start_at if start_at.present?
  end
  def localized_start_at=(string)
    attribute_will_change! :start_at
    self.start_at = string.present? ? LocalizedDateTimeParser.parse(string, Time).to_time : nil
  end

  def localized_end_at
    I18n.localize end_at if end_at.present?
  end
  def localized_end_at=(string)
    attribute_will_change! :end_at
    self.end_at = string.present? ? LocalizedDateTimeParser.parse(string, Time).to_time : nil
  end

  def term
    Term.by_date start_at
  end

  def semester_calendars
    SemesterCalendar.where(group_id: corporations, term_id: term) if corporations.any? && term
  end

  def semester_calendar
    semester_calendars.first
  end
  def semester_calendar!
    semester_calendars.try(:first_or_create) || raise('cannot create semester calendar')
  end


  # Scopes
  # ==========================================================================================

  # We used to define `upcoming` as "from now on", i.e. `start_time > Time.zone.now`.
  # However, it is more convenient to see events that are currently in progress.
  # Therefore, redefining `upcoming` to hide events on the next day.#
  #
  #        yesterday  -----  today  ----  tomorrow
  #                              |= event, today, 20h
  #                         |--------------------------------------->  (upcoming)
  #
  # For events that are ongoing, e.g. started yesterday, but end tomorrow, we'll include
  # these events this scope in order to show them as long as they might be interesting.
  #
  #        yesterday  -----  today  ----  tomorrow
  #            |= event, yesterday to tomorrow =|
  #                         |--------------------------------------->  (upcoming)
  #
  # Date.today.to_datetime is 0h.
  #
  scope :upcoming, lambda { where("(start_at > ? AND end_at IS NULL) OR (end_at IS NOT NULL AND end_at > ?)", Date.today.to_datetime, Date.today.to_datetime) }

  def upcoming?
    Event.upcoming.pluck(:id).include? self.id
  end


  # Finder Methods
  # ==========================================================================================

  def self.find_all_by_user(user)
    ids = user.groups.collect { |g| g.events.pluck(:id) }.flatten
    ids += user.ancestor_event_ids
    self.where(id: ids.uniq).order(:start_at)
  end


  # Calendar Export
  # ==========================================================================================

  def to_icalendar_event
    e = Icalendar::Event.new
    if self.start_at
      e.dtstart = Icalendar::Values::DateTime.new(self.start_at.utc, tzid: 'UTC')
      e.dtend = Icalendar::Values::DateTime.new((self.end_at || self.start_at + 1.hour).utc, tzid: 'UTC')
    end
    e.summary = self.name
    e.description = self.description
    e.location = self.location
    if self.contact_people.first.try(:email).present?
      e.organizer = self.contact_people.first.email
      e.organizer.ical_params = {'CN' => self.contact_people.first.title}
    end
    e.url = self.url
    e.uid = e.url
    e.created = Icalendar::Values::DateTime.new(self.created_at.utc, tzid: 'UTC')
    e.last_modified = Icalendar::Values::DateTime.new(self.updated_at.utc, tzid: 'UTC')
    return e
  end

  def to_icalendar
    cal = Icalendar::Calendar.new
    cal.add_event self.to_icalendar_event
    cal.publish
    return cal
  end

  def to_ics
    self.to_icalendar.to_ical
  end

  def to_ical
    self.to_ics
  end

  # Example:
  #     Group.find(12).events.to_ics
  #
  def self.to_ics
    self.to_icalendar.to_ical
  end

  def self.to_icalendar
    cal = Icalendar::Calendar.new
    self.all.each do |event|
      cal.add_event event.to_icalendar_event
    end
    cal.publish
    return cal
  end

  def self.to_ical
    self.to_ics
  end
end