<commit_before>class Event
  include Mongoid::Document
  include Mongoid::Timestamps
  include Mongoid::Slug
  include RendersTemplates

  include Tag::Taggable

  attr_accessor :head_assets, :body_assets, :cached_render

  has_many :reminders

  field :name,            type: String
  field :scheduled_at,    type: Time
  field :status,          type: String,  default: 'Upcoming'
  field :template_data,   type: Hash,    default: {}
  field :activities,      type: Hash,    default: {}
  field :content_updates, type: Array,   default: []

  slug :name, permanent: true

  embeds_many :content_areas

  validates :name, presence: true, unique_slug: { message: "generates a slug that has already been taken" }
  validates_datetime :scheduled_at, { message: 'must be a valid date/time' }

  belongs_to :event_template
  has_and_belongs_to_many :embed_templates
  has_and_belongs_to_many :users
  has_one :current_window, class_name: 'UpdateWindow', validate: false

  default_scope order_by([[:status, :desc], [:scheduled_at, :desc]])

  before_save :update_template_data, :generate_content_areas, :cache_render

  after_save do
    UpdateWindow.create(event: self) if self.current_window.nil?
    Cacher.cache_events([self])
    Cacher.cache_archives # regenerate the archives
  end

  scope :upcoming, where(status: 'Upcoming').order_by([[:scheduled_at, :asc]])
  scope :finished, where(status: 'Finished').order_by([[:scheduled_at, :desc]])


  # Mongoid::Slug changes this to `self.slug`. Undo that.
  def to_param
    id.to_s
  end

  def head_assets
    @@head_assets ||= render_to_string partial: 'shared/head_assets'
  end

  def body_assets
    @@body_assets ||= render_to_string partial: 'shared/body_assets'
  end

  def reminder_form
    @reminder_form ||= render_to_string partial: 'shared/reminder_form', locals: { event: self }
  end

  def script_id
    @script_id ||= render_to_string partial: 'shared/script_id', locals: { event: self }
  end

  def cache_render
    @cached_render = render
  rescue V8::JSError
    errors.add(:base, "template #{self.event_template.name} contains errors" )
    errors.blank?
  rescue ActionView::Template::Error
    errors.add(:base, "one or more asset templates contain errors" )
  end

  # Render the HTML for an event page
  def render
    rendered_content = preprocess_template(event_template)
      .render_with(
        template_data.merge({
          event_reminder: reminder_form
        }))
    SiteTemplate.first.render_with({ content: rendered_content,
                                     head_assets: head_assets,
                                     body_assets: script_id + body_assets})
  end

  # Render the HTML for an embed
  def rendered_embeds
    embeds = {}
    embed_templates.each do |embed_template|
      data = template_data.merge({
        head_assets: head_assets,
        body_assets: script_id + body_assets
      })
      embeds[embed_template.slug] = preprocess_template(embed_template).render_with(data)
    end
    embeds
  end

  # Convert content areas from Handlebars to HTML
  def preprocess_template(template)
    content_areas.each do |content_area|
      # only render assets once for each type
      unless head_assets.include?(content_area.render_head)
        self.head_assets += content_area.render_head
      end
      unless body_assets.include?(content_area.render_body)
        self.body_assets += content_area.render_body
      end
      template.template.gsub!(/\{\{([\w ]*):( *)#{content_area.name} \}\}/, content_area.render)
    end
    template
  end

  def add_content_update(params)

    if self.current_window.content_updates.length > 19

      # Create a new update window and set it as the next window.
      new_window = UpdateWindow.create(previous_window: self.current_window)

      self.current_window.next_window = new_window
      self.current_window.save

      # The new window is now the current window.
      self.current_window = new_window
    end
    self.current_window.content_updates.create(params)
    self.save
    self.current_window.reload

    cache_updates
  end

  def finalize!
    self.status = "Finished"
    save!
  end

  def reopen!
    self.status = "Upcoming"
    save!
  end

  def as_json(options = {})
    super.merge(unix_scheduled_at: scheduled_at.to_i)
  end

  def as_renderable_data()
    self.template_data.merge({
      head_assets: head_assets,
      body_assets: script_id + body_assets
    })
  end

  # Public: Returns the list of taggables that share tags with this event. If
  # this event has no tags, then it returns the full passed-in collection, as
  # is.
  #
  # collection - a Collection of Taggable objects.
  #
  # Returns a filtered collection.
  def filter_by_tags(collection)
    return collection if tag_list.empty?

    # # FIXED: Do this in mongo instead of loading everything in memory.
    # collection.select do |taggable|
    #   tags = tag_list.push('global')
    #   (taggable.tag_list & tags).any?
    # end

    ids = []
    type = collection.first.class.to_s
    Tag.any_in(name: tag_list.push('global')).each do |tag|
      tag.taggable_references.where(taggable_type: type).each do |ref|
        ids.push ref.taggable_id
      end
    end
    collection.any_in(_id: ids)
  end

  protected

  def cache_updates
    Cacher.cache('/event/' + self.id.to_s + '/updates.json', self.current_window.to_json)
  end

  def update_template_data
    self.template_data ||= {}
    fresh_fields = []

    # Find all custom fields from all templates.
    templates = ([self.event_template] + self.embed_templates).compact
    templates.each do |t|
      t.custom_fields.each do |f|
        # Add to hash if needed.
        self.template_data[f] ||= ''
        # Cache the field name for the deletion step below.
        fresh_fields << f
      end if t.custom_fields
    end

    # Remove custom fields that are no longer relevant.
    self.template_data.delete_if { |k,v| !fresh_fields.include?(k) }
  end

  def generate_content_areas
    clean_record_names = []
    ([event_template] + embed_templates).each do |template|
      template.custom_areas.each do |name, area_type|
        existing = self.content_areas.where(name: name)
        clean_record_names << name
        unless existing.any?
          klass = area_type.classify.constantize
          self.content_areas << klass.new(name: name, area_type: area_type)
        else
          existing.each do |area|
            area.set(:name, name)
            area.set(:area_type, area_type)
          end
        end
      end
    end
    remove = self.content_areas.not_in name: clean_record_names
    remove.destroy_all
  end
end
<commit_msg>get content area assets in event render<commit_after>class Event
  include Mongoid::Document
  include Mongoid::Timestamps
  include Mongoid::Slug
  include RendersTemplates

  include Tag::Taggable

  attr_accessor :head_assets, :body_assets, :cached_render

  has_many :reminders

  field :name,            type: String
  field :scheduled_at,    type: Time
  field :status,          type: String,  default: 'Upcoming'
  field :template_data,   type: Hash,    default: {}
  field :activities,      type: Hash,    default: {}
  field :content_updates, type: Array,   default: []

  slug :name, permanent: true

  embeds_many :content_areas

  validates :name, presence: true, unique_slug: { message: "generates a slug that has already been taken" }
  validates_datetime :scheduled_at, { message: 'must be a valid date/time' }

  belongs_to :event_template
  has_and_belongs_to_many :embed_templates
  has_and_belongs_to_many :users
  has_one :current_window, class_name: 'UpdateWindow', validate: false

  default_scope order_by([[:status, :desc], [:scheduled_at, :desc]])

  before_save :update_template_data, :generate_content_areas, :cache_render

  after_save do
    UpdateWindow.create(event: self) if self.current_window.nil?
    Cacher.cache_events([self])
    Cacher.cache_archives # regenerate the archives
  end

  scope :upcoming, where(status: 'Upcoming').order_by([[:scheduled_at, :asc]])
  scope :finished, where(status: 'Finished').order_by([[:scheduled_at, :desc]])


  # Mongoid::Slug changes this to `self.slug`. Undo that.
  def to_param
    id.to_s
  end

  def head_assets
    @head_assets ||= render_to_string partial: 'shared/head_assets'
  end

  def body_assets
    @body_assets ||= render_to_string partial: 'shared/body_assets'
  end

  def reminder_form
    @reminder_form ||= render_to_string partial: 'shared/reminder_form', locals: { event: self }
  end

  def script_id
    @script_id ||= render_to_string partial: 'shared/script_id', locals: { event: self }
  end

  def cache_render
    @cached_render = render
  rescue V8::JSError
    errors.add(:base, "template #{self.event_template.name} contains errors" )
    errors.blank?
  rescue ActionView::Template::Error
    errors.add(:base, "one or more asset templates contain errors" )
  end

  # Render the HTML for an event page
  def render
    rendered_content = preprocess_template(event_template)
      .render_with(
        template_data.merge({
          event_reminder: reminder_form
        }))
    SiteTemplate.first.render_with({ content: rendered_content,
                                     head_assets: head_assets,
                                     body_assets: script_id + body_assets})
  end

  # Render the HTML for an embed
  def rendered_embeds
    embeds = {}
    embed_templates.each do |embed_template|
      data = template_data.merge({
        head_assets: head_assets,
        body_assets: script_id + body_assets
      })
      embeds[embed_template.slug] = preprocess_template(embed_template).render_with(data)
    end
    embeds
  end

  # Convert content areas from Handlebars to HTML
  def preprocess_template(template)
    content_areas.each do |content_area|
      # only render assets once for each type
      unless head_assets.include?(content_area.render_head)
        @head_assets += content_area.render_head
      end
      unless body_assets.include?(content_area.render_body)
        @body_assets += content_area.render_body
      end
      template.template.gsub!(/\{\{([\w ]*):( *)#{content_area.name} \}\}/, content_area.render)
    end
    template
  end

  def add_content_update(params)

    if self.current_window.content_updates.length > 19

      # Create a new update window and set it as the next window.
      new_window = UpdateWindow.create(previous_window: self.current_window)

      self.current_window.next_window = new_window
      self.current_window.save

      # The new window is now the current window.
      self.current_window = new_window
    end
    self.current_window.content_updates.create(params)
    self.save
    self.current_window.reload

    cache_updates
  end

  def finalize!
    self.status = "Finished"
    save!
  end

  def reopen!
    self.status = "Upcoming"
    save!
  end

  def as_json(options = {})
    super.merge(unix_scheduled_at: scheduled_at.to_i)
  end

  def as_renderable_data()
    self.template_data.merge({
      head_assets: head_assets,
      body_assets: script_id + body_assets
    })
  end

  # Public: Returns the list of taggables that share tags with this event. If
  # this event has no tags, then it returns the full passed-in collection, as
  # is.
  #
  # collection - a Collection of Taggable objects.
  #
  # Returns a filtered collection.
  def filter_by_tags(collection)
    return collection if tag_list.empty?

    # # FIXED: Do this in mongo instead of loading everything in memory.
    # collection.select do |taggable|
    #   tags = tag_list.push('global')
    #   (taggable.tag_list & tags).any?
    # end

    ids = []
    type = collection.first.class.to_s
    Tag.any_in(name: tag_list.push('global')).each do |tag|
      tag.taggable_references.where(taggable_type: type).each do |ref|
        ids.push ref.taggable_id
      end
    end
    collection.any_in(_id: ids)
  end

  protected

  def cache_updates
    Cacher.cache('/event/' + self.id.to_s + '/updates.json', self.current_window.to_json)
  end

  def update_template_data
    self.template_data ||= {}
    fresh_fields = []

    # Find all custom fields from all templates.
    templates = ([self.event_template] + self.embed_templates).compact
    templates.each do |t|
      t.custom_fields.each do |f|
        # Add to hash if needed.
        self.template_data[f] ||= ''
        # Cache the field name for the deletion step below.
        fresh_fields << f
      end if t.custom_fields
    end

    # Remove custom fields that are no longer relevant.
    self.template_data.delete_if { |k,v| !fresh_fields.include?(k) }
  end

  def generate_content_areas
    clean_record_names = []
    ([event_template] + embed_templates).each do |template|
      template.custom_areas.each do |name, area_type|
        existing = self.content_areas.where(name: name)
        clean_record_names << name
        unless existing.any?
          klass = area_type.classify.constantize
          self.content_areas << klass.new(name: name, area_type: area_type)
        else
          existing.each do |area|
            area.set(:name, name)
            area.set(:area_type, area_type)
          end
        end
      end
    end
    remove = self.content_areas.not_in name: clean_record_names
    remove.destroy_all
  end
end

{'fraction_non_alphanumeric': 0.09126271693596649, 'fraction_numerical': 0.0004488330341113106, 'mean_word_length': 3.0598238688126327, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2313900', 'n_tokens_mistral': 4243, 'n_tokens_neox': 4172, 'n_words': 1044}