[Git][noosfero/noosfero][master] 2 commits: Add abstract plugin to federate networks via OpenGraph
Bráulio Bhavamitra
gitlab at gitlab.com
Wed Aug 12 23:30:05 BRT 2015
Bráulio Bhavamitra pushed to branch master at Noosfero / noosfero
Commits:
be3b210f by Braulio Bhavamitra at 2015-08-12T23:14:30Z
Add abstract plugin to federate networks via OpenGraph
- - - - -
180ad529 by Bráulio Bhavamitra at 2015-08-13T02:29:49Z
Merge branch 'open_graph' into 'master'
Abstract plugin to federate networks via OpenGraph
Depends on: !362 !345 !473 !482
See merge request !512
- - - - -
43 changed files:
- app/models/article.rb
- app/models/uploaded_file.rb
- lib/tasks/plugins_tests.rake
- + plugins/open_graph/Gemfile
- + plugins/open_graph/controllers/myprofile/open_graph_plugin/myprofile_controller.rb
- + plugins/open_graph/db/migrate/20141031130250_create_open_graph_plugin_tracks.rb
- + plugins/open_graph/install.rb
- + plugins/open_graph/lib/ext/article.rb
- + plugins/open_graph/lib/ext/profile.rb
- + plugins/open_graph/lib/ext/profile_activity.rb
- + plugins/open_graph/lib/ext/uploaded_file.rb
- + plugins/open_graph/lib/open_graph_plugin.rb
- + plugins/open_graph/lib/open_graph_plugin/attach_stories.rb
- + plugins/open_graph/lib/open_graph_plugin/base.rb
- + plugins/open_graph/lib/open_graph_plugin/display_helper.rb
- + plugins/open_graph/lib/open_graph_plugin/publisher.rb
- + plugins/open_graph/lib/open_graph_plugin/settings.rb
- + plugins/open_graph/lib/open_graph_plugin/stories.rb
- + plugins/open_graph/locales/en-US.yml
- + plugins/open_graph/locales/pt-BR.yml
- + plugins/open_graph/models/open_graph_plugin/activity.rb
- + plugins/open_graph/models/open_graph_plugin/activity_track_config.rb
- + plugins/open_graph/models/open_graph_plugin/community_track_config.rb
- + plugins/open_graph/models/open_graph_plugin/enterprise_track_config.rb
- + plugins/open_graph/models/open_graph_plugin/friend_track_config.rb
- + plugins/open_graph/models/open_graph_plugin/track.rb
- + plugins/open_graph/models/open_graph_plugin/track_config.rb
- + plugins/open_graph/plugin.yml
- + plugins/open_graph/public/javascripts/open_graph.js
- + plugins/open_graph/public/style.scss
- + plugins/open_graph/public/stylesheets/style.scss
- + plugins/open_graph/test/functional/open_graph_graph/my_profile_controller_test.rb
- + plugins/open_graph/test/unit/open_graph_graph/publisher_test.rb
- + plugins/open_graph/views/open_graph_plugin/myprofile/_ac_profile.html.erb
- + plugins/open_graph/views/open_graph_plugin/myprofile/_heading.html.erb
- + plugins/open_graph/views/open_graph_plugin/myprofile/_profile_search.jsonify
- + plugins/open_graph/views/open_graph_plugin/myprofile/_track_activity.html.erb
- + plugins/open_graph/views/open_graph_plugin/myprofile/_track_community.html.erb
- + plugins/open_graph/views/open_graph_plugin/myprofile/_track_enterprise.html.erb
- + plugins/open_graph/views/open_graph_plugin/myprofile/_track_form.html.erb
- + plugins/open_graph/views/open_graph_plugin/myprofile/_track_friend.html.erb
- + plugins/open_graph/views/open_graph_plugin/myprofile/_track_objects.html.erb
- + plugins/open_graph/views/open_graph_plugin/myprofile/_track_profiles.html.erb
Changes:
=====================================
app/models/article.rb
=====================================
--- a/app/models/article.rb
+++ b/app/models/article.rb
@@ -8,7 +8,8 @@ class Article < ActiveRecord::Base
:accept_comments, :feed, :published, :source, :source_name,
:highlighted, :notify_comments, :display_hits, :slug,
:external_feed_builder, :display_versions, :external_link,
- :image_builder, :show_to_followers
+ :image_builder, :show_to_followers,
+ :author
acts_as_having_image
=====================================
app/models/uploaded_file.rb
=====================================
--- a/app/models/uploaded_file.rb
+++ b/app/models/uploaded_file.rb
@@ -163,4 +163,8 @@ class UploadedFile < Article
true
end
+ def notifiable?
+ true
+ end
+
end
=====================================
lib/tasks/plugins_tests.rake
=====================================
--- a/lib/tasks/plugins_tests.rake
+++ b/lib/tasks/plugins_tests.rake
@@ -169,7 +169,7 @@ def test_sequence(plugins, tasks)
failed[plugin] << task
end
end
- disable_plugins(plugin)
+ disable_plugins
end
fail_flag = false
failed.each do |plugin, tasks|
=====================================
plugins/open_graph/Gemfile
=====================================
--- /dev/null
+++ b/plugins/open_graph/Gemfile
@@ -0,0 +1,3 @@
+
+gem 'jsonify-rails'
+
=====================================
plugins/open_graph/controllers/myprofile/open_graph_plugin/myprofile_controller.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/controllers/myprofile/open_graph_plugin/myprofile_controller.rb
@@ -0,0 +1,47 @@
+class OpenGraphPlugin::MyprofileController < MyProfileController
+
+ protect 'edit_profile', :profile
+ before_filter :set_context
+
+ def enterprise_search
+ scope = environment.enterprises.enabled.public
+ profile_search scope
+ end
+ def community_search
+ scope = environment.communities.public
+ profile_search scope
+ end
+ def friend_search
+ scope = profile.friends
+ profile_search scope
+ end
+
+ def track_config
+ profile.update_attributes! params[:profile_data]
+ render partial: 'track_form', locals: {context: context, reload: true}
+ end
+
+ protected
+
+ def profile_search scope
+ @query = params[:query]
+ @profiles = scope.limit(10).order('name ASC').
+ where(['name ILIKE ? OR name ILIKE ? OR identifier LIKE ?', "#{@query}%", "% #{@query}%", "#{@query}%"])
+ render partial: 'profile_search', locals: {profiles: @profiles}
+ end
+
+ def context
+ :open_graph
+ end
+
+ def set_context
+ OpenGraphPlugin.context = self.context
+ end
+
+ def default_url_options
+ # avoid rails' use_relative_controller!
+ {use_route: '/'}
+ end
+
+end
+
=====================================
plugins/open_graph/db/migrate/20141031130250_create_open_graph_plugin_tracks.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/db/migrate/20141031130250_create_open_graph_plugin_tracks.rb
@@ -0,0 +1,36 @@
+class CreateOpenGraphPluginTracks < ActiveRecord::Migration
+ def up
+ create_table :open_graph_plugin_tracks do |t|
+ t.string :type
+ t.string :context
+ t.boolean :enabled, default: true
+
+ t.integer :tracker_id
+
+ t.integer :actor_id
+
+ t.string :action
+
+ t.string :object_type
+ t.text :object_data_url
+ t.integer :object_data_id
+ t.string :object_data_type
+
+ t.timestamps
+ end
+
+ add_index :open_graph_plugin_tracks, [:type]
+ add_index :open_graph_plugin_tracks, [:context]
+ add_index :open_graph_plugin_tracks, [:type, :context]
+ add_index :open_graph_plugin_tracks, [:actor_id]
+ add_index :open_graph_plugin_tracks, [:action]
+ add_index :open_graph_plugin_tracks, [:object_type]
+ add_index :open_graph_plugin_tracks, [:enabled]
+ add_index :open_graph_plugin_tracks, [:object_data_url]
+ add_index :open_graph_plugin_tracks, [:object_data_id, :object_data_type], name: 'index_open_graph_plugin_tracks_object_data_id_type'
+ end
+
+ def down
+ drop_table :open_graph_plugin_tracks
+ end
+end
=====================================
plugins/open_graph/install.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/install.rb
@@ -0,0 +1,2 @@
+system "script/noosfero-plugins -q enable metadata"
+
=====================================
plugins/open_graph/lib/ext/article.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/ext/article.rb
@@ -0,0 +1,15 @@
+require_dependency 'article'
+
+class Article
+
+ after_update :open_graph_scrape
+
+ protected
+
+ def open_graph_scrape
+ activity = OpenGraphPlugin::Activity.where(object_data_id: self.id, object_data_type: self.class.base_class.name).first
+ activity.scrape if activity
+ end
+ handle_asynchronously :open_graph_scrape
+
+end
=====================================
plugins/open_graph/lib/ext/profile.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/ext/profile.rb
@@ -0,0 +1,59 @@
+require_dependency 'profile'
+# hate to wrte this, but without Noosfero::Plugin::Settings is loaded instead
+require 'open_graph_plugin/settings'
+
+# attr_accessible must be defined on subclasses
+Profile.descendants.each do |subclass|
+ subclass.class_eval do
+ attr_accessible :open_graph_settings
+
+ OpenGraphPlugin::TrackConfig::Types.each do |track, klass|
+ klass = "OpenGraphPlugin::#{klass}".constantize
+ attributes = "#{klass.association}_attributes"
+ profile_ids = "open_graph_#{track}_profiles_ids"
+
+ attr_accessible attributes
+ attr_accessible profile_ids
+ end
+ end
+end
+
+class Profile
+
+ def open_graph_settings attrs = {}
+ @open_graph_settings ||= OpenGraphPlugin::Settings.new self, attrs
+ attrs.each{ |a, v| @open_graph_settings.send "#{a}=", v }
+ @open_graph_settings
+ end
+ alias_method :open_graph_settings=, :open_graph_settings
+
+ has_many :open_graph_tracks, class_name: 'OpenGraphPlugin::Track', source: :tracker_id, foreign_key: :tracker_id
+
+ has_many :open_graph_activities, class_name: 'OpenGraphPlugin::Activity', source: :tracker_id, foreign_key: :tracker_id
+
+ has_many :open_graph_track_configs, class_name: 'OpenGraphPlugin::TrackConfig', source: :tracker_id, foreign_key: :tracker_id
+ OpenGraphPlugin::TrackConfig::Types.each do |track, klass|
+ klass = "OpenGraphPlugin::#{klass}".constantize
+ association = klass.association
+ profile_ids = "open_graph_#{track}_profiles_ids"
+
+ has_many association, class_name: klass.name, foreign_key: :tracker_id
+ accepts_nested_attributes_for association, allow_destroy: true, reject_if: :open_graph_reject_empty_object_type
+
+ define_method "#{profile_ids}=" do |ids|
+ cids = self.send(association).order('created_at ASC').map(&:object_data_id)
+ nids = if ids.is_a? Array then ids else ids.split ',' end
+ nids = nids.map(&:to_i)
+ Profile.where(id: nids-cids).each{ |profile| self.send(association).create! type: klass.name, object_data: profile }
+ self.send(association).each{ |c| c.destroy unless c.object_data_id.in? nids }
+ end
+
+ end
+
+ define_method :open_graph_reject_empty_object_type do |attributes|
+ exists = attributes[:id].present?
+ empty = attributes[:object_type].empty?
+ attributes.merge! _destroy: 1 if exists and empty
+ return (!exists and empty)
+ end
+end
=====================================
plugins/open_graph/lib/ext/profile_activity.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/ext/profile_activity.rb
@@ -0,0 +1,19 @@
+require_dependency 'profile_activity'
+
+class ProfileActivity
+
+ # update happens with grouped ActionTracker
+ after_save :open_graph_publish
+
+ def open_graph_publish
+ # Scrap not yet supported
+ if self.activity.is_a? ActionTracker::Record
+ verb = self.activity.verb.to_sym
+ return unless object = self.activity.target
+ return unless stories = OpenGraphPlugin::Stories::TrackerStories[verb]
+ OpenGraphPlugin::Stories.publish object, stories
+ end
+ end
+
+end
+
=====================================
plugins/open_graph/lib/ext/uploaded_file.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/ext/uploaded_file.rb
@@ -0,0 +1,8 @@
+require_dependency 'uploaded_file'
+
+class UploadedFile
+
+ extend OpenGraphPlugin::AttachStories::ClassMethods
+ open_graph_attach_stories only: :add_an_image
+
+end
=====================================
plugins/open_graph/lib/open_graph_plugin.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/open_graph_plugin.rb
@@ -0,0 +1,21 @@
+module OpenGraphPlugin
+
+ extend Noosfero::Plugin::ParentMethods
+
+ def self.plugin_name
+ I18n.t 'open_graph_plugin.lib.plugin.name'
+ end
+
+ def self.plugin_description
+ I18n.t 'open_graph_plugin.lib.plugin.description'
+ end
+
+ def self.context
+ Thread.current[:open_graph_context] || :open_graph
+ end
+ def self.context= value
+ Thread.current[:open_graph_context] = value
+ end
+
+end
+
=====================================
plugins/open_graph/lib/open_graph_plugin/attach_stories.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/open_graph_plugin/attach_stories.rb
@@ -0,0 +1,44 @@
+require_dependency 'open_graph_plugin/stories'
+
+# This is used when ActionTracker is not compartible with the way
+module OpenGraphPlugin::AttachStories
+
+ module ClassMethods
+
+ def open_graph_attach_stories options={}
+ if stories = Array(options[:only])
+ callbacks = {}
+ stories.each do |story|
+ defs = OpenGraphPlugin::Stories::Definitions[story]
+ Array(defs[:on]).each do |on|
+ callbacks[on] ||= []
+ callbacks[on] << story
+ end
+ end
+ else
+ klass = self.name
+ callbacks = OpenGraphPlugin::Stories::ModelStories[klass.to_sym]
+ return if callbacks.blank?
+ end
+
+ callbacks.each do |on, stories|
+ # subclasses may override this, but the callback is called only once
+ method = "open_graph_publish_after_#{on}"
+
+ self.send "after_#{on}", method
+ # buggy with rails 3.2
+ #self.send "after_commit", method, on: on
+
+ define_method method do
+ OpenGraphPlugin::Stories.publish self, stories
+ end
+ end
+ end
+
+ end
+
+ module InstanceMethods
+
+ end
+
+end
=====================================
plugins/open_graph/lib/open_graph_plugin/base.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/open_graph_plugin/base.rb
@@ -0,0 +1,15 @@
+
+class OpenGraphPlugin::Base < Noosfero::Plugin
+
+ def js_files
+ [].map{ |j| "javascripts/#{j}" }
+ end
+
+ def stylesheet?
+ true
+ end
+
+end
+
+ActiveSupport.run_load_hooks :open_graph_plugin, OpenGraphPlugin
+
=====================================
plugins/open_graph/lib/open_graph_plugin/display_helper.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/open_graph_plugin/display_helper.rb
@@ -0,0 +1,7 @@
+
+module OpenGraphPlugin::DisplayHelper
+
+ def blah
+ puts 'here'
+ end
+end
=====================================
plugins/open_graph/lib/open_graph_plugin/publisher.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/open_graph_plugin/publisher.rb
@@ -0,0 +1,166 @@
+
+class OpenGraphPlugin::Publisher
+
+ attr_accessor :actions
+ attr_accessor :objects
+
+ def self.default
+ @default ||= self.new
+ end
+
+ def initialize attributes = {}
+ # defaults
+ self.actions = OpenGraphPlugin::Stories::DefaultActions
+ self.objects = OpenGraphPlugin::Stories::DefaultObjects
+
+ attributes.each do |attr, value|
+ self.send "#{attr}=", value
+ end
+ end
+
+ def publish actor, story_defs, object_data_url
+ raise 'abstract method called'
+ end
+
+ def publish_stories object_data, actor, stories
+ stories.each do |story|
+ begin
+ self.publish_story object_data, actor, story
+ rescue => e
+ ExceptionNotifier.notify_exception e
+ end
+ end
+ end
+
+ def update_delay
+ 1.day
+ 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? and activity.created_at <= self.update_delay.from_now
+ end
+
+ def publish_story object_data, actor, story
+ OpenGraphPlugin.context = self.context
+ defs = OpenGraphPlugin::Stories::Definitions[story]
+ passive = defs[:passive]
+
+ print_debug "open_graph: publish_story #{story}" if debug? actor
+ match_criteria = if (ret = self.call defs[:criteria], object_data, actor).nil? then true else ret end
+ return unless match_criteria
+ print_debug "open_graph: #{story} match criteria" if debug? actor
+ match_condition = if (ret = self.call defs[:publish_if], object_data, actor).nil? then true else ret end
+ return unless match_condition
+ print_debug "open_graph: #{story} match publish_if" if debug? actor
+
+ actors = self.story_trackers defs, actor, object_data
+ return if actors.blank?
+ print_debug "open_graph: #{story} has enabled trackers" if debug? actor
+
+ if publish = defs[:publish]
+ begin
+ instance_exec actor, object_data, &publish
+ rescue => e
+ print_debug "open_graph: can't publish story: #{e.message}" if debug? actor
+ ExceptionNotifier.notify_exception e
+ end
+ else
+ # force profile identifier for custom domains and fixed host. see og_url_for
+ object_profile = self.call(story_defs[:object_profile], object_data) || object_data.profile rescue nil
+ extra_params = if object_profile then {profile: object_profile.identifier} else {} end
+
+ custom_object_data_url = self.call defs[:object_data_url], object_data, actor
+ object_data_url = if passive then self.passive_url_for object_data, custom_object_data_url, defs, extra_params else self.url_for object_data, custom_object_data_url, extra_params end
+
+ actors.each do |actor|
+ print_debug "open_graph: start publishing" if debug? actor
+ begin
+ self.publish actor, defs, object_data_url
+ rescue => e
+ print_debug "open_graph: can't publish story: #{e.message}" if debug? actor
+ ExceptionNotifier.notify_exception e
+ end
+ end
+ end
+ end
+
+ def story_trackers story_defs, actor, object_data
+ passive = story_defs[:passive]
+ trackers = []
+
+ track_configs = Array(story_defs[:track_config]).compact.map(&:constantize)
+ return if track_configs.empty?
+ print_debug "open_graph: using configs: #{track_configs.map(&:name).inspect}" if debug? actor
+
+ if passive
+ object_profile = self.call(story_defs[:object_profile], object_data) || object_data.profile rescue nil
+ return unless object_profile
+
+ track_configs.each do |c|
+ trackers.concat c.trackers_to_profile(object_profile)
+ end.flatten
+
+ trackers.select! do |t|
+ track_configs.any?{ |c| c.enabled? self.context, t }
+ end
+ else #active
+ object_actor = self.call(story_defs[:object_actor], object_data) || object_data.profile rescue nil
+ return unless object_actor and object_actor.person?
+ custom_actor = self.call(story_defs[:custom_actor], object_data)
+ actor = custom_actor if custom_actor
+
+ match_track = track_configs.any? do |c|
+ c.enabled?(self.context, actor) and
+ actor.send("open_graph_#{c.track_name}_track_configs").where(object_type: story_defs[:object_type]).first
+ end
+ trackers << actor if match_track
+ end
+
+ trackers
+ end
+
+ protected
+
+ include MetadataPlugin::UrlHelper
+
+ def register_publish attributes
+ OpenGraphPlugin::Activity.create! attributes
+ end
+
+ # Call don't ask: move to a og_url method inside object
+ def url_for object, custom_url=nil, extra_params={}
+ return custom_url if custom_url.is_a? String
+ url = custom_url || if object.is_a? Profile then og_profile_url object else object.url end
+ # for profile when custom domain is used
+ url.merge! profile: object.profile.identifier if object.respond_to? :profile
+ url.merge! extra_params
+ self.og_url_for url
+ end
+
+ def passive_url_for object, custom_url, story_defs, extra_params={}
+ object_type = story_defs[:object_type]
+ extra_params.merge! og_type: MetadataPlugin.og_types[object_type]
+ self.url_for object, custom_url, extra_params
+ end
+
+ def call p, *args
+ p and instance_exec *args, &p
+ end
+
+ def context
+ :open_graph
+ end
+
+ def print_debug msg
+ puts msg
+ Delayed::Worker.logger.debug msg
+ end
+ def debug? actor=nil
+ !Rails.env.production?
+ end
+
+end
+
=====================================
plugins/open_graph/lib/open_graph_plugin/settings.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/open_graph_plugin/settings.rb
@@ -0,0 +1,14 @@
+class OpenGraphPlugin::Settings < Noosfero::Plugin::Settings
+
+ def self.new base, attrs = {}
+ super base, self.parents.first, attrs
+ end
+
+ OpenGraphPlugin::TrackConfig::Types.each do |track, klass|
+ define_method "#{track}_track_enabled=" do |value|
+ super ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
+ end
+ end
+
+end
+
=====================================
plugins/open_graph/lib/open_graph_plugin/stories.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/lib/open_graph_plugin/stories.rb
@@ -0,0 +1,302 @@
+
+class OpenGraphPlugin::Stories
+
+ class_attribute :publishers
+ self.publishers = []
+
+ def self.register_publisher publisher
+ self.publishers << publisher
+ end
+
+ def self.publish record, stories
+ actor = User.current.person rescue nil
+ return unless actor
+
+ self.publishers.each do |publisher|
+ publisher = publisher.delay unless Rails.env.development? or Rails.env.test?
+ publisher.publish_stories record, actor, stories
+ end
+ end
+
+ Definitions = {
+ # needed a patch on UploadedFile: def notifiable?; true; end
+ add_a_document: {
+ action_tracker_verb: :create_article,
+ track_config: 'OpenGraphPlugin::ActivityTrackConfig',
+ action: :add,
+ object_type: :uploaded_file,
+ models: :UploadedFile,
+ on: :create,
+ criteria: proc do |article, actor|
+ article.is_a? UploadedFile
+ end,
+ publish_if: proc do |uploaded_file, actor|
+ # done in add_an_image
+ next false if uploaded_file.image?
+ uploaded_file.published?
+ end,
+ object_data_url: proc do |uploaded_file, actor|
+ uploaded_file.url.merge view: true
+ end,
+ },
+ add_an_image: {
+ # :upload_image verb can't be used as it uses the parent Gallery as target
+ # hooked via open_graph_attach_stories
+ action_tracker_verb: nil,
+ track_config: 'OpenGraphPlugin::ActivityTrackConfig',
+ action: :add,
+ object_type: :gallery_image,
+ models: :UploadedFile,
+ on: :create,
+ criteria: proc do |article, actor|
+ article.is_a? UploadedFile
+ end,
+ publish_if: proc do |uploaded_file, actor|
+ uploaded_file.image? and uploaded_file.parent.is_a? Gallery
+ end,
+ object_data_url: proc do |uploaded_file, actor|
+ uploaded_file.url.merge view: true
+ end,
+ },
+ create_an_article: {
+ action_tracker_verb: :create_article,
+ track_config: 'OpenGraphPlugin::ActivityTrackConfig',
+ action: :create,
+ object_type: :blog_post,
+ models: :Article,
+ on: :create,
+ criteria: proc do |article, actor|
+ article.parent.is_a? Blog
+ end,
+ publish_if: proc do |article, actor|
+ article.published?
+ end,
+ },
+ create_an_event: {
+ action_tracker_verb: :create_article,
+ track_config: 'OpenGraphPlugin::ActivityTrackConfig',
+ action: :create,
+ object_type: :event,
+ models: :Event,
+ on: :create,
+ criteria: proc do |article, actor|
+ article.is_a? Event
+ end,
+ publish_if: proc do |event, actor|
+ event.published?
+ end,
+ },
+ start_a_discussion: {
+ action_tracker_verb: :create_article,
+ track_config: 'OpenGraphPlugin::ActivityTrackConfig',
+ action: :start,
+ object_type: :forum,
+ models: :Article,
+ on: :create,
+ criteria: proc do |article, actor|
+ article.parent.is_a? Forum
+ end,
+ publish_if: proc do |article, actor|
+ article.published?
+ end,
+ object_data_url: proc do |article, actor|
+ url = article.url
+ if og_type = MetadataPlugin::og_types[:forum]
+ url[:og_type] = og_type
+ end
+ url
+ end,
+ },
+
+ # these a published as passive to give focus to the enterprise
+=begin
+ add_a_sse_product: {
+ action_tracker_verb: :create_product,
+ track_config: 'OpenGraphPlugin::ActivityTrackConfig',
+ action: :announce_new,
+ models: :Product,
+ on: :create,
+ object_type: :product,
+ publish_if: proc do |product, actor|
+ product.profile.public?
+ end,
+ },
+ update_a_sse_product: {
+ action_tracker_verb: :update_product,
+ track_config: 'OpenGraphPlugin::ActivityTrackConfig',
+ action: :announce_update,
+ object_type: :product,
+ models: :Product,
+ on: :update,
+ publish_if: proc do |product, actor|
+ product.profile.public?
+ end,
+ },
+=end
+
+ favorite_a_sse_initiative: {
+ action_tracker_verb: :favorite_enterprise,
+ track_config: 'OpenGraphPlugin::ActivityTrackConfig',
+ action: :favorite,
+ object_type: :favorite_enterprise,
+ models: :FavoriteEnterprisePerson,
+ on: :create,
+ object_actor: proc do |favorite_enterprise_person|
+ favorite_enterprise_person.person
+ end,
+ object_profile: proc do |favorite_enterprise_person|
+ favorite_enterprise_person.enterprise
+ end,
+ object_data_url: proc do |favorite_enterprise_person, actor|
+ self.og_profile_url favorite_enterprise_person.enterprise
+ end,
+ },
+
+=begin
+ comment_a_discussion: {
+ action_tracker_verb: nil,
+ action: :comment,
+ object_type: :forum,
+ models: :Comment,
+ on: :create,
+ criteria: proc do |comment, actor|
+ source, parent = comment.source, comment.source.parent
+ source.is_a? Article and parent.is_a? Forum
+ end,
+ publish_if: proc do |comment, actor|
+ comment.source.parent.published?
+ end,
+ },
+ comment_an_article: {
+ action_tracker_verb: nil,
+ action: :comment,
+ object_type: :blog_post,
+ models: :Comment,
+ on: :create,
+ criteria: proc do |comment, actor|
+ source, parent = comment.source, comment.source.parent
+ source.is_a? Article and parent.is_a? Blog
+ end,
+ publish_if: proc do |comment, actor|
+ comment.source.parent.published?
+ end,
+ },
+=end
+
+ make_friendship_with: {
+ action_tracker_verb: :new_friendship,
+ track_config: 'OpenGraphPlugin::ActivityTrackConfig',
+ action: :make_friendship,
+ object_type: :friend,
+ models: :Friendship,
+ on: :create,
+ custom_actor: proc do |friendship|
+ friendship.person
+ end,
+ object_actor: proc do |friendship|
+ friendship.person
+ end,
+ object_profile: proc do |friendship|
+ friendship.friend
+ end,
+ object_data_url: proc do |friendship, actor|
+ self.og_profile_url friendship.friend
+ end,
+ },
+
+ # PASSIVE STORIES
+ announce_news_from_a_sse_initiative: {
+ action_tracker_verb: :create_article,
+ track_config: 'OpenGraphPlugin::EnterpriseTrackConfig',
+ action: :announce_news,
+ object_type: :enterprise,
+ passive: true,
+ models: :Article,
+ on: :create,
+ criteria: proc do |article, actor|
+ article.profile.enterprise?
+ end,
+ publish_if: proc do |article, actor|
+ article.published?
+ end,
+ },
+ announce_a_new_sse_product: {
+ action_tracker_verb: :create_product,
+ track_config: 'OpenGraphPlugin::EnterpriseTrackConfig',
+ action: :announce_new,
+ object_type: :product,
+ passive: true,
+ models: :Product,
+ on: :create,
+ criteria: proc do |product, actor|
+ product.profile.enterprise?
+ end,
+ },
+ announce_an_update_of_sse_product: {
+ action_tracker_verb: :update_product,
+ track_config: 'OpenGraphPlugin::EnterpriseTrackConfig',
+ action: :announce_update,
+ object_type: :product,
+ passive: true,
+ models: :Product,
+ on: :update,
+ criteria: proc do |product, actor|
+ product.profile.enterprise?
+ end,
+ },
+
+ announce_news_from_a_community: {
+ action_tracker_verb: :create_article,
+ track_config: 'OpenGraphPlugin::CommunityTrackConfig',
+ action: :announce_news,
+ object_type: :community,
+ passive: true,
+ models: :Article,
+ on: :create,
+ criteria: proc do |article, actor|
+ article.profile.community?
+ end,
+ publish_if: proc do |article, actor|
+ article.published?
+ end,
+ },
+
+ }
+
+ ValidObjectList = Definitions.map{ |story, data| data[:object_type] }.uniq
+ ValidActionList = Definitions.map{ |story, data| data[:action] }.uniq
+
+ # TODO make this verification work
+ #raise "Each active story must use a unique object_type for configuration to work" if ValidObjectList.size < Definitions.size
+
+ DefaultActions = ValidActionList.inject({}){ |h, a| h[a] = a; h }
+ DefaultObjects = ValidObjectList.inject({}){ |h, o| h[o] = o; h }
+
+ TrackerStories = {}; Definitions.each do |story, data|
+ Array(data[:action_tracker_verb]).each do |verb|
+ next unless verb
+ TrackerStories[verb] ||= []
+ TrackerStories[verb] << story
+ end
+ end
+
+ TrackConfigStories = {}; Definitions.each do |story, data|
+ Array(data[:track_config]).each do |track_config|
+ next unless track_config
+ TrackConfigStories[track_config] ||= []
+ TrackConfigStories[track_config] << [story, data]
+ end
+ end
+
+ ModelStories = {}; Definitions.each do |story, data|
+ Array(data[:models]).each do |model|
+ ModelStories[model] ||= {}
+ Array(data[:on]).each do |on|
+ ModelStories[model][on] ||= []
+ ModelStories[model][on] << story
+ end
+ end
+ end
+
+end
+
=====================================
plugins/open_graph/locales/en-US.yml
=====================================
--- /dev/null
+++ b/plugins/open_graph/locales/en-US.yml
@@ -0,0 +1,43 @@
+
+"en-US": &en-US
+
+ open_graph_plugin:
+ lib:
+ plugin:
+ name: 'OpenGraph'
+ description: 'OpenGraph'
+ views:
+ track:
+ config:
+ activity:
+ configure: 'Configure'
+ label: "My activities: new photos on my albuns, blogs's posts and other contents"
+ objects:
+ blog_post: "Blogs' posts"
+ event: 'Creation of events'
+ favorite_enterprise: 'Quando eu favoritar um empreendimento'
+ forum: "Forum's topic posted"
+ friend: 'New friendships'
+ gallery_image: 'New images on my albuns'
+ uploaded_file: 'Files sent'
+ enterprise:
+ memberships: "Enterprises that I'm a member of"
+ favorites: "My favorite enterprises"
+ see_all: 'See enterprises'
+ label: "News from enterprises that I am a member and my favorites"
+ search_placeholder: "type to find enterprises"
+ favorites_how_to:
+ title: "How to add favorite Solidarity Economy initiatives"
+ body: "To add favorite Solidarity Economy initiatives, you should visit its page in Cirandas and click on button %{favorite_button} which is located below its logo, normally on the left side."
+ community:
+ label: "News from selected communities"
+ search_placeholder: "type to find communities"
+ friend:
+ label: "News from friends"
+ search_placeholder: "type to find friends"
+
+'en_US':
+ <<: *en-US
+'en':
+ <<: *en-US
+
=====================================
plugins/open_graph/locales/pt-BR.yml
=====================================
--- /dev/null
+++ b/plugins/open_graph/locales/pt-BR.yml
@@ -0,0 +1,40 @@
+
+"pt-BR": &pt-BR
+
+ open_graph_plugin:
+ lib:
+ plugin:
+ name: 'OpenGraph'
+ description: 'OpenGraph'
+ views:
+ track:
+ config:
+ activity:
+ configure: 'Configurar'
+ label: 'Publicar minhas atividades do cirandas no meu mural do facebook'
+ objects:
+ blog_post: 'Quando eu criar um conteúdo ou artigo'
+ event: 'Quando eu adicionar eventos'
+ forum: 'Quando eu criar novos tópicos de fórum'
+ friend: 'Quando eu fizer amizades'
+ gallery_image: 'Quando eu adicionar imagens nos meus albuns'
+ uploaded_file: 'Quando eu enviar novos documentos'
+ favorite_enterprise: 'Quando eu favoritar um empreendimento'
+ enterprise:
+ memberships: "Empreendimentos dos quais faço parte"
+ favorites: "Meus empreendimentos favoritos"
+ see_all: 'Ver empreendimentos'
+ label: "Publicar as novidades dos meus empreendimentos favoritos e daqueles que faço parte"
+ search_placeholder: "busque o empreendimento"
+ favorites_how_to:
+ title: "Como adicionar empreendimentos favoritos"
+ body: "Para adicionar empreendimentos favoritos, basta você visitar a página do empreendimento desejado e clicar no botão %{favorite_button} que fica abaixo da logo do empreendimento, geralmente à esquerda."
+ community:
+ label: "Publicar novidades das seguintes comunidades"
+ search_placeholder: "escolha a comunidade"
+
+'pt_BR':
+ <<: *pt-BR
+'pt':
+ <<: *pt-BR
+
=====================================
plugins/open_graph/models/open_graph_plugin/activity.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/models/open_graph_plugin/activity.rb
@@ -0,0 +1,8 @@
+# This is a log of activities, unlike ActivityTrack that is a configuration
+class OpenGraphPlugin::Activity < OpenGraphPlugin::Track
+
+ # subclass this to define (e.g. FbAppPlugin::Activity)
+ def scrape
+ end
+
+end
=====================================
plugins/open_graph/models/open_graph_plugin/activity_track_config.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/models/open_graph_plugin/activity_track_config.rb
@@ -0,0 +1,22 @@
+class OpenGraphPlugin::ActivityTrackConfig < OpenGraphPlugin::TrackConfig
+
+ # workaround for STI bug
+ self.table_name = :open_graph_plugin_tracks
+
+ self.track_name = :activity
+
+ Objects = OpenGraphPlugin::Stories::TrackConfigStories[self.name].map do |story, data|
+ data[:object_type].to_s
+ end.uniq
+
+ def self.objects
+ Objects
+ end
+
+ validates_uniqueness_of :object_type, scope: [:tracker_id]
+ validates_inclusion_of :object_type, in: self.objects
+
+ protected
+
+end
+
=====================================
plugins/open_graph/models/open_graph_plugin/community_track_config.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/models/open_graph_plugin/community_track_config.rb
@@ -0,0 +1,8 @@
+class OpenGraphPlugin::CommunityTrackConfig < OpenGraphPlugin::TrackConfig
+
+ # workaround for STI bug
+ self.table_name = :open_graph_plugin_tracks
+
+ self.track_name = :community
+
+end
=====================================
plugins/open_graph/models/open_graph_plugin/enterprise_track_config.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/models/open_graph_plugin/enterprise_track_config.rb
@@ -0,0 +1,20 @@
+class OpenGraphPlugin::EnterpriseTrackConfig < OpenGraphPlugin::TrackConfig
+
+ # workaround for STI bug
+ self.table_name = :open_graph_plugin_tracks
+
+ self.track_name = :enterprise
+
+ self.static_trackers = true
+
+ def self.trackers_to_profile enterprise
+ trackers = enterprise.members.to_set
+ trackers.merge enterprise.fans if enterprise.respond_to? :fans
+ trackers.to_a
+ end
+
+ def self.profile_track_objects profile
+ (profile.enterprises.public.enabled + profile.favorite_enterprises.public.enabled).uniq
+ end
+
+end
=====================================
plugins/open_graph/models/open_graph_plugin/friend_track_config.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/models/open_graph_plugin/friend_track_config.rb
@@ -0,0 +1,8 @@
+class OpenGraphPlugin::FriendTrackConfig < OpenGraphPlugin::TrackConfig
+
+ # workaround for STI bug
+ self.table_name = :open_graph_plugin_tracks
+
+ self.track_name = :friend
+
+end
=====================================
plugins/open_graph/models/open_graph_plugin/track.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/models/open_graph_plugin/track.rb
@@ -0,0 +1,28 @@
+class OpenGraphPlugin::Track < ActiveRecord::Base
+
+ attr_accessible :type, :context, :tracker_id, :tracker, :actor_id, :action,
+ :object_type, :object_data, :object_data_id, :object_data_type, :object_data_url
+
+ belongs_to :tracker, class_name: 'Profile'
+ belongs_to :actor, class_name: 'Profile'
+ belongs_to :object_data, polymorphic: true
+
+ validates_presence_of :context
+ before_validation :set_context
+
+ def self.objects
+ []
+ end
+
+ def self.association
+ @association ||= "open_graph_#{self.name.demodulize.pluralize.underscore}".to_sym
+ end
+
+ protected
+
+ def set_context
+ self.context = OpenGraphPlugin.context
+ end
+
+end
+
=====================================
plugins/open_graph/models/open_graph_plugin/track_config.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/models/open_graph_plugin/track_config.rb
@@ -0,0 +1,49 @@
+class OpenGraphPlugin::TrackConfig < OpenGraphPlugin::Track
+
+ Types = {
+ activity: 'ActivityTrackConfig',
+ enterprise: 'EnterpriseTrackConfig',
+ community: 'CommunityTrackConfig',
+ # TODO: not yet implemented
+ #friend: 'FriendTrackConfig',
+ }
+
+ # define on subclasses (required)
+ class_attribute :track_name
+ def self.track_enabled_field
+ "#{self.track_name}_track_enabled"
+ end
+
+ # true if do not depend on records (e.g. EnterpriseTrackConfig depends on friends)
+ # redefine on subclasses
+ class_attribute :static_trackers
+ self.static_trackers = false
+
+ def self.enabled? context, actor
+ settings = actor.send "#{context}_settings"
+ settings.send "#{self.track_name}_track_enabled"
+ end
+
+ scope :tracks_to_profile, lambda { |profile, exclude_actor=nil|
+ scope = where object_data_id: profile.id, object_data_type: profile.class.base_class
+ scope = scope.where context: OpenGraphPlugin.context
+ scope = scope.includes :tracker
+ scope = scope.where ['tracker_id <> ?', exclude_actor.id] if exclude_actor
+ scope
+ }
+
+ # redefine on subclasses
+ def self.trackers_to_profile profile
+ tracks = self.tracks_to_profile profile
+ tracks = tracks.where type: self
+ tracks.map(&:tracker)
+ end
+
+ def self.profile_tracks profile
+ profile.send self.association
+ end
+ def self.profile_track_objects profile
+ self.profile_tracks(profile).map(&:object_data).compact
+ end
+
+end
=====================================
plugins/open_graph/plugin.yml
=====================================
--- /dev/null
+++ b/plugins/open_graph/plugin.yml
@@ -0,0 +1,3 @@
+name: open_graph
+dependencies:
+ - metadata
=====================================
plugins/open_graph/public/javascripts/open_graph.js
=====================================
--- /dev/null
+++ b/plugins/open_graph/public/javascripts/open_graph.js
@@ -0,0 +1,181 @@
+open_graph = {
+
+ track: {
+
+ config: {
+
+ view: {
+ form: null,
+ },
+
+ init: function(reload) {
+ this.view.form = $('#track-form form')
+ this.view.form.find('.panel-heading').each(function(i, context) {
+ open_graph.track.config.headingToggle(context)
+ })
+ },
+
+ submit: function() {
+ loading_overlay.show($('#track-config'))
+ open_graph.track.config.view.form.ajaxSubmit({
+ success: function(data) {
+ data = $(data)
+ // needs update to get ids from accepts_nested_attributes_for
+ $('#track-activity').html(data.find('#track-activity').html())
+ loading_overlay.hide($('#track-config'))
+ },
+ })
+ return false;
+ },
+
+ // trigged on init state and on subcheckboxes change
+ headingToggle: function(context, open) {
+ var panel = $(context).parents('.panel')
+ var panelHeading = panel.find('.panel-heading')
+ var panelBody = panel.find('.panel-body')
+ var parentCheckbox = panel.find('.config-check')
+ var configButton = panel.find('.config-button')
+ var input = panel.find('.track-config-toggle')
+ var openWas = input.val() == 'true'
+ if (open === undefined)
+ open = input.val() == 'true' && (panelHeading.hasClass('enable-on-empty') || this.numberChecked(context) > 0)
+ // open is defined, that is an user action
+ else {
+ if (open) {
+ if (panelHeading.hasClass('open-on-enable'))
+ panelBody.collapse('show')
+ } else
+ panelBody.collapse('hide')
+ }
+
+ configButton.toggle(open)
+ parentCheckbox.toggleClass('fa-toggle-on', open)
+ parentCheckbox.toggleClass('fa-toggle-off', !open)
+ input.prop('value', open)
+ if (openWas != open)
+ open_graph.track.config.submit()
+ },
+
+ // the event of change
+ toggleEvent: function(context, event) {
+ var panel = $(context).parents('.panel')
+ var panelBody = panel.find('.panel-body')
+ var checkboxes = panelBody.find('input[type=checkbox]')
+ var open = panel.find('.track-config-toggle').val() == 'true'
+ open = !open;
+
+ checkboxes.prop('checked', open)
+
+ this.headingToggle(context, open)
+ return false;
+ },
+
+ open: function(context) {
+ var panel = $(context).parents('.panel')
+ var panelBody = panel.find('.panel-body')
+ panelBody.collapse('show')
+ },
+
+ toggleObjectType: function(checkbox) {
+ checkbox = $(checkbox)
+
+ this.headingToggle(checkbox)
+
+ checkbox.siblings("input[name*='[_destroy]']").val(!checkbox.is(':checked'))
+ open_graph.track.config.submit()
+ },
+
+ numberChecked: function(context) {
+ var panel = $(context).parents('.panel')
+ var panelBody = panel.find('.panel-body')
+ var checkboxes = panel.find('.panel-body input[type=checkbox]')
+ var profilesInput = panel.find('.panel-body .select-profiles')
+
+ var nObjects = checkboxes.filter(':checked').length
+ var nProfiles = profilesInput.length ? profilesInput.tokenfield('getTokens').length : 0;
+ var nChecked = nObjects + nProfiles;
+ var nTotal = checkboxes.length + nProfiles
+
+ return nChecked
+ },
+
+ enterprise: {
+ see_all: function(context) {
+ var panel = $(context).parents('.panel')
+ var panelBody = panel.find('.panel-body')
+ noosfero.modal.html(panelBody.html())
+ },
+ },
+
+ initAutocomplete: function(track, url, items) {
+ var selector = '#select-'+track
+ var input = $(selector)
+ var tokenField = open_graph.autocomplete.init(url, selector, items)
+
+ input.change(open_graph.track.config.submit)
+ tokenField
+ .on('tokenfield:createdtoken tokenfield:removedtoken', function() {
+ open_graph.track.config.headingToggle(this)
+ }).on('tokenfield:createtoken tokenfield:removetoken', function(event) {
+ input.val()
+ }).on('tokenfield:createtoken', function(event) {
+ var existingTokens = $(this).tokenfield('getTokens')
+ $.each(existingTokens, function(index, token) {
+ if (token.value === event.attrs.value)
+ event.preventDefault()
+ })
+ })
+
+ return tokenField;
+ },
+
+ },
+ },
+
+ autocomplete: {
+ bloodhoundOptions: {
+ datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
+ queryTokenizer: Bloodhound.tokenizers.whitespace,
+ ajax: {
+ beforeSend: function() {
+ input.addClass('small-loading')
+ },
+ complete: function() {
+ input.removeClass('small-loading')
+ },
+ },
+ },
+ tokenfieldOptions: {
+
+ },
+ typeaheadOptions: {
+ minLength: 1,
+ highlight: true,
+ },
+
+ init: function(url, selector, data, options) {
+ options = options || {}
+ var bloodhoundOptions = $.extend({}, this.bloodhoundOptions, options.bloodhound || {});
+ var typeaheadOptions = $.extend({}, this.typeaheadOptions, options.typeahead || {});
+ var tokenfieldOptions = $.extend({}, this.tokenfieldOptions, options.tokenfield || {});
+
+ var input = $(selector)
+ bloodhoundOptions.remote = {
+ url: url,
+ replace: function(url, uriEncodedQuery) {
+ return $.param.querystring(url, {query:uriEncodedQuery});
+ },
+ }
+ var engine = new Bloodhound(bloodhoundOptions)
+ engine.initialize()
+
+ tokenfieldOptions.typeahead = [typeaheadOptions, { displayKey: 'label', source: engine.ttAdapter() }]
+
+ var tokenField = input.tokenfield(tokenfieldOptions)
+ input.tokenfield('setTokens', data)
+
+ return input
+ },
+ },
+}
+
=====================================
plugins/open_graph/public/style.scss
=====================================
--- /dev/null
+++ b/plugins/open_graph/public/style.scss
@@ -0,0 +1 @@
+stylesheets/style.scss
\ No newline at end of file
=====================================
plugins/open_graph/public/stylesheets/style.scss
=====================================
--- /dev/null
+++ b/plugins/open_graph/public/stylesheets/style.scss
@@ -0,0 +1,66 @@
+#track-form {
+
+ .panel-heading {
+ a, a:visited {
+ color: #fff;
+ display: block;
+ text-decoration: none;
+ }
+ a:hover {
+ text-decoration: underline;
+ }
+ a.btn {
+ display: inline-block;
+ text-decoration: none;
+ }
+ }
+
+ // always use one line to fit placeholder
+ .tokenfield {
+
+ .twitter-typeahead {
+ width: 100%;
+ display: block;
+
+ .tt-input {
+ width: 100% !important;
+ }
+ }
+ }
+
+ #track-config {
+ .panel-heading {
+ padding-left: 36px;
+ }
+ span.config-check {
+ font-weight: bold;
+ margin-left: -26px;
+ margin-right: 4px;
+ }
+ span.config-check.fa-toggle-off {
+ color: #99f;
+ }
+ .activity-config, .sse-config, .community-config {
+ float:right;
+ }
+ .activity-label, .sse-label, .community-label {
+ margin-right: 90px;
+ }
+ }
+}
+
+// shown inside a popin
+.open-graph-enterprises-modal {
+ overflow: hidden;
+
+ h1 {
+ font-size: 22px;
+ }
+ #open-graph-favorite-enterprises-how-to {
+ clear:both;
+ padding-top: 1px;
+ }
+ p {
+ text-align:justify;
+ }
+}
=====================================
plugins/open_graph/test/functional/open_graph_graph/my_profile_controller_test.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/test/functional/open_graph_graph/my_profile_controller_test.rb
@@ -0,0 +1,54 @@
+require 'test_helper'
+require 'open_graph_plugin/myprofile_controller'
+
+# Re-raise errors caught by the controller.
+class OpenGraphPlugin::MyprofileController; def rescue_action(e) raise e end; end
+
+class OpenGraphPlugin::MyprofileControllerTest < ActionController::TestCase
+
+ def setup
+ @controller = OpenGraphPlugin::MyprofileController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @actor = create_user.person
+ end
+
+ should "save selected activities" do
+ login_as @actor.identifier
+ @myenterprise = @actor.environment.enterprises.create! name: 'mycoop', identifier: 'mycoop'
+ @myenterprise.add_member @actor
+ @enterprise = @actor.environment.enterprises.create! name: 'coop', identifier: 'coop'
+ @enterprise.fans << @actor
+
+ post :track_config, profile: @actor.identifier, profile_data: {
+ open_graph_settings: {
+ activity_track_enabled: "true",
+ enterprise_track_enabled: "true",
+ community_track_enabled: "false",
+ },
+ open_graph_activity_track_configs_attributes: {
+ 0 => {
+ tracker_id: @actor.id,
+ object_type: 'blog_post',
+ },
+ },
+
+ # ignored, enterprise uses static tracking
+ open_graph_enterprise_profiles_ids: [@enterprise.id],
+ }
+ @actor.reload
+
+ assert_equal true, @actor.open_graph_settings.activity_track_enabled
+ assert_equal true, @actor.open_graph_settings.enterprise_track_enabled
+ assert_equal false, @actor.open_graph_settings.community_track_enabled
+
+ assert_equal 1, @actor.open_graph_activity_track_configs.count
+ assert_equal 'blog_post', @actor.open_graph_activity_track_configs.first.object_type
+ assert_equal @actor.id, @actor.open_graph_activity_track_configs.first.tracker_id
+
+ assert_equal [@actor], OpenGraphPlugin::EnterpriseTrackConfig.trackers_to_profile(@enterprise)
+ assert_equal [@actor], OpenGraphPlugin::EnterpriseTrackConfig.trackers_to_profile(@myenterprise)
+
+ end
+
+end
=====================================
plugins/open_graph/test/unit/open_graph_graph/publisher_test.rb
=====================================
--- /dev/null
+++ b/plugins/open_graph/test/unit/open_graph_graph/publisher_test.rb
@@ -0,0 +1,111 @@
+require "test_helper"
+
+class OpenGraphPlugin::PublisherTest < ActiveSupport::TestCase
+
+ def setup
+ @actor = create_user.person
+ User.current = @actor.user
+ @stories = OpenGraphPlugin::Stories::Definitions
+ @publisher = OpenGraphPlugin::Publisher.new
+ OpenGraphPlugin::Stories.stubs(:publishers).returns([@publisher])
+ @publisher.stubs(:context).returns(:open_graph)
+ @publisher.stubs(:og_domain).returns('noosfero.net')
+ end
+
+ should "publish only tracked stuff" do
+ @other_actor = create_user.person
+
+ @myenterprise = @actor.environment.enterprises.create! name: 'mycoop', identifier: 'mycoop'
+ @myenterprise.add_member @actor
+ @enterprise = @actor.environment.enterprises.create! name: 'coop', identifier: 'coop'
+ # the original domain from open_graph should be used
+ @enterprise.domains.create! name: 'customdomain.com'
+
+ @community = @actor.environment.communities.create! name: 'comm', identifier: 'comm', closed: false
+
+ @actor.update_attributes!({
+ open_graph_settings: {
+ activity_track_enabled: "true",
+ enterprise_track_enabled: "true",
+ community_track_enabled: "true",
+ },
+ open_graph_activity_track_configs_attributes: {
+ 0 => { tracker_id: @actor.id, object_type: 'blog_post', },
+ 1 => { tracker_id: @actor.id, object_type: 'gallery_image', },
+ 2 => { tracker_id: @actor.id, object_type: 'uploaded_file', },
+ 3 => { tracker_id: @actor.id, object_type: 'event', },
+ 4 => { tracker_id: @actor.id, object_type: 'forum', },
+ 5 => { tracker_id: @actor.id, object_type: 'friend', },
+ 6 => { tracker_id: @actor.id, object_type: 'favorite_enterprise', },
+ },
+ open_graph_enterprise_profiles_ids: "#{@enterprise.id}",
+ open_graph_community_profiles_ids: "#{@community.id}",
+ })
+ @other_actor.update_attributes! open_graph_settings: { activity_track_enabled: "true", },
+ open_graph_activity_track_configs_attributes: { 0 => { tracker_id: @other_actor.id, object_type: 'friend', }, }
+
+ # active
+ User.current = @actor.user
+
+ blog = Blog.create! profile: @actor, name: 'blog'
+ blog_post = TinyMceArticle.new profile: User.current.person, parent: blog, name: 'blah', author: User.current.person
+ @publisher.expects(:publish).with(User.current.person, @stories[:create_an_article], @publisher.send(:url_for, blog_post))
+ blog_post.save!
+
+ gallery = Gallery.create! name: 'gallery', profile: User.current.person
+ image = UploadedFile.new uploaded_data: fixture_file_upload('/files/rails.png', 'image/png'), parent: gallery, profile: User.current.person
+ @publisher.expects(:publish).with(User.current.person, @stories[:add_an_image], @publisher.send(:url_for, image, image.url.merge(view: true)))
+ image.save!
+
+ document = UploadedFile.new uploaded_data: fixture_file_upload('/files/doctest.en.xhtml', 'text/html'), profile: User.current.person
+ @publisher.expects(:publish).with(User.current.person, @stories[:add_a_document], @publisher.send(:url_for, document, document.url.merge(view: true)))
+ document.save!
+
+ event = Event.new name: 'event', profile: User.current.person
+ @publisher.expects(:publish).with(User.current.person, @stories[:create_an_event], @publisher.send(:url_for, event))
+ event.save!
+
+ forum = Forum.create! name: 'forum', profile: User.current.person
+ topic = TinyMceArticle.new profile: User.current.person, parent: forum, name: 'blah2', author: User.current.person
+ @publisher.expects(:publish).with(User.current.person, @stories[:start_a_discussion], @publisher.send(:url_for, topic, topic.url.merge(og_type: MetadataPlugin.og_types[:forum])))
+ topic.save!
+
+ @publisher.expects(:publish).with(@actor, @stories[:make_friendship_with], @publisher.send(:url_for, @other_actor)).twice
+ @publisher.expects(:publish).with(@other_actor, @stories[:make_friendship_with], @publisher.send(:url_for, @actor)).twice
+ AddFriend.create!(person: @actor, friend: @other_actor).finish
+ Friendship.remove_friendship @actor, @other_actor
+ # friend verb is groupable
+ AddFriend.create!(person: @actor, friend: @other_actor).finish
+
+ @publisher.expects(:publish).with(User.current.person, @stories[:favorite_a_sse_initiative], @publisher.send(:url_for, @enterprise))
+ @enterprise.fans << User.current.person
+
+ # active but published as passive
+ User.current = @actor.user
+
+ blog_post = TinyMceArticle.new profile: @enterprise, parent: @enterprise.blog, name: 'blah', author: User.current.person
+ story = @stories[:announce_news_from_a_sse_initiative]
+ @publisher.expects(:publish).with(User.current.person, story, @publisher.send(:passive_url_for, blog_post, nil, story))
+ blog_post.save!
+
+ # passive
+ User.current = @other_actor.user
+
+ # fan
+ blog_post = TinyMceArticle.new profile: @enterprise, parent: @enterprise.blog, name: 'blah2', author: User.current.person
+ story = @stories[:announce_news_from_a_sse_initiative]
+ @publisher.expects(:publish).with(@actor, story, 'http://noosfero.net/coop/blog/blah2')
+ blog_post.save!
+ # member
+ blog_post = TinyMceArticle.new profile: @myenterprise, parent: @myenterprise.blog, name: 'blah2', author: User.current.person
+ story = @stories[:announce_news_from_a_sse_initiative]
+ @publisher.expects(:publish).with(@actor, story, 'http://noosfero.net/mycoop/blog/blah2')
+ blog_post.save!
+
+ blog_post = TinyMceArticle.new profile: @community, parent: @community.blog, name: 'blah', author: User.current.person
+ story = @stories[:announce_news_from_a_community]
+ @publisher.expects(:publish).with(@actor, story, 'http://noosfero.net/comm/blog/blah')
+ blog_post.save!
+ end
+
+end
=====================================
plugins/open_graph/views/open_graph_plugin/myprofile/_ac_profile.html.erb
=====================================
--- /dev/null
+++ b/plugins/open_graph/views/open_graph_plugin/myprofile/_ac_profile.html.erb
@@ -0,0 +1,2 @@
+<%= profile_image profile, :icon %>
+<%= profile.short_name nil %>
=====================================
plugins/open_graph/views/open_graph_plugin/myprofile/_heading.html.erb
=====================================
--- /dev/null
+++ b/plugins/open_graph/views/open_graph_plugin/myprofile/_heading.html.erb
@@ -0,0 +1,5 @@
+<span class='config-check fa'></span>
+<%= f.fields_for "#{context}_settings" do |ff| %>
+ <%= ff.hidden_field klass.track_enabled_field, value: profile.send("#{context}_settings").send(klass.track_enabled_field), class: 'track-config-toggle' %>
+<% end %>
+<%= t("open_graph_plugin.views.track.config.#{track}.label") %>
=====================================
plugins/open_graph/views/open_graph_plugin/myprofile/_profile_search.jsonify
=====================================
--- /dev/null
+++ b/plugins/open_graph/views/open_graph_plugin/myprofile/_profile_search.jsonify
@@ -0,0 +1,7 @@
+self.formats = [:html]
+profiles.each do |p|
+ json << {
+ value: p.id, label: render('open_graph_plugin/myprofile/ac_profile', profile: p),
+ }
+end
+
=====================================
plugins/open_graph/views/open_graph_plugin/myprofile/_track_activity.html.erb
=====================================
--- /dev/null
+++ b/plugins/open_graph/views/open_graph_plugin/myprofile/_track_activity.html.erb
@@ -0,0 +1,12 @@
+<div class="panel-heading">
+ <%= button_to_function 'menu-ctrl-panel', t('open_graph_plugin.views.track.config.activity.configure'), "",
+ class: 'activity-config config-button', option: 'success', size: 'xs', 'data-target' => "#track-#{track}", 'data-toggle' => 'collapse', 'aria-controls' => 'collapseTwo' %>
+ <a href="#" onclick='return open_graph.track.config.toggleEvent(this, event)' class='activity-label'>
+ <%= render 'heading', f: f, track: track, context: context, klass: klass %>
+ </a>
+</div>
+
+<div id="track-<%=track%>" class="panel-body collapse">
+ <%= render 'track_objects', f: f, track: track, objects: klass.objects, klass: klass, context: context %>
+</div>
+
=====================================
plugins/open_graph/views/open_graph_plugin/myprofile/_track_community.html.erb
=====================================
--- /dev/null
+++ b/plugins/open_graph/views/open_graph_plugin/myprofile/_track_community.html.erb
@@ -0,0 +1,12 @@
+<div class="panel-heading open-on-enable">
+ <%= button_to_function 'menu-ctrl-panel', t('open_graph_plugin.views.track.config.activity.configure'), "",
+ class: 'community-config config-button', option: 'success', size: 'xs', 'data-target' => "#track-#{track}", 'data-toggle' => 'collapse', 'aria-controls' => 'collapseTwo' %>
+ <a href="#track-<%=track%>" onclick='open_graph.track.config.toggleEvent(this, event)', class='community-label'>
+ <%= render 'heading', f: f, track: track, context: context, klass: klass %>
+ </a>
+</div>
+
+<div id="track-<%=track%>" class="panel-body collapse">
+ <%= render 'track_objects', f: f, track: track, objects: klass.objects, klass: klass, context: context %>
+ <%= render 'track_profiles', f: f, track: track, context: context, klass: klass %>
+</div>
=====================================
plugins/open_graph/views/open_graph_plugin/myprofile/_track_enterprise.html.erb
=====================================
--- /dev/null
+++ b/plugins/open_graph/views/open_graph_plugin/myprofile/_track_enterprise.html.erb
@@ -0,0 +1,44 @@
+<div class="panel-heading enable-on-empty">
+ <%= button_to_function 'menu-ctrl-panel', t('open_graph_plugin.views.track.config.enterprise.see_all'), 'open_graph.track.config.enterprise.see_all(this)',
+ class: 'sse-config config-button', option: 'success', size: 'xs' %>
+ <a href="#" onclick='return open_graph.track.config.toggleEvent(this, event)' style='sse-label'>
+ <%= render 'heading', f: f, track: track, context: context, klass: klass %>
+ </a>
+</div>
+
+<div id="track-<%=track%>" class="panel-body collapse" style="display: none">
+ <% if user.enterprises.present? %>
+ <div id="enterprises-memberships" class="open-graph-enterprises-modal">
+ <h1>
+ <%= t('open_graph_plugin.views.track.config.enterprise.memberships') %>
+ </h1>
+ <div class="open-graph-enterprises-list">
+ <% user.enterprises.public.enabled.each do |enterprise| %>
+ <%= profile_image_link enterprise, :portrait, :div %>
+ <% end %>
+ </div>
+ </div>
+ <% end %>
+
+ <div id="favorite-enterprises" class="open-graph-enterprises-modal">
+ <h1>
+ <%= t('open_graph_plugin.views.track.config.enterprise.favorites') %>
+ </h1>
+ <% if user.favorite_enterprises.present? %>
+ <div class="open-graph-enterprises-list">
+ <% user.favorite_enterprises.public.enabled.each do |enterprise| %>
+ <%= profile_image_link enterprise, :portrait, :div %>
+ <% end %>
+ </div>
+ <% end %>
+ <div id='open-graph-favorite-enterprises-how-to'>
+ <h1>
+ <%= t('open_graph_plugin.views.track.config.enterprise.favorites_how_to.title') %>
+ </h1>
+ <p>
+ <%= t 'open_graph_plugin.views.track.config.enterprise.favorites_how_to.body', favorite_button: button_to_function(:love, _('Add as favorite'), '', :title => _('Add enterprise as favorite'), :option => 'success') %>
+ </p>
+ </div>
+ </div>
+</div>
+
=====================================
plugins/open_graph/views/open_graph_plugin/myprofile/_track_form.html.erb
=====================================
--- /dev/null
+++ b/plugins/open_graph/views/open_graph_plugin/myprofile/_track_form.html.erb
@@ -0,0 +1,22 @@
+<%
+ reload ||= false
+%>
+<%= javascript_tag do %>
+ open_graph.track.config.reload = <%= reload.to_json %>
+<% end %>
+
+<%= form_for profile, as: :profile_data, remote: true, url: {action: :track_config},
+ html: {id: 'track-config', onsubmit: 'return open_graph.track.config.submit()'} do |f| %>
+
+ <div class="panel-group" role="tablist" aria-multiselectable="true">
+ <% OpenGraphPlugin::TrackConfig::Types.each do |track, klass| %>
+ <div class="panel panel-primary">
+ <%= render "track_#{track}", f: f, track: track, klass: "OpenGraphPlugin::#{klass}".constantize, context: context %>
+ </div>
+ <% end %>
+ </div>
+<% end %>
+
+<%= javascript_tag do %>
+ open_graph.track.config.init()
+<% end %>
=====================================
plugins/open_graph/views/open_graph_plugin/myprofile/_track_friend.html.erb
=====================================
--- /dev/null
+++ b/plugins/open_graph/views/open_graph_plugin/myprofile/_track_friend.html.erb
@@ -0,0 +1,10 @@
+<div class="panel-heading">
+ <a href="#track-<%=track%>" data-toggle="collapse" aria-controls="collapseTwo" onclick='open_graph.track.config.toggleEvent(this, event)'>
+ <%= render 'heading', f: f, track: track, context: context, klass: klass %>
+ </a>
+</div>
+
+<div id="track-<%=track%>" class="panel-body collapse">
+ <%= render 'track_objects', f: f, track: track, objects: klass.objects, klass: klass, context: context %>
+ <%= render 'track_profiles', f: f, track: track, context: context, klass: klass %>
+</div>
=====================================
plugins/open_graph/views/open_graph_plugin/myprofile/_track_objects.html.erb
=====================================
--- /dev/null
+++ b/plugins/open_graph/views/open_graph_plugin/myprofile/_track_objects.html.erb
@@ -0,0 +1,17 @@
+<%
+ tracks = profile.send klass.association
+%>
+
+<% objects.each do |object| %>
+ <div id="object-<%= object %>" class="tracked-object">
+ <% track_record = tracks.find{ |t| t.object_type == object } || profile.send(klass.association).build %>
+ <%= f.fields_for klass.association, track_record do |ff| %>
+ <%= ff.hidden_field :id %>
+ <%= ff.hidden_field :tracker_id %>
+ <%= ff.check_box :object_type, {onchange: 'open_graph.track.config.toggleObjectType(this)'}, object, '' %>
+ <%= ff.label :object_type, t("open_graph_plugin.views.track.config.#{track}.objects.#{object}") %>
+ <%= ff.hidden_field :_destroy %>
+ <% end %>
+ </div>
+<% end %>
+
=====================================
plugins/open_graph/views/open_graph_plugin/myprofile/_track_profiles.html.erb
=====================================
--- /dev/null
+++ b/plugins/open_graph/views/open_graph_plugin/myprofile/_track_profiles.html.erb
@@ -0,0 +1,19 @@
+<%
+ static = klass.static_trackers
+ profiles = klass.profile_track_objects profile
+%>
+<%= text_field_tag "#{f.object_name}[open_graph_#{track}_profiles_ids]", '', id: "select-#{track}", class: 'select-profiles',
+ placeholder: (t("open_graph_plugin.views.track.config.#{track}.search_placeholder") unless static),
+ disabled: ("disabled" if static) %>
+
+<%= javascript_tag do %>
+ $(document).ready(function () {
+ var input = open_graph.track.config.initAutocomplete(<%=track.to_json%>,
+ <%= url_for(action: "#{track}_search").to_json %>,
+ <%= profiles.map{ |p| {value: p.id, label: render('ac_profile', profile: p), } }.to_json %>
+ )
+ <% if static %>
+ input.tokenfield('readonly')
+ <% end %>
+ })
+<% end %>
View it on GitLab: https://gitlab.com/noosfero/noosfero/compare/6c114d19fdd68478b9612111c345b356486b5adf...180ad5296e483134f6df021d56008e75c2e2dc0e
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listas.softwarelivre.org/pipermail/noosfero-dev/attachments/20150813/75467a5d/attachment-0001.html>
More information about the Noosfero-dev
mailing list