Clase para los eventos. Es subclase de Document, por lo que su tabla es
documents
Días de antelación para las alertas de eventos de la AM
Es un atributo que sólo se usa en el formulario de contenido adicional para un evento.
Información sobre qué periodistas pueden ir al evento
# File app/models/event.rb, line 438 def self.next4streaming # Eventos con streaming que empiezan dentro de 5 horas o menos y no han acabado. # self.published.translated.current.with_streaming.map {|evt| evt if evt.streaming_for?(subsite) && (evt.starts_at <= Time.now + 5.hours) && (evt.ends_at > Time.now)}.compact # Eventos con streaming del día. Los que no están traducidos también salen en la lista. self.published.current.with_streaming.map {|evt| evt if evt.streaming_for?("irekia")}.compact end
El nombre de la agenda para los eventos compartidos es “Agenda compartida”.
# File app/models/event.rb, line 351 def self.schedule_name I18n.translate('sadmin.events.agenda_compartida') end
Los eventos que se muestran en Irekia corresponden a una de las tres secciones: actos, acciones y eventos. Esta función devuelve la lista con los nombres de estas secciones.
# File app/models/event.rb, line 247 def self.show_in_opts [] #["actos", "acciones", "eventos"] end
# File app/models/event.rb, line 56 def alert_this_change=(val) @alert_this_change = val.to_i return @alert_this_change end
# File app/models/event.rb, line 222 def alertable if self.is_private? val = false else if self.attributes['alertable'].nil? val = true else val = self.attributes['alertable'] end end return val end
# File app/models/event.rb, line 571 def all_journalists=(val) if (val.to_i > 0) self.has_photographers = true self.has_journalists = true else self.has_journalists = false end end
# File app/models/event.rb, line 584 def all_journalists? self.all_journalists end
Devuelve true si el streaming del evento está anunciado.
# File app/models/event.rb, line 452 def announced? self.stream_flow && self.stream_flow.announced? && self.stream_flow.event_id.eql?(self.id) end
Devuelve los nombres de todos los asistemntes: políticos e invitados
# File app/models/event.rb, line 288 def attendee_names(locale = I18n.locale.to_s) speaker4locale = nil if self.speaker.present? speaker4locale = self.send("speaker_#{locale}").present? ? self.send("speaker_#{locale}") : self.speaker end politicians4locale = self.politicians.map {|politician| "#{politician.public_name_and_role(locale)}"} (politicians4locale + [speaker4locale]).compact.join(", ") end
Copia los datos del evt
a self
.
# File app/models/event.rb, line 387 def copy_from(evt) evt_attr = evt.attributes evt_attr.delete('id') evt_attr.each do |at, value| if self.respond_to?("#{at}=") self.send("#{at}=", value) end end if evt.is_a?(ScheduleEvent) # self.is_private = true # By default the event goes to schedule department if present or to GV. self.organization_id = evt.organization_id || Organization.find_by_internal_id(0).id end self end
Tipos de cobertura para el evento.
# File app/models/event.rb, line 424 def cov_types_pretty(locale=I18n.locale.to_s) cov_types = [] ["irekia_coverage_audio", "irekia_coverage_video", "irekia_coverage_photo", "irekia_coverage_article"].each do |cov_type| cov_types << I18n.t("events.#{cov_type}", :locale => locale) if self.send("#{cov_type}?") end if se = streaming_for_pretty(locale) cov_types.push "streaming en #{se}" unless se.blank? end cov_types.compact end
Devuelve el status actual del evento: passed, programmed о future.
# File app/models/event.rb, line 467 def current_status status = "future" if self.ends_at < Time.zone.now status = "passed" else status = "programmed" if self.starts_at.to_date.eql?(Date.today) end status end
Descripción formateada para ical
# File app/models/event.rb, line 326 def description_for_ics description = "#{self.organization.name}.\n" description << "#{self.attendee_names}.\n" description << self.body.strip_html return description end
Devuelve el Tag
relacionado con la sección de Irekia donde
sale en evento.
# File app/models/event.rb, line 278 def irekia_tag for i in Event.show_in_opts res = self.tags.detect {|t| t.name_es.eql?("Irekia::#{i.capitalize}") } return res unless res.nil? end nil end
El evento puede eliminarse por completo si no hay que notificar sobre su eliminación
# File app/models/event.rb, line 334 def is_destroyable? if (!self.deleted? && self.alerts.sent.count > 0) || (self.deleted? && self.alerts.unsent.count > 0) false else true end end
Devuelve true
si el evento es privado y false
si
no lo es.
# File app/models/event.rb, line 236 def is_private? self.published_at.nil? end
Método auxiliar. Un evento es púbico si no es privado.
# File app/models/event.rb, line 241 def is_public? !self.is_private? end
# File app/models/event.rb, line 137 def location_data_provided if self.is_public? && self.place.present? unless eloc = EventLocation.find_by_place_and_city_and_address(self.place, self.city, self.location_for_gmaps) errors.add_on_empty :city errors.add_on_empty :location_for_gmaps end end end
Noticias y videos asignados al evento No se puede usar has_many through con “polymorphic associations”.
# File app/models/event.rb, line 493 def news self.related_items.map {|rel| rel.eventable if rel.eventable.is_a?(News)}.compact end
# File app/models/event.rb, line 537 def news_ids self.related_items.map {|rel| rel.eventable_id if rel.eventable.is_a?(News)}.compact end
# File app/models/event.rb, line 549 def news_ids=(ids_list) self.set_related_items(ids_list, News) end
Devuelve true si el evento se está emitiendo.
# File app/models/event.rb, line 447 def on_air? self.stream_flow && self.stream_flow.on_air? && self.stream_flow.event_id.eql?(self.id) end
Periodistas y fotógrafos
# File app/models/event.rb, line 554 def only_photographers=(val) if (val.to_i > 0) self.has_photographers = true self.has_journalists = false else self.has_photographers = false end end
# File app/models/event.rb, line 567 def only_photographers? self.only_photographers end
Devuelve la lista de eventos que se solapan con self
# File app/models/event.rb, line 457 def overlapped Event.find(:all, :conditions => ["(starts_at < ?) AND (ends_at > ?)", self.ends_at, self.starts_at]) - [self] end
Devuelve la lista de eventos con streaming en directo que se solapan con
self
.
# File app/models/event.rb, line 462 def overlapped_streaming self.overlapped.map {|evt| evt if evt.streaming_live?}.compact end
Si el valor asignado desde el formulario es -1 marcamos el evento como privado. Si el valor es 0, el evento es público. NOTA: Estos valores vienen del formulario y son del tipo String
# File app/models/event.rb, line 367 def schedule_id=(val) if val.to_s.eql?("0") self.published_at = Time.zone.now else self.published_at = nil self.alertable = false self.alert_this_change = 0 end true end
# File app/models/event.rb, line 355 def schedule_name Event.schedule_name end
Devuelve el nombre de la sección donde sale el evento en Irekia.
# File app/models/event.rb, line 253 def show_in res = "" for i in Event.show_in_opts res = i if self.tag_list_es.include?("Irekia::#{i.capitalize}") end res end
Asigna el Tag
correspondiente a la sección de Irekia donde
sale el evento. El valor que se pasa tiene que ser alguna de las opciones
que devuelve el método show_in_opts
.
# File app/models/event.rb, line 263 def show_in=(val) if Event.show_in_opts.include?(val) self.tag_list = self.tag_list - Event.show_in_opts.map {|opt| "Irekia::#{opt.capitalize}"} self.tag_list << "Irekia::#{val.capitalize}" end end
# File app/models/event.rb, line 410 def streaming_for?(place) self.streaming_places.include?(place) end
# File app/models/event.rb, line 168 def streaming_for_if_streaming_live if self.streaming_live sf = STREAMING4.map {|place| self.send("streaming_for_#{place}")}.uniq if sf.eql?([0]) errors.add :streaming_for, "no puede estar vacío. Tienes que elegir por lo menos una opción." end end end
# File app/models/event.rb, line 419 def streaming_for_pretty(locale=I18n.locale.to_s) self.streaming_places.map {|pl| I18n.t("events.#{pl.strip}", :locale => locale)}.to_sentence.gsub("y\sI", "e I") end
Lista de las webs donde se hará el streaming
# File app/models/event.rb, line 415 def streaming_for_pretty? self.streaming_for.present? end
# File app/models/event.rb, line 406 def streaming_places self.streaming_for.to_s.split(',') end
Comprueba que se especifica la sala de streaming, en caso de que vaya a haberlo
# File app/models/event.rb, line 148 def streaming_room if self.streaming_live if !self.stream_flow_id errors.add :streaming_room, "está sin especificar. Debes elegir la sala." else # Comprobar la sala if oe = self.overlapped_streaming.detect {|evt| evt.stream_flow_id.eql?(self.stream_flow_id)} errors.add :streaming_room, "#{self.stream_flow.title} está ocupada por el evento #{oe.title} (#{oe.pretty_dates})" end # Comprobar la web de emisión # ["irekia"].each do |place| # if self.send("streaming_for_#{place}?") && self.overlapped_streaming.detect {|evt| evt.send("streaming_for_#{place}?")} # errors.add :streaming_for, "#{place.capitalize} está ocupada." # end # end end end end
Devuelve el streaming status del evento: future, programmed, passed, announced, o live
# File app/models/event.rb, line 478 def streaming_status status = self.current_status if self.stream_flow.present? status = 'announced' if self.announced? status = 'live' if self.on_air? else status = 'empty' end status end
# File app/models/event.rb, line 178 def sync_alertable_and_alert_this_change if !self.alertable? && self.alert_this_change errors.add :alert_this_change, "no puedes alertar sobre este cambio porque las alertas para este evento están desactivadas" end end
Devuelve el evento en formato ical
# File app/models/event.rb, line 299 def to_ics(cal, &block) if self.deleted? cal.add_x_property('METHOD', 'CANCEL') else cal.add_x_property('METHOD', 'REQUEST') end cal.event do |event| event.uid = "uid_#{self.id}_irekia_euskadi_net" event.sequence = self.staff_alert_version event.summary = self.title event.description = block_given? ? yield[:description] || self.description_for_ics : self.description_for_ics event.dtstart = self.starts_at.getutc.strftime("%Y%m%dT%H%M%SZ") event.dtend = self.ends_at.getutc.strftime("%Y%m%dT%H%M%SZ") event.location = self.pretty_place event.url = yield[:url] if block_given? event.created = self.created_at.getutc.strftime("%Y%m%dT%H%M%SZ") event.last_modified = self.updated_at.getutc.strftime("%Y%m%dT%H%M%SZ") event.dtstamp = Time.now.getutc.strftime("%Y%m%dT%H%M%SZ") if self.deleted? event.status = "CANCELLED" else event.status = "CONFIRMED" end end end
Indica si el evento está traducido a lang_code
Los idiomas
disponibles son Document::LANGUAGES
# File app/models/event.rb, line 201 def translated_to?(lang_code) translated = self.send("title_#{lang_code}").present? unless self.send("body_#{I18n.default_locale.to_s}").blank? # Los eventos pueden no tener body en ningun idioma translated = translated && self.send("body_#{lang_code}").present? end return translated end
# File app/models/event.rb, line 541 def video_ids self.related_items.map {|rel| rel.eventable_id if rel.eventable.is_a?(Video)}.compact end
# File app/models/event.rb, line 545 def video_ids=(ids_list) self.set_related_items(ids_list, Video) end
# File app/models/event.rb, line 533 def videos self.related_items.map {|rel| rel.eventable if rel.eventable.is_a?(Video)}.compact end
Indica si el evento se puede cambiar de privado a público y vice versa.
# File app/models/event.rb, line 381 def visibility_can_change? true end
Crea una lista con los sitios donde este evento es visible.
# File app/models/event.rb, line 185 def visible_in show_in = [] show_in << "private" if self.is_private? show_in << "irekia" if self.published? return show_in end
See thewebfellas.com/blog/2008/11/2/goodbye-attachment_fu-hello-paperclip#comment-2415
# File app/models/event.rb, line 839 def attachment_for name @_paperclip_attachments ||= {} @_paperclip_attachments[name] ||= Attachment.new(name, self, self.class.attachment_definitions[name]) end
Los miembros de departamento tienen restrigido el lugar donde pueden publicar eventos (privados o irekia). Aunque el formulario sólo les muestra las opciones que les corresponden, nos aseguramos que no añaden eventos donde no pueden.
# File app/models/event.rb, line 625 def check_user_can_create_this_type_of_event if UserActionObserver.current_user.present? yes_he_can = false current_user = User.find(UserActionObserver.current_user) if (self.is_private? && current_user.can?("create_private", "events")) || (self.is_public? && current_user.can?("create_irekia", "events")) yes_he_can = true end if yes_he_can return true else errors.add_to_base "No puedes crear eventos de este tipo" return false end else return true end end
No todas las columnas de la tabla documents se utilizan en los eventos, por lo que nos aseguramos de que están vacías. Se llama desde before_save
# File app/models/event.rb, line 592 def disable_unnecessary_fields # self.has_comments = false, en irekia3 sí se pueden comentar los eventos # self.comments_closed = true self.has_comments_with_photos = false self.has_ratings = false # self.comments_count = 0 self.cover_photo_file_name = nil self.cover_photo_content_type = nil self.cover_photo_file_size = nil self.cover_photo_updated_at = nil end
Programa las alertas que se deberán enviar relativas a este evento. Hay dos tipos de alertas
Alertas para periodistas: Cada vez que un campo relevante del evento cambia (fecha, lugar, visibilidad…), se envía un email notificándolo. Se envían 3 días antes de su comienzo
Alertas para operadores de streaming y responsables de salas: Cuando se confirma el streaming para un evento, se envían alertas a los operadores de streaming, responsables de sala, y creador del evento para que preparen lo necesario para el streaming. Se envian 1 día antes de que comiencen
Alertas al creador del evento y el jefe de prensa del departamento del evento cuando cambia el valor del campo cobertura Irekia (así ellos saben si Irekia va a cubrir el evento o no y dónde esta el borrador de la noticia relacionada con el evento)
Solo nos preocupamos por las alertas cuando los eventos aún no han pasado. Después, da igual lo que cambien que no avisamos a nadie
# File app/models/event.rb, line 657 def schedule_alerts if self.ends_at && self.ends_at >= Time.zone.now # Aviso periodistas if (self.alertable_changed? || self.starts_at_changed? || self.ends_at_changed? || self.place_changed? || self.published_at_changed? || deleted_changed?) # logger.info "Algo ha cambiadooooooooooo #{self.is_private?} || #{self.alert_this_change}" # Borramos las alertas programadas si el evento es privado o nos han pedido que programemos nuevas if self.is_private? || self.deleted? || self.alert_this_change # logger.info "es privado o eliminado o alert this cangeeeeeeeeeeeee" EventAlert.delete_all(["spammable_type = ? AND event_id= ? AND sent_at IS NULL", 'Journalist', self.id]) if self.alertable? || (self.published_at_changed? && self.published_at.nil?) # logger.info "Es alertable o lo acabamos de convertir en privado" # Si es alertable (por lo tanto, público) alertamos a todos los que corresponda # Hay un caso en el que el evento sea alertable == false pero que debamos alertar a los que # ya hemos alertado, y es el caso en el que acabamos de convertir el evento en privado. En este # caso sólo hay que alertar a los que ya alertamos self.journalist_alert_version += 1 event_department_id = self.organization.is_a?(Department) ? self.organization_id : self.organization.department.id active_subscriptors_for_this_department = Subscription.active.find(:all, :conditions => "subscriptions.department_id = #{event_department_id}").map(&:user_id) # Debería ser así pero como en spammable_type hemos desglosado en Journalist, etc # no funciona porque "has_many :event_alerts, :as => :spammable" añade la condicion # "spammable_type='User'" que no nos vale # alerted_subscriptions_for_this_event = Subscription.active.find :all, # :joins => {:journalist => :event_alerts}, # :conditions => ["subscriptions.department_id = #{event_department_id} # AND event_id = ? AND spammable_type = ?", self.id, "Journalist"] alerted_subscriptions_for_this_event = Subscription.active.find :all, :joins => "INNER JOIN event_alerts ON event_alerts.spammable_id = users.id AND event_alerts.spammable_type = 'Journalist'", :conditions => ["subscriptions.department_id = #{event_department_id} AND event_id = ? AND spammable_type = ?", self.id, "Journalist"] alerted_subscriptors_for_this_event = alerted_subscriptions_for_this_event.map(&:user_id) # logger.info "alerted_subscriptors_for_this_event: #{alerted_subscriptors_for_this_event.inspect}" alerted_subscriptors_for_this_event.each do |alerted_user_id| if self.published_at.nil? alert_send_at = self.starts_at - ALERTS_BEFOREHAND else alert_send_at = Time.zone.now end # Se les alerta tanto si el evento es alertable como si lo acabamos de convertir en privado self.alerts.build :spammable_id => alerted_user_id, :spammable_type => "Journalist", :version => self.journalist_alert_version, :send_at => alert_send_at end if self.alertable? not_alerted_for_this_event = active_subscriptors_for_this_department - alerted_subscriptors_for_this_event not_alerted_for_this_event.each do |not_alerted_user_id| if self.is_public? alert_send_at = self.starts_at - ALERTS_BEFOREHAND self.alerts.build :spammable_id => not_alerted_user_id, :spammable_type => "Journalist", :version => self.journalist_alert_version, :send_at => alert_send_at end end end end end end # Aviso para el staff sobre cambios en la cobertura, el streaming, las fechas y el sitio if self.published_at_changed? || self.starts_at_changed? || self.ends_at_changed? || self.place_changed? || streaming_live_changed? || deleted_changed? || self.stream_flow_id_changed? || self.streaming_for_changed? || self.irekia_coverage_changed? self.staff_alert_version += 1 EventAlert.delete_all(["spammable_type <> ? AND event_id= ? AND sent_at IS NULL", 'Journalist', self.id]) this_event_alert_recipients = [] alert_notify_about = 'streaming' if self.stream_flow && self.stream_flow.send_alerts? this_event_alert_recipients += self.stream_flow.room_managers this_event_alert_recipients += StreamingOperator.find(:all) this_event_alert_recipients += [User.find(self.created_by)] if self.created_by end # Avisamos a los responsables de la sala antigua if self.stream_flow_id != self.stream_flow_id_was && !self.stream_flow_id_was.nil? && StreamFlow.find(self.stream_flow_id_was).send_alerts? this_event_alert_recipients += StreamFlow.find(self.stream_flow_id_was).room_managers this_event_alert_recipients += StreamingOperator.find(:all) this_event_alert_recipients += [User.find(self.created_by)] if self.created_by end # Si ha cambiado el valor de "cobertura irekia" avisamos al creador y el jefe de prensa del dept. if self.irekia_coverage_changed? alert_notify_about = 'coverage' this_event_alert_recipients += [User.find(self.created_by)] if self.created_by DepartmentEditor.find(:all, :conditions => {:department_id => self.department.id}).each do |editor| this_event_alert_recipients.push editor end end this_event_alert_recipients.uniq! this_event_alert_recipients.each do |recipient| create_alert = false last_sent_alert = EventAlert.find :first, :conditions => ["event_id = ? AND spammable_id = ? AND spammable_type = ?", self.id, recipient.id, recipient.class.to_s], :order => "sent_at DESC" if !last_sent_alert if self.is_public? if self.streaming_live? logger.info "No hay alertas enviadas. Si, creamos" create_alert = true alert_send_at = self.starts_at - 1.day end if self.irekia_coverage_changed? logger.info "Aviso sobre cambio en la cobertura" create_alert = true alert_send_at = self.starts_at - 1.day end else logger.info "Evento sin confirmar o sin publicar. No, no creamos alertas." end else logger.info "Sí, sí creamos" create_alert = true if self.published_at.nil? alert_send_at = self.starts_at - 1.days else alert_send_at = Time.zone.now end end if create_alert logger.info "Creando alerta para #{recipient.class.to_s} #{recipient.id.to_s}" self.alerts.build :spammable_id => recipient.id, :spammable_type => recipient.class.to_s, :version => self.staff_alert_version, :send_at => alert_send_at, :notify_about => alert_notify_about end end end end return true end
Programa el tweet referente a este evento, si está publicado y se muestra en Irekia. Se tweetea 3 días antes de su comienzo.
# File app/models/event.rb, line 798 def schedule_tweets # Si ha pasado más de un mes de este evento, no lo twitteamos if self.starts_at && self.starts_at >= 1.month.ago # Primero borramos los tweets pendientes de este evento, por si ha cambiado la fecha DocumentTweet.delete_all(["document_id= ? AND tweeted_at IS NULL", self.id]) Event::LANGUAGES.each do |l| if self.published? && self.translated_to?(l.to_s) && !DocumentTweet.exists?(:document_id => self.id, :tweet_locale => l.to_s) self.tweets.build(:tweet_account => "irekia_agenda", :tweet_at => self.starts_at - 3.days, :tweet_locale => l.to_s) end end end return true end
Asigna el valor por defecto del campo l_attends
si este no
tiene ningún valor asignado.
# File app/models/event.rb, line 605 def set_l_attends self.l_attends ||= false true end
Los eventos no se pueden eliminar completamente si se han enviado alertas sobre su presencia, hasta que no se envia otra alerta sobre su eliminación. Cuando se marca como eliminado, se pasa a borrador para que deje de aparecer en la parte pública. Se llama desde before_save
# File app/models/event.rb, line 614 def set_to_draft_if_deleted # asi nos aseguramos de que no aparecera en la parte publica if self.deleted? self.published_at = nil end return true end
Asegura que no tiene sala de streaming si no hay streaming
# File app/models/event.rb, line 814 def sync_streaming_and_room if !self.streaming_live self.stream_flow_id = nil else return true end end