Noosfero/noosfero

View on GitHub
plugins/open_graph/models/open_graph_plugin/activity.rb

Summary

Maintainability
B
6 hrs
Test Coverage
# This is a log of activities, unlike ActivityTrack that is a configuration
class OpenGraphPlugin::Activity < OpenGraphPlugin::Track
  Defs = OpenGraphPlugin::Stories::Definitions

  UpdateDelay = 1.day

  class_attribute :actions, :objects
  self.actions = OpenGraphPlugin::Stories::DefaultActions
  self.objects = OpenGraphPlugin::Stories::DefaultObjects

  validates_presence_of :action
  validates_presence_of :object_type

  # subclass this to define (e.g. FbAppPlugin::Activity)
  def scrape
    raise NotImplementedError
  end

  def publish!(actor = self.actor)
    self.published_at = Time.now
    print_debug "open_graph: published with success" if debug? actor
  end

  def defs
    @defs ||= Defs[self.story.to_sym]
  end

  def object_profile
    @object_profile ||= self.call(self.defs[:object_profile], self.object_data) || self.object_data.profile rescue nil
  end

  def track_configs
    @track_configs ||= Array(self.defs[:track_config]).compact.map(&:constantize)
  end

  def match_criteria?
    if (ret = self.call self.defs[:criteria], self.object_data, self.actor).nil? then true else ret end
  end

  def match_publish_if?
    if (ret = self.call self.defs[:publish_if], self.object_data, self.actor).nil? then true else ret end
  end

  def custom_object_data_url
    @custom_object_data_url ||= self.call defs[:object_data_url], self.object_data, self.actor
  end

  def object_actor
    @object_actor ||= self.call(self.defs[:object_actor], self.object_data) || self.object_data.profile rescue nil
  end

  def custom_actor
    @custom_actor ||= self.call self.defs[:custom_actor], self.object_data
  end

  def set_object_data_url
    # force profile identifier for custom domains and fixed host. see og_url_for
    extra_params = if self.object_profile then { profile: self.object_profile.identifier } else {} end

    self.object_data_url = if self.defs[:passive] then self.passive_url_for self.object_data, self.custom_object_data_url, self.defs, extra_params else self.url_for self.object_data, self.custom_object_data_url, extra_params end
  end

  def dispatch_publications
    print_debug "open_graph: dispatch_publications of #{story}" if debug? self.actor

    return unless self.match_criteria?

    print_debug "open_graph: #{story} match criteria" if debug? self.actor
    return unless self.match_publish_if?

    print_debug "open_graph: #{story} match publish_if" if debug? self.actor
    return unless (actors = self.trackers).present?

    print_debug "open_graph: #{story} has enabled trackers" if debug? self.actor

    self.set_object_data_url
    self.action = self.class.actions[self.defs[:action]]
    self.object_type = self.class.objects[self.defs[:object_type]]

    print_debug "open_graph: start publishing" if debug? actor
    unless (publish = self.defs[:publish]).present?
      actors.each do |actor|
        begin
          self.publish! actor
        rescue => e
          print_debug "open_graph: can't publish story: #{e.message}" if debug? actor
          raise unless Rails.env.production?

          ExceptionNotifier.notify_exception e
        end
      end
    else # custom publish proc
      begin
        instance_exec self.actor, self.object_data, &publish
      rescue => e
        print_debug "open_graph: can't publish story: #{e.message}" if debug? self.actor
        raise unless Rails.env.production?

        ExceptionNotifier.notify_exception e
      end
    end
  end

  def trackers
    @trackers ||= begin
      return if self.track_configs.empty?

      trackers = []

      print_debug "open_graph: using configs: #{self.track_configs.map(&:name).inspect}" if debug? self.actor

      if self.defs[:passive]
        return unless self.object_profile

        self.track_configs.each do |c|
          trackers.concat c.trackers_to_profile(self.object_profile)
        end.flatten

        trackers.select! do |t|
          self.track_configs.any? { |c| c.enabled? self.context, t }
        end
      else # active
        return unless self.object_actor && self.object_actor.person?

        actor = self.custom_actor || self.actor

        match_track = self.track_configs.any? do |c|
          c.enabled?(self.context, actor) &&
            actor.send("open_graph_#{c.track_name}_track_configs").where(object_type: self.defs[:object_type]).first
        end
        trackers << actor if match_track
      end

      trackers
    end
  end

  protected

    include OpenGraphPlugin::UrlHelper

    def update_delay
      UpdateDelay
    end

    # only publish recent objects to avoid multiple publications
    def recent_publish?(actor, object_type, object_data_url)
      activity_params = { actor_id: actor.id, object_type: object_type, object_data_url: object_data_url }
      activity = OpenGraphPlugin::Activity.where(activity_params).first
      activity.present? && (activity.created_at <= self.update_delay.from_now)
    end

    def call(p, *args)
      p && instance_exec(*args, &p)
    end
end