| Class | Event |
| In: |
app/models/event.rb
|
| Parent: | Document |
Clase para los eventos. Es subclase de Document, por lo que su tabla es documents
| STREAMING4 | = | [:agencia, :irekia, :en_diferido] | ||
| AM_INTERVAL | = | 3.days | Días de antelación para los eventos de la AM |
| draft_news | [RW] | Es un atributo que sólo se usa en el formulario de contenido adicional para un evento. |
| related_news_title | [R] | |
| schedule_id | [RW] |
Dependiendo de la sección donde se muestra un evento en OpenIrekia, al evento le corresponde un Tag u otro. Esta función devuelve la lista con los tags que corresponden al evento.
# File app/models/event.rb, line 227
227: def self.irekia_tags
228: self.show_in_opts.map {|opt| Tag.find_by_name_es("OpenIrekia::#{opt.capitalize}")}.compact
229: end
# File app/models/event.rb, line 432
432: def self.next4streaming(subsite)
433: finder = subsite.eql?('agencia') ? self.send('in_agencia') : self.send('in_irekia')
434:
435: # Eventos con streaming que empiezan dentro de 5 horas o menos y no han acabado.
436: # finder.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
437:
438: # Eventos con streaming del día. Los que no están traducidos también salen en la lista.
439: finder.published.current.with_streaming
440: end
El nombre de la agenda para los eventos compartidos es "Agenda compartida".
# File app/models/event.rb, line 356
356: def self.schedule_name
357: I18n.translate('sadmin.events.agenda_compartida')
358: end
Los eventos que se muestran en OpenIrekia 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 221
221: def self.show_in_opts
222: ["actos", "acciones", "eventos"]
223: end
Devuelve true si el streaming del evento está anunciado.
# File app/models/event.rb, line 448
448: def announced?(subsite)
449: self.stream_flow && self.stream_flow.announced?(subsite) && self.stream_flow.event_id.eql?(self.id)
450: end
# File app/models/event.rb, line 189
189: def confirmed_and_shown?
190: !self.draft? && (self.show_in_irekia || self.show_in_agencia)
191: end
# File app/models/event.rb, line 193
193: def confirmed_and_shown_in_agencia?
194: !self.draft? && self.show_in_agencia
195: end
Copia los datos del evt a self.
# File app/models/event.rb, line 384
384: def copy_from(evt)
385: evt_attr = evt.attributes
386: evt_attr.delete('id')
387: evt_attr.each do |at, value|
388: if self.respond_to?("#{at}=")
389: self.send("#{at}=", value)
390: end
391: end
392:
393: if evt.is_a?(ScheduleEvent)
394: # self.is_private = true
395:
396: # Por defecto el evento va a la agenda del departamento o a la del departamento con <tt>internal_id=1</tt>
397: self.organization_id = evt.organization_id || Organization.find_by_internal_id(1).id
398: end
399:
400: self
401: end
# File app/models/event.rb, line 420
420: def cov_types_pretty(locale=I18n.locale)
421: cov_types = []
422: ["irekia_coverage_audio", "irekia_coverage_video", "irekia_coverage_photo", "irekia_coverage_article"].each do |cov_type|
423: cov_types << I18n.t("events.#{cov_type}", :locale => locale) if self.send("#{cov_type}?")
424: end
425: if se = streaming_for_pretty(locale)
426: cov_types.push "streaming en #{se}" unless se.blank?
427: end
428: cov_types.compact
429: end
Descripción formateada para ical
# File app/models/event.rb, line 289
289: def description_for_ics
290: description = "#{self.organization.name}.\n"
291: description << "#{self.speaker}.\n" if self.speaker.present?
292: description << self.body.strip_html
293: return description
294: end
Devuelve el Tag relacionado con la sección de OpenIrekia donde sale en evento.
# File app/models/event.rb, line 242
242: def irekia_tag
243: for i in Event.show_in_opts
244: res = self.tags.detect {|t| t.name_es.eql?("OpenIrekia::#{i.capitalize}") }
245: return res unless res.nil?
246: end
247: nil
248: end
El evento puede eliminarse por completo si no hay que notificar sobre su eliminación
# File app/models/event.rb, line 333
333: def is_destroyable?
334: if (!self.deleted? && self.alerts.sent.count > 0) || (self.deleted? && self.alerts.unsent.count > 0)
335: false
336: else
337: true
338: end
339: end
Si el valor de val es false el evento es privado y por lo tanto se asigna false como valor de los campos show_in_irekia y show_in_agencia.
# File app/models/event.rb, line 153
153: def is_private=(val)
154: if val
155: self.show_in_irekia = false
156: self.show_in_agencia = false
157: end
158: end
Devuelve true si el evento es privado y false si no lo es.
# File app/models/event.rb, line 147
147: def is_private?
148: !show_in_irekia? && !show_in_agencia?
149: end
Método auxiliar. Un evento es púbico si no es privado.
# File app/models/event.rb, line 184
184: def is_public?
185: !self.is_private?
186: end
# File app/models/event.rb, line 514
514: def news_ids
515: self.related_items.map {|rel| rel.eventable_id if rel.eventable.is_a?(News)}.compact
516: end
# File app/models/event.rb, line 526
526: def news_ids=(ids_list)
527: self.set_related_items(ids_list, News)
528: end
Devuelve true si el evento se está emitiendo.
# File app/models/event.rb, line 443
443: def on_air?(subsite)
444: self.stream_flow && self.stream_flow.on_air?(subsite) && self.stream_flow.event_id.eql?(self.id)
445: end
Periodistas y fotógrafos
# File app/models/event.rb, line 531
531: def only_photographers?
532: self.has_photographers? && !self.has_journalists?
533: end
Devuelve la lista de eventos que se solapan con self
# File app/models/event.rb, line 453
453: def overlapped
454: Event.find(:all, :conditions => ["(starts_at < ?) AND (ends_at > ?)", self.ends_at, self.starts_at]) - [self]
455: end
Devuelve la lista de eventos con streaming en directo que se solapan con self.
# File app/models/event.rb, line 458
458: def overlapped_streaming
459: self.overlapped.map {|evt| evt if evt.streaming_live?}.compact
460: end
Devuelve 1 si el evento es privado y 0 en el caso contrario.
# File app/models/event.rb, line 210
210: def private_event
211: self.is_private? ? 1 : 0
212: end
Llama el método is_private con argumento val.
# File app/models/event.rb, line 215
215: def private_event=(val)
216: self.is_private = val.to_i.eql?(1)
217: end
Indica si el evento está publicado en OpenIrekia
# File app/models/event.rb, line 198
198: def published?
199: confirmed_and_shown? && (published_at <= Time.zone.now)
200: end
Indica si el evento está publicado en agencia
# File app/models/event.rb, line 203
203: def published_in_agencia?
204: confirmed_and_shown_in_agencia? && (self.starts_at <= (Time.zone.now + AM_INTERVAL))
205: end
# File app/models/event.rb, line 492
492: def related_news_id
493: self.has_related_news? ? self.related_news.id : nil
494: end
# File app/models/event.rb, line 488
488: def related_news_title
489: @related_news_title ||= self.has_related_news? ? self.related_news.title : nil
490: end
# File app/models/event.rb, line 496
496: def related_news_title=(search_title)
497: if search_title.empty?
498: # borramos las relación noticia-evento
499: self.news_ids = []
500: @related_news_title = 'buscar noticia'
501: else
502: # sustiutimos la noticias asignada al evento por la que corresponde a _search_title_
503: if n = News.find_by_title_es(search_title)
504: self.news_ids = [n.id]
505: @related_news_title = n.title
506: end
507: end
508: end
El schedule_id es nil para los evento compartidos.
# File app/models/event.rb, line 365
365: def schedule_id
366: nil
367: end
Aunque se le asigne un valor desde el formulario, un evento comprtido siempre tiene schedule_id = nil
# File app/models/event.rb, line 370
370: def schedule_id=(val)
371: @schedule_id = nil
372: true
373: end
Devuelve el nombre de la sección donde sale el evento en OpenIrekia.
# File app/models/event.rb, line 232
232: def show_in
233: res = ""
234: for i in Event.show_in_opts
235: res = i if self.tag_list_es.include?("OpenIrekia::#{i.capitalize}")
236: end
237: res
238: end
Asigna el Tag correspondiente a la sección de OpenIrekia 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 252
252: def show_in=(val)
253: if Event.show_in_opts.include?(val)
254: self.tag_list = self.tag_list - Event.show_in_opts.map {|opt| "OpenIrekia::#{opt.capitalize}"}
255: self.tag_list << "OpenIrekia::#{val.capitalize}"
256: end
257: end
Fecha de inicio del evento para Ferret. Los eventos en la agencia se pueden ver 3 dias antes de que empiecen, por eso ponemos como fecha de inicio, 3 días antes.
# File app/models/event.rb, line 343
343: def starts_at_in_agencia_for_ferret
344: (self.starts_at - AM_INTERVAL).to_s(:number)
345: end
# File app/models/event.rb, line 407
407: def streaming_for?(place)
408: self.streaming_places.include?(place)
409: end
# File app/models/event.rb, line 123
123: def streaming_for_if_streaming_live
124: if self.streaming_live
125: sf = STREAMING4.map {|place| self.send("streaming_for_#{place}")}.uniq
126: if sf.eql?([0])
127: errors.add :streaming_for, "no puede estar vacío. Tienes que elegir por lo menos una opción."
128: end
129: end
130: end
# File app/models/event.rb, line 416
416: def streaming_for_pretty(locale=I18n.locale)
417: self.streaming_places.map {|pl| I18n.t("events.#{pl.strip}", :locale => locale)}.to_sentence.gsub("y\sI", "e I")
418: end
Lista de las webs donde se hará el streaming
# File app/models/event.rb, line 412
412: def streaming_for_pretty?
413: self.streaming_for.present?
414: end
# File app/models/event.rb, line 403
403: def streaming_places
404: self.streaming_for.to_s.split(',')
405: end
Comprueba que se especifica la sala de streaming, en caso de que vaya a haberlo
# File app/models/event.rb, line 103
103: def streaming_room
104: if self.streaming_live
105: if !self.stream_flow_id
106: errors.add :streaming_room, "está sin especificar. Debes elegir la sala."
107: else
108: # Comprobar la sala
109: if oe = self.overlapped_streaming.detect {|evt| evt.stream_flow_id.eql?(self.stream_flow_id)}
110: errors.add :streaming_room, "#{self.stream_flow.title} está ocupada por el evento #{oe.title} (#{oe.pretty_dates})"
111: end
112: # Comprobar la web de emisión
113: # ["irekia", "agencia"].each do |place|
114: # if self.send("streaming_for_#{place}?") && self.overlapped_streaming.detect {|evt| evt.send("streaming_for_#{place}?")}
115: # errors.add :streaming_for, "#{place.capitalize} está ocupada."
116: # end
117: # end
118: end
119: end
120: end
Devuelve el streaming status del evento: passed, announced, live о future.
# File app/models/event.rb, line 463
463: def streaming_status(subsite)
464: status = "future"
465: status = "passed" if self.ends_at < Time.zone.now
466: status = 'announced' if self.announced?(subsite)
467: status = 'live' if self.on_air?(subsite)
468: status
469: end
Devuelve el evento en formato ical
# File app/models/event.rb, line 260
260: def to_ics(cal, &block)
261: if self.deleted?
262: cal.add_x_property('METHOD', 'CANCEL')
263: else
264: cal.add_x_property('METHOD', 'REQUEST')
265: end
266: cal.event do |event|
267: event.uid = "uid_#{self.id}_irekia_euskadi_net"
268: event.sequence = self.staff_alert_version
269: event.summary = self.title
270: event.description = block_given? ? yield[:description] || self.description_for_ics : self.description_for_ics
271: event.dtstart = self.starts_at.getutc.strftime("%Y%m%dT%H%M%SZ")
272: event.dtend = self.ends_at.getutc.strftime("%Y%m%dT%H%M%SZ")
273: event.location = self.pretty_place
274: event.url = yield[:url] if block_given?
275: event.created = self.created_at.getutc.strftime("%Y%m%dT%H%M%SZ")
276: event.last_modified = self.updated_at.getutc.strftime("%Y%m%dT%H%M%SZ")
277: event.dtstamp = Time.now.getutc.strftime("%Y%m%dT%H%M%SZ")
278: if self.deleted?
279: event.status = "CANCELLED"
280: elsif self.confirmed?
281: event.status = "TENTATIVE"
282: else
283: event.status = "CONFIRMED"
284: end
285: end
286: end
Indica si el evento está traducido a lang_code Los idiomas disponibles son Document::LANGUAGES
# File app/models/event.rb, line 162
162: def translated_to?(lang_code)
163: translated = self.send("title_#{lang_code}").present?
164: unless self.send("body_#{I18n.default_locale}").blank?
165: # Los eventos pueden no tener body en ningun idioma
166: translated = translated && self.send("body_#{lang_code}").present?
167: end
168: return translated
169: end
# File app/models/event.rb, line 518
518: def video_ids
519: self.related_items.map {|rel| rel.eventable_id if rel.eventable.is_a?(Video)}.compact
520: end
# File app/models/event.rb, line 522
522: def video_ids=(ids_list)
523: self.set_related_items(ids_list, Video)
524: end
# File app/models/event.rb, line 510
510: def videos
511: self.related_items.map {|rel| rel.eventable if rel.eventable.is_a?(Video)}.compact
512: end
Indica si el evento se puede cambiar de privado a público y vice versa.
# File app/models/event.rb, line 378
378: def visibility_can_change?
379: true
380: end
Crea una lista con los sitios donde este evento es visible.
# File app/models/event.rb, line 133
133: def visible_in
134: show_in = []
135: show_in << "private" if self.is_private?
136: show_in << "irekia" if self.show_in_irekia?
137: show_in << "agencia" if self.show_in_agencia?
138: return show_in
139: end
Devuelve true si el evento está visible el subsite indicado como parámetro.
# File app/models/event.rb, line 142
142: def visible_in?(subsite)
143: self.visible_in.include?(subsite.to_s)
144: end
Los miembros de departamento tienen restrigido el lugar donde pueden publicar eventos (privados, irekia o agencia). 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 604
604: def check_user_can_create_this_type_of_event
605: yes_he_can = false
606: current_user = User.find(UserActionObserver.current_user)
607: if (self.is_private? && current_user.can?("create_private", "events")) || \
608: (self.show_in_irekia? && current_user.can?("create_irekia", "events")) || \
609: (self.show_in_agencia? && current_user.can?("create_agencia", "events"))
610: yes_he_can = true
611: end
612: if yes_he_can
613: return true
614: else
615: errors.add_to_base "No puedes crear eventos de este tipo"
616: return false
617: end
618: 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 539
539: def disable_unnecessary_fields
540: self.has_comments = false
541: self.comments_closed = true
542: self.has_comments_with_photos = false
543: self.has_ratings = false
544: self.comments_count = 0
545: self.cover_photo_file_name = nil
546: self.cover_photo_content_type = nil
547: self.cover_photo_file_size = nil
548: self.cover_photo_updated_at = nil
549: end
Programa las alertas que se deberán enviar relativas a este evento. Hay dos tipos de alertas
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 633
633: def schedule_alerts
634: if self.ends_at && self.ends_at >= Time.zone.now
635:
636: # Aviso periodistas
637: if self.starts_at_changed? || self.ends_at_changed? || self.place_changed? || self.state_changed? || self.show_in_agencia_changed? || deleted_changed?
638: self.journalist_alert_version += 1
639:
640: EventAlert.delete_all(["spammable_type = ? AND event_id= ? AND sent_at IS NULL", 'Journalist', self.id])
641: event_department_id = self.organization.is_a?(Department) ? self.organization_id : self.organization.department.id
642: Subscription.active.with_alerts.find(:all, :conditions => "subscriptions.department_id = #{event_department_id}").each do |subscription|
643: create_alert = false
644: last_sent_alert = EventAlert.find(:first,
645: :conditions => ["event_id = ? AND spammable_id = ? AND spammable_type = ?", self.id, subscription.user_id, "Journalist"],
646: :order => "sent_at DESC")
647: if !last_sent_alert
648: if self.confirmed_and_shown_in_agencia?
649: create_alert = true
650: alert_send_at = self.starts_at - AM_INTERVAL
651: end
652: else
653: create_alert = true
654: if self.draft?
655: alert_send_at = self.starts_at - 3.days
656: else
657: alert_send_at = Time.zone.now
658: end
659: end
660: if create_alert
661: # logger.info "Creando alerta para periodista"
662: self.alerts.build(:spammable_id => subscription.user_id, :spammable_type => "Journalist", :version => self.journalist_alert_version, :send_at => alert_send_at)
663: end
664: end
665: end
666:
667: # Aviso para el staff sobre cambios en la cobertura, el streaming, las fechas y el sitio
668: if self.show_in_agencia_changed? || self.show_in_irekia_changed? || self.starts_at_changed? || self.ends_at_changed? || \
669: self.place_changed? || self.state_changed? || streaming_live_changed? || deleted_changed? || \
670: self.stream_flow_id_changed? || self.streaming_for_changed? || self.irekia_coverage_changed?
671: self.staff_alert_version += 1
672:
673: EventAlert.delete_all(["spammable_type <> ? AND event_id= ? AND sent_at IS NULL", 'Journalist', self.id])
674:
675: this_event_alert_recipients = []
676: alert_notify_about = 'streaming'
677: if self.stream_flow && self.stream_flow.send_alerts?
678: this_event_alert_recipients += self.stream_flow.room_managers
679: this_event_alert_recipients += StreamingOperator.find(:all)
680: this_event_alert_recipients += [User.find(self.created_by)] if self.created_by
681: end
682:
683: # Avisamos a los responsables de la sala antigua
684: 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?
685: this_event_alert_recipients += StreamFlow.find(self.stream_flow_id_was).room_managers
686: this_event_alert_recipients += StreamingOperator.find(:all)
687: this_event_alert_recipients += [User.find(self.created_by)] if self.created_by
688: end
689:
690: # Si ha cambiado el valor de "cobertura irekia" avisamos al creador y el jefe de prensa del dept.
691: if self.irekia_coverage_changed?
692: alert_notify_about = 'coverage'
693: this_event_alert_recipients += [User.find(self.created_by)] if self.created_by
694: DepartmentEditor.find(:all, :conditions => {:department_id => self.department.id}).each do |editor|
695: this_event_alert_recipients.push editor
696: end
697: end
698:
699: this_event_alert_recipients.uniq!
700: this_event_alert_recipients.each do |recipient|
701: create_alert = false
702: 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")
703: if !last_sent_alert
704: if self.confirmed_and_shown?
705: if self.streaming_live?
706: logger.info "No hay alertas enviadas. Si, creamos"
707: create_alert = true
708: alert_send_at = self.starts_at - 1.day
709: end
710: if self.irekia_coverage_changed?
711: logger.info "Aviso sobre cambio en la cobertura para el creador y el jefe de prensa"
712: create_alert = true
713: alert_send_at = self.starts_at - 1.day
714: end
715: else
716: logger.info "Evento sin confirmar o sin publicar. No, no creamos alertas."
717: end
718: else
719: # logger.info "Sí, sí creamos"
720: create_alert = true
721: if self.draft?
722: alert_send_at = self.starts_at - 1.days
723: else
724: alert_send_at = Time.zone.now
725: end
726: end
727: if create_alert
728: logger.info "Creando alerta para #{recipient.class.to_s}"
729: 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)
730: end
731: end
732: end
733: end
734: return true
735: end
Programa el tweet referente a este evento, si está publicado y se muestra en OpenIrekia. Se tweetea 3 días antes de su comienzo.
# File app/models/event.rb, line 739
739: def schedule_tweets
740: # Si ha pasado más de un mes de este evento, no lo twitteamos
741: if self.starts_at && self.starts_at >= 1.month.ago
742: # Primero borramos los tweets pendientes de este evento, por si ha cambiado la fecha
743: DocumentTweet.delete_all(["document_id= ? AND tweeted_at IS NULL", self.id])
744:
745: Event::LANGUAGES.each do |l|
746: if self.published? && self.show_in_irekia? && self.translated_to?(l) && !DocumentTweet.exists?(:document_id => self.id, :tweet_locale => l)
747: self.tweets.build(:tweet_account => "irekia_agenda", :tweet_at => self.starts_at - 3.days, :tweet_locale => l)
748: end
749: end
750: end
751: return true
752: end
Asigna el valor del campo draft. Si el evento es privado, draft = true. Si el evento es público, el valor de draft es true si el evento no está confirmado y false si el evento está confirmado.
# File app/models/event.rb, line 579
579: def set_draft_value
580: if self.is_private?
581: self.draft = true
582: else
583: self.draft = !self.state.eql?("confirmado")
584: end
585: return true
586: end
Asigna el valor por defecto del campo l_attends si este no tiene ningún valor asignado.
# File app/models/event.rb, line 571
571: def set_l_attends
572: self.l_attends ||= false
573: true
574: end
Pone el valor correcto para publication_date a partir del valor de otros atributos. Se llama desde before_save
# File app/models/event.rb, line 553
553: def set_publication_date
554: if self.is_private?
555: self.published_at = nil
556: else
557: if self.show_in_agencia? && !self.show_in_irekia?
558: self.published_at = self.starts_at - AM_INTERVAL
559: else
560: if self.show_in_irekia? && self.confirmed?
561: self.published_at = Time.zone.now
562: else
563: self.published_at = nil
564: end
565: end
566: end
567: return true
568: end
Asigna related_items para cada uno de los ids y el tipo indicado.
# File app/models/event.rb, line 764
764: def set_related_items(ids_list, item_type)
765: Event.transaction do
766: self.related_items.map {|rel| rel if rel.eventable.is_a?(item_type)}.compact.each do |rel|
767: if ids_list.include?(rel.eventable_id)
768: ids_list.delete(rel.eventable_id)
769: else
770: rel.destroy
771: end
772: end
773: ids_list.each do |new_id|
774: self.related_items.create(:eventable_type => item_type, :eventable_id => new_id)
775: end
776: end
777: 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 592
592: def set_to_draft_if_deleted
593: # asi nos aseguramos de que no aparecera en la parte publica
594: if self.deleted?
595: self.draft = true
596: self.state = "previsto"
597: end
598: return true
599: end