Commit 984386a416854d4b1e2993a0649043a04027cf65
Exists in
staging
and in
42 other branches
Merge branch 'metadata-plugin' into 'master'
Changes on metadata plugin Discussed on !359 See merge request !444
Showing
21 changed files
with
296 additions
and
218 deletions
Show diff stats
app/helpers/layout_helper.rb
app/models/article.rb
| ... | ... | @@ -390,6 +390,10 @@ class Article < ActiveRecord::Base |
| 390 | 390 | {} |
| 391 | 391 | end |
| 392 | 392 | |
| 393 | + def alternate_languages | |
| 394 | + self.translations.map(&:language) | |
| 395 | + end | |
| 396 | + | |
| 393 | 397 | scope :native_translations, :conditions => { :translation_of_id => nil } |
| 394 | 398 | |
| 395 | 399 | def translatable? | ... | ... |
app/views/layouts/application-ng.html.erb
| ... | ... | @@ -7,11 +7,6 @@ |
| 7 | 7 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
| 8 | 8 | <meta name="description" content="<%= @environment.name %>" /> |
| 9 | 9 | |
| 10 | - <!-- Twitter Card --> | |
| 11 | - <meta name="twitter:card" value="summary"> | |
| 12 | - <meta name="twitter:title" content="<%= h page_title %>"> | |
| 13 | - <meta name="twitter:description" content="<%= meta_description_tag(@page) %>"> | |
| 14 | - | |
| 15 | 10 | <!-- site root --> |
| 16 | 11 | <meta property="noosfero:root" content="<%= Noosfero.root %>"/> |
| 17 | 12 | ... | ... |
plugins/metadata/config.yml.dist
| 1 | 1 | open_graph: |
| 2 | - domain: cirandas.net | |
| 3 | - environment_logo: 'http://cirandas.net/designs/themes/cirandas-responsive/images/cirandas-logo-110.png' | |
| 2 | + domain: domainregisteredonfacebook.com | |
| 3 | + environment_logo: 'http://example.com/designs/themes/environmenttheme/images/logo.png' | |
| 4 | 4 | types: |
| 5 | 5 | article: article |
| 6 | - product: app_cirandas:sse_product | |
| 7 | - uploaded_file: app_cirandas:document | |
| 8 | - image: app_cirandas:picture | |
| 9 | - profile: app_cirandas:profile | |
| 10 | - person: app_cirandas:user | |
| 11 | - community: app_cirandas:community | |
| 12 | - enterprise: app_cirandas:sse_initiative | |
| 6 | + product: facebook_app:sse_product | |
| 7 | + uploaded_file: facebook_app:document | |
| 8 | + image: facebook_app:picture | |
| 9 | + profile: facebook_app:profile | |
| 10 | + person: facebook_app:user | |
| 11 | + community: facebook_app:community | |
| 12 | + enterprise: facebook_app:sse_initiative | ... | ... |
plugins/metadata/lib/ext/article.rb
| ... | ... | @@ -2,31 +2,42 @@ require_dependency 'article' |
| 2 | 2 | |
| 3 | 3 | class Article |
| 4 | 4 | |
| 5 | - Metadata = { | |
| 6 | - 'og:type' => MetadataPlugin.og_types[:article], | |
| 7 | - 'og:url' => proc{ |a, c| c.og_url_for a.url }, | |
| 8 | - 'og:title' => proc{ |a, c| a.title }, | |
| 9 | - 'og:image' => proc do |a, c| | |
| 10 | - result = a.body_images_paths | |
| 11 | - result = "#{a.profile.environment.top_url}#{a.profile.image.public_filename}" if a.profile.image if result.blank? | |
| 12 | - result = MetadataPlugin.config[:open_graph][:environment_logo] if result.blank? | |
| 13 | - result | |
| 14 | - end, | |
| 15 | - 'og:see_also' => [], | |
| 16 | - 'og:site_name' => proc{ |a, c| a.profile.name }, | |
| 17 | - 'og:updated_time' => proc{ |a, c| a.updated_at.iso8601 }, | |
| 18 | - 'og:locale:locale' => proc{ |a, c| a.environment.default_language }, | |
| 19 | - 'og:locale:alternate' => proc{ |a, c| a.environment.languages - [a.environment.default_language] }, | |
| 20 | - 'twitter:image' => proc{ |a, c| a.body_images_paths }, | |
| 21 | - 'article:expiration_time' => "", # In the future we might want to populate this | |
| 22 | - 'article:modified_time' => proc{ |a, c| a.updated_at.iso8601 }, | |
| 23 | - 'article:published_time' => proc{ |a, c| a.published_at.iso8601 }, | |
| 24 | - 'article:section' => "", # In the future we might want to populate this | |
| 25 | - 'article:tag' => proc{ |a, c| a.tags.map &:name }, | |
| 26 | - 'og:description' => proc{ |a, c| ActionView::Base.full_sanitizer.sanitize a.body }, | |
| 27 | - 'og:rich_attachment' => "", | |
| 5 | + metadata_spec namespace: :og, key_attr: :property, tags: { | |
| 6 | + type: MetadataPlugin.og_types[:article] || :article, | |
| 7 | + url: proc{ |a, plugin| plugin.og_url_for a.url }, | |
| 8 | + title: proc{ |a, plugin| "#{a.title} - #{a.profile.name}" }, | |
| 9 | + image: proc do |a, plugin| | |
| 10 | + result = a.body_images_paths | |
| 11 | + result = "#{a.profile.environment.top_url}#{a.profile.image.public_filename}" if a.profile.image if result.blank? | |
| 12 | + result ||= MetadataPlugin.config[:open_graph][:environment_logo] rescue nil if result.blank? | |
| 13 | + result | |
| 14 | + end, | |
| 15 | + see_also: [], | |
| 16 | + site_name: proc{ |a, c| a.profile.name }, | |
| 17 | + updated_time: proc{ |a, c| a.updated_at.iso8601 }, | |
| 18 | + 'locale:locale' => proc{ |a, c| a.language || a.environment.default_language }, | |
| 19 | + 'locale:alternate' => proc{ |a, c| a.alternate_languages }, | |
| 20 | + | |
| 21 | + description: proc{ |a, plugin| ActionView::Base.full_sanitizer.sanitize a.body }, | |
| 22 | + rich_attachment: "", | |
| 28 | 23 | } |
| 29 | 24 | |
| 25 | + metadata_spec namespace: :twitter, key_attr: :name, tags: { | |
| 26 | + card: 'summary', | |
| 27 | + description: proc do |a, plugin| | |
| 28 | + description = a.body.to_s || a.environment.name | |
| 29 | + CGI.escapeHTML(plugin.helpers.truncate(plugin.helpers.strip_tags(description), length: 200)) | |
| 30 | + end, | |
| 31 | + title: proc{ |a, plugin| "#{a.title} - #{a.profile.name}" }, | |
| 32 | + image: proc{ |a, plugin| a.body_images_paths }, | |
| 33 | + } | |
| 30 | 34 | |
| 35 | + metadata_spec namespace: :article, key_attr: :property, tags: { | |
| 36 | + expiration_time: "", # In the future we might want to populate this | |
| 37 | + modified_time: proc{ |a, plugin| a.updated_at.iso8601 }, | |
| 38 | + published_time: proc{ |a, plugin| a.published_at.iso8601 }, | |
| 39 | + section: "", # In the future we might want to populate this | |
| 40 | + tag: proc{ |a, plugin| a.tags.map &:name }, | |
| 41 | + } | |
| 31 | 42 | |
| 32 | 43 | end | ... | ... |
plugins/metadata/lib/ext/community.rb
| ... | ... | @@ -3,8 +3,8 @@ require_dependency "#{File.dirname __FILE__}/profile" |
| 3 | 3 | |
| 4 | 4 | class Community |
| 5 | 5 | |
| 6 | - Metadata = Metadata.merge({ | |
| 7 | - 'og:type' => MetadataPlugin.og_types[:community], | |
| 8 | - }) | |
| 6 | + metadata_spec namespace: :og, tags: { | |
| 7 | + type: MetadataPlugin.og_types[:community] || :community, | |
| 8 | + } | |
| 9 | 9 | |
| 10 | 10 | end | ... | ... |
plugins/metadata/lib/ext/enterprise.rb
| ... | ... | @@ -3,16 +3,18 @@ require_dependency "#{File.dirname __FILE__}/profile" |
| 3 | 3 | |
| 4 | 4 | class Enterprise |
| 5 | 5 | |
| 6 | - Metadata = Metadata.merge({ | |
| 7 | - 'og:type' => MetadataPlugin.og_types[:enterprise], | |
| 8 | - 'business:contact_data:email' => proc{ |e, c| e.contact_email }, | |
| 9 | - 'business:contact_data:phone_number' => proc{ |e, c| e.contact_phone }, | |
| 10 | - 'business:contact_data:street_address' => proc{ |e, c| e.address }, | |
| 11 | - 'business:contact_data:locality' => proc{ |e, c| e.city }, | |
| 12 | - 'business:contact_data:region' => proc{ |e, c| e.state }, | |
| 13 | - 'business:contact_data:postal_code' => proc{ |e, c| e.zip_code }, | |
| 14 | - 'business:contact_data:country_name' => proc{ |e| e.country }, | |
| 15 | - 'place:location:latitude' => proc{ |e, c| p.lat }, | |
| 16 | - 'place:location:longitude' => proc{ |e, c| p.lng }, | |
| 17 | - }) | |
| 6 | + metadata_spec namespace: :og, tags: { | |
| 7 | + type: MetadataPlugin.og_types[:enterprise] || :enterprise, | |
| 8 | + } | |
| 9 | + | |
| 10 | + metadata_spec namespace: 'business:contact_data', tags: { | |
| 11 | + email: proc{ |e, plugin| e.contact_email }, | |
| 12 | + phone_number: proc{ |e, plugin| e.contact_phone }, | |
| 13 | + street_address: proc{ |e, plugin| e.address }, | |
| 14 | + locality: proc{ |e, plugin| e.city }, | |
| 15 | + region: proc{ |e, plugin| e.state }, | |
| 16 | + postal_code: proc{ |e, plugin| e.zip_code }, | |
| 17 | + country_name: proc{ |e, plugin| e.country }, | |
| 18 | + } | |
| 19 | + | |
| 18 | 20 | end | ... | ... |
plugins/metadata/lib/ext/environment.rb
| ... | ... | @@ -2,12 +2,20 @@ require_dependency 'environment' |
| 2 | 2 | |
| 3 | 3 | class Environment |
| 4 | 4 | |
| 5 | - Metadata = { | |
| 6 | - 'og:site_name' => proc{ |e, c| e.name }, | |
| 7 | - 'og:description' => proc{ |e, c| e.name }, | |
| 8 | - 'og:url' => proc{ |e, c| e.top_url }, | |
| 9 | - 'og:locale:locale' => proc{ |e, c| e.default_language }, | |
| 10 | - 'og:locale:alternate' => proc{ |e, c| e.languages - [e.default_language] } | |
| 5 | + metadata_spec namespace: :og, tags: { | |
| 6 | + type: 'website', | |
| 7 | + title: proc{ |e, plugin| e.name }, | |
| 8 | + site_name: proc{ |e, plugin| e.name }, | |
| 9 | + description: proc{ |e, plugin| e.name }, | |
| 10 | + url: proc{ |e, plugin| e.top_url }, | |
| 11 | + 'locale:locale' => proc{ |e, plugin| e.default_language }, | |
| 12 | + 'locale:alternate' => proc{ |e, plugin| if e.default_language then e.languages - [e.default_language] else e.languages end }, | |
| 13 | + } | |
| 14 | + | |
| 15 | + metadata_spec namespace: :twitter, key_attr: :name, tags: { | |
| 16 | + card: 'summary', | |
| 17 | + title: proc{ |e, plugin| e.name }, | |
| 18 | + description: proc{ |e, plugin| e.name }, | |
| 11 | 19 | } |
| 12 | 20 | |
| 13 | 21 | end | ... | ... |
plugins/metadata/lib/ext/person.rb
| ... | ... | @@ -3,8 +3,8 @@ require_dependency "#{File.dirname __FILE__}/profile" |
| 3 | 3 | |
| 4 | 4 | class Person |
| 5 | 5 | |
| 6 | - Metadata = Metadata.merge({ | |
| 7 | - 'og:type' => MetadataPlugin.og_types[:person], | |
| 8 | - }) | |
| 6 | + metadata_spec namespace: :og, tags: { | |
| 7 | + type: MetadataPlugin.og_types[:person] || :person, | |
| 8 | + } | |
| 9 | 9 | |
| 10 | 10 | end | ... | ... |
plugins/metadata/lib/ext/product.rb
| ... | ... | @@ -2,24 +2,25 @@ require_dependency 'product' |
| 2 | 2 | |
| 3 | 3 | class Product |
| 4 | 4 | |
| 5 | - Metadata = { | |
| 6 | - 'og:type' => MetadataPlugin.og_types[:product], | |
| 7 | - 'og:url' => proc{ |p, c| c.og_url_for p.url }, | |
| 8 | - 'og:gr_hascurrencyvalue' => proc{ |p, c| p.price.to_f }, | |
| 9 | - 'og:gr_hascurrency' => proc{ |p, c| p.environment.currency_unit }, | |
| 10 | - 'og:title' => proc{ |p, c| p.name }, | |
| 11 | - 'og:description' => proc{ |p, c| ActionView::Base.full_sanitizer.sanitize p.description }, | |
| 12 | - 'og:image' => proc{ |p, c| "#{p.environment.top_url}#{p.image.public_filename}" if p.image }, | |
| 13 | - 'og:image:type' => proc{ |p, c| p.image.content_type if p.image }, | |
| 14 | - 'og:image:height' => proc{ |p, c| p.image.height if p.image }, | |
| 15 | - 'og:image:width' => proc{ |p, c| p.image.width if p.image }, | |
| 16 | - 'og:see_also' => [], | |
| 17 | - 'og:site_name' => proc{ |p, c| c.og_url_for p.profile.url }, | |
| 18 | - 'og:updated_time' => proc{ |p, c| p.updated_at.iso8601 }, | |
| 19 | - 'og:locale:locale' => proc{ |p, c| p.environment.default_language }, | |
| 20 | - 'og:locale:alternate' => proc{ |p, c| p.environment.languages - [p.environment.default_language] }, | |
| 21 | - } | |
| 5 | + metadata_spec namespace: :og, tags: { | |
| 6 | + type: MetadataPlugin.og_types[:product] || :product, | |
| 7 | + url: proc{ |p, plugin| plugin.og_url_for p.url }, | |
| 8 | + gr_hascurrencyvalue: proc{ |p, plugin| p.price.to_f }, | |
| 9 | + gr_hascurrency: proc{ |p, plugin| p.environment.currency_unit }, | |
| 10 | + title: proc{ |a, plugin| "#{p.name} - #{p.profile.name}" }, | |
| 11 | + description: proc{ |p, plugin| ActionView::Base.full_sanitizer.sanitize p.description }, | |
| 12 | + | |
| 13 | + image: proc{ |p, plugin| "#{p.environment.top_url}#{p.image.public_filename}" if p.image }, | |
| 14 | + 'image:type' => proc{ |p, plugin| p.image.content_type if p.image }, | |
| 15 | + 'image:height' => proc{ |p, plugin| p.image.height if p.image }, | |
| 16 | + 'image:width' => proc{ |p, plugin| p.image.width if p.image }, | |
| 22 | 17 | |
| 23 | - protected | |
| 18 | + see_also: [], | |
| 19 | + site_name: proc{ |p, plugin| plugin.og_url_for p.profile.url }, | |
| 20 | + updated_time: proc{ |p, plugin| p.updated_at.iso8601 }, | |
| 21 | + | |
| 22 | + 'locale:locale' => proc{ |p, plugin| p.environment.default_language }, | |
| 23 | + 'locale:alternate' => proc{ |p, plugin| p.environment.languages - [p.environment.default_language] if p.environment.languages }, | |
| 24 | + } | |
| 24 | 25 | |
| 25 | 26 | end | ... | ... |
plugins/metadata/lib/ext/profile.rb
| ... | ... | @@ -2,23 +2,32 @@ require_dependency 'profile' |
| 2 | 2 | |
| 3 | 3 | class Profile |
| 4 | 4 | |
| 5 | - Metadata = { | |
| 6 | - 'og:type' => MetadataPlugin.og_types[:profile], | |
| 7 | - 'og:image' => proc{ |p, c| "#{p.environment.top_url}#{p.image.public_filename}" if p.image }, | |
| 8 | - 'og:title' => proc{ |p, c| p.short_name nil }, | |
| 9 | - 'og:url' => proc do |p, c| | |
| 5 | + metadata_spec namespace: :og, tags: { | |
| 6 | + type: MetadataPlugin.og_types[:profile] || :profile, | |
| 7 | + image: proc{ |p, plugin| "#{p.environment.top_url}#{p.image.public_filename}" if p.image }, | |
| 8 | + title: proc{ |p, plugin| p.nickname || p.name }, | |
| 9 | + url: proc do |p, plugin| | |
| 10 | 10 | #force profile identifier for custom domains and fixed host. see og_url_for |
| 11 | - c.og_url_for p.url.merge(profile: p.identifier) | |
| 11 | + plugin.og_url_for p.url.merge(profile: p.identifier) | |
| 12 | 12 | end, |
| 13 | - 'og:description' => proc{ |p, c| p.description }, | |
| 14 | - 'og:updated_time' => proc{ |p, c| p.updated_at.iso8601 }, | |
| 15 | - 'place:location:latitude' => proc{ |p, c| p.lat }, | |
| 16 | - 'place:location:longitude' => proc{ |p, c| p.lng }, | |
| 17 | - 'og:locale:locale' => proc{ |p, c| p.environment.default_language }, | |
| 18 | - 'og:locale:alternate' => proc{ |p, c| p.environment.languages - [p.environment.default_language] }, | |
| 19 | - 'og:site_name' => "", | |
| 20 | - 'og:see_also' => "", | |
| 21 | - 'og:rich_attachment' => "", | |
| 13 | + description: proc{ |p, plugin| p.description }, | |
| 14 | + updated_time: proc{ |p, plugin| p.updated_at.iso8601 }, | |
| 15 | + 'locale:locale' => proc{ |p, plugin| p.environment.default_language }, | |
| 16 | + 'locale:alternate' => proc{ |p, plugin| p.environment.languages - [p.environment.default_language] if p.environment.languages }, | |
| 17 | + site_name: "", | |
| 18 | + see_also: "", | |
| 19 | + rich_attachment: "", | |
| 20 | + } | |
| 21 | + | |
| 22 | + metadata_spec namespace: 'place:location', tags: { | |
| 23 | + latitude: proc{ |p, plugin| p.lat }, | |
| 24 | + longitude: proc{ |p, plugin| p.lng }, | |
| 25 | + } | |
| 26 | + | |
| 27 | + metadata_spec namespace: :twitter, key_attr: :name, tags: { | |
| 28 | + card: 'summary', | |
| 29 | + title: proc{ |p, plugin| p.name }, | |
| 30 | + description: proc{ |p, plugin| p.description }, | |
| 22 | 31 | } |
| 23 | 32 | |
| 24 | 33 | end | ... | ... |
plugins/metadata/lib/ext/uploaded_file.rb
| ... | ... | @@ -3,15 +3,15 @@ require_dependency "#{File.dirname __FILE__}/article" |
| 3 | 3 | |
| 4 | 4 | class UploadedFile |
| 5 | 5 | |
| 6 | - Metadata = { | |
| 7 | - 'og:type' => proc do |u, c| | |
| 6 | + metadata_spec namespace: :og, tags: { | |
| 7 | + type: proc do |u, plugin| | |
| 8 | 8 | type = if u.image? then :image else :uploaded_file end |
| 9 | - MetadataPlugin.og_types[type] | |
| 9 | + MetadataPlugin.og_types[type] || type | |
| 10 | 10 | end, |
| 11 | - 'og:url' => proc{ |u, c| c.og_url_for u.url.merge(view: true) }, | |
| 12 | - 'og:title' => proc{ |u, c| u.title }, | |
| 13 | - 'og:image' => proc{ |u, c| "#{u.environment.top_url}#{u.public_filename}" if u.image? }, | |
| 14 | - 'og:description' => proc{ |u, c| u.abstract || u.title }, | |
| 11 | + url: proc{ |u, plugin| plugin.og_url_for u.url.merge(view: true) }, | |
| 12 | + title: proc{ |u, plugin| u.title }, | |
| 13 | + image: proc{ |u, plugin| "#{u.environment.top_url}#{u.public_filename}" if u.image? }, | |
| 14 | + description: proc{ |u, plugin| u.abstract || u.title }, | |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | end | ... | ... |
plugins/metadata/lib/metadata_plugin.rb
| ... | ... | @@ -2,11 +2,11 @@ |
| 2 | 2 | class MetadataPlugin < Noosfero::Plugin |
| 3 | 3 | |
| 4 | 4 | def self.plugin_name |
| 5 | - I18n.t 'metadata_plugin.lib.plugin.name' | |
| 5 | + _('Export metadata') | |
| 6 | 6 | end |
| 7 | 7 | |
| 8 | 8 | def self.plugin_description |
| 9 | - I18n.t 'metadata_plugin.lib.plugin.description' | |
| 9 | + _('Export metadata for models on meta tags') | |
| 10 | 10 | end |
| 11 | 11 | |
| 12 | 12 | def self.config |
| ... | ... | @@ -17,30 +17,64 @@ class MetadataPlugin < Noosfero::Plugin |
| 17 | 17 | @og_types ||= self.config[:open_graph][:types] rescue {} |
| 18 | 18 | end |
| 19 | 19 | |
| 20 | + CONTROLLERS = { | |
| 21 | + manage_products: { | |
| 22 | + variable: :@product, | |
| 23 | + }, | |
| 24 | + content_viewer: { | |
| 25 | + variable: proc do | |
| 26 | + if profile and profile.home_page_id == @page.id | |
| 27 | + @profile | |
| 28 | + elsif @page.respond_to? :encapsulated_file | |
| 29 | + @page.encapsulated_file | |
| 30 | + else | |
| 31 | + @page | |
| 32 | + end | |
| 33 | + end, | |
| 34 | + }, | |
| 35 | + profile: { | |
| 36 | + variable: :@profile, | |
| 37 | + }, | |
| 38 | + # fallback | |
| 39 | + environment: { | |
| 40 | + variable: :@environment, | |
| 41 | + }, | |
| 42 | + } | |
| 43 | + | |
| 20 | 44 | def head_ending |
| 21 | 45 | plugin = self |
| 22 | 46 | lambda do |
| 23 | - options = MetadataPlugin::Spec::Controllers[controller.controller_path.to_sym] | |
| 24 | - options ||= MetadataPlugin::Spec::Controllers[:profile] if controller.is_a? ProfileController | |
| 25 | - options ||= MetadataPlugin::Spec::Controllers[:environment] | |
| 47 | + options = MetadataPlugin::CONTROLLERS[controller.controller_path.to_sym] | |
| 48 | + options ||= MetadataPlugin::CONTROLLERS[:profile] if controller.is_a? ProfileController | |
| 49 | + options ||= MetadataPlugin::CONTROLLERS[:environment] | |
| 26 | 50 | return unless options |
| 27 | 51 | |
| 28 | 52 | return unless object = case variable = options[:variable] |
| 29 | - when Proc then instance_exec(&variable) rescue nil | |
| 53 | + when Proc then instance_exec(&variable) | |
| 30 | 54 | else instance_variable_get variable |
| 31 | 55 | end |
| 32 | - return unless metadata = (object.class.const_get(:Metadata) rescue nil) | |
| 33 | - | |
| 34 | - metadata.map do |property, contents| | |
| 35 | - contents = contents.call(object, plugin) rescue nil if contents.is_a? Proc | |
| 36 | - next if contents.blank? | |
| 37 | - | |
| 38 | - Array(contents).map do |content| | |
| 39 | - content = content.call(object, plugin) rescue nil if content.is_a? Proc | |
| 40 | - next if content.blank? | |
| 41 | - tag 'meta', property: property, content: content | |
| 42 | - end.join | |
| 43 | - end.join | |
| 56 | + return unless specs = (object.class.metadata_specs rescue nil) | |
| 57 | + | |
| 58 | + r = [] | |
| 59 | + specs.each do |namespace, spec| | |
| 60 | + namespace = "#{namespace}:" if namespace.present? | |
| 61 | + key_attr = spec[:key_attr] || :property | |
| 62 | + value_attr = spec[:value_attr] || :content | |
| 63 | + tags = spec[:tags] | |
| 64 | + | |
| 65 | + tags.each do |key, values| | |
| 66 | + key = "#{namespace}#{key}" | |
| 67 | + values = values.call(object, plugin) if values.is_a? Proc | |
| 68 | + next if values.blank? | |
| 69 | + | |
| 70 | + Array(values).each do |value| | |
| 71 | + value = value.call(object, plugin) if value.is_a? Proc | |
| 72 | + next if value.blank? | |
| 73 | + r << tag(:meta, key_attr => key, value_attr => value) | |
| 74 | + end | |
| 75 | + end | |
| 76 | + end | |
| 77 | + r.join | |
| 44 | 78 | end |
| 45 | 79 | end |
| 46 | 80 | |
| ... | ... | @@ -51,9 +85,16 @@ class MetadataPlugin < Noosfero::Plugin |
| 51 | 85 | Noosfero::Application.routes.url_helpers.url_for options |
| 52 | 86 | end |
| 53 | 87 | |
| 88 | + def helpers | |
| 89 | + self.context.class.helpers | |
| 90 | + end | |
| 91 | + | |
| 54 | 92 | protected |
| 55 | 93 | |
| 56 | 94 | end |
| 57 | 95 | |
| 58 | 96 | ActiveSupport.run_load_hooks :metadata_plugin, MetadataPlugin |
| 97 | +ActiveSupport.on_load :active_record do | |
| 98 | + ActiveRecord::Base.extend MetadataPlugin::Specs::ClassMethods | |
| 99 | +end | |
| 59 | 100 | ... | ... |
plugins/metadata/lib/metadata_plugin/spec.rb
| ... | ... | @@ -1,29 +0,0 @@ |
| 1 | - | |
| 2 | -class MetadataPlugin::Spec | |
| 3 | - | |
| 4 | - Controllers = { | |
| 5 | - manage_products: { | |
| 6 | - variable: :@product, | |
| 7 | - }, | |
| 8 | - content_viewer: { | |
| 9 | - variable: proc do | |
| 10 | - if profile and profile.home_page_id == @page.id | |
| 11 | - @profile | |
| 12 | - elsif @page.respond_to? :encapsulated_file | |
| 13 | - @page.encapsulated_file | |
| 14 | - else | |
| 15 | - @page | |
| 16 | - end | |
| 17 | - end, | |
| 18 | - }, | |
| 19 | - # fallback | |
| 20 | - profile: { | |
| 21 | - variable: :@profile, | |
| 22 | - }, | |
| 23 | - # last fallback | |
| 24 | - environment: { | |
| 25 | - variable: :@environment, | |
| 26 | - }, | |
| 27 | - } | |
| 28 | - | |
| 29 | -end |
| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | +module MetadataPlugin::Specs | |
| 2 | + | |
| 3 | + module ClassMethods | |
| 4 | + | |
| 5 | + def self.extended base | |
| 6 | + base.class_attribute :metadata_specs | |
| 7 | + base.metadata_specs ||= {} | |
| 8 | + end | |
| 9 | + | |
| 10 | + def metadata_spec spec = {} | |
| 11 | + namespace = spec[:namespace] | |
| 12 | + # setters are used to avoid propagation to super classes, see http://apidock.com/rails/Class/class_attribute | |
| 13 | + if _spec = self.metadata_specs[namespace] | |
| 14 | + self.metadata_specs = self.metadata_specs.deep_merge(namespace => _spec.deep_merge(spec)) | |
| 15 | + else | |
| 16 | + self.metadata_specs = self.metadata_specs.deep_merge(namespace => spec) | |
| 17 | + end | |
| 18 | + end | |
| 19 | + | |
| 20 | + end | |
| 21 | + | |
| 22 | +end | ... | ... |
plugins/metadata/locales/en.yml
plugins/metadata/locales/pt.yml
plugins/metadata/test/functional/content_viewer_controller_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,51 @@ |
| 1 | +require 'test_helper' | |
| 2 | +require 'content_viewer_controller' | |
| 3 | + | |
| 4 | +# Re-raise errors caught by the controller. | |
| 5 | +class ContentViewerController; def rescue_action(e) raise e end; end | |
| 6 | + | |
| 7 | +class ContentViewerControllerTest < ActionController::TestCase | |
| 8 | + | |
| 9 | + def setup | |
| 10 | + @controller = ContentViewerController.new | |
| 11 | + @request = ActionController::TestRequest.new | |
| 12 | + @response = ActionController::TestResponse.new | |
| 13 | + | |
| 14 | + @profile = create_user('testinguser').person | |
| 15 | + @environment = @profile.environment | |
| 16 | + @environment.enabled_plugins += ['MetadataPlugin'] | |
| 17 | + @environment.save! | |
| 18 | + end | |
| 19 | + | |
| 20 | + attr_reader :profile, :environment | |
| 21 | + | |
| 22 | + should 'produce meta tags for profile if on homepage' do | |
| 23 | + get :view_page, profile: profile.identifier, page: [] | |
| 24 | + assert_tag tag: 'meta', attributes: {property: 'og:title', content: profile.name} | |
| 25 | + end | |
| 26 | + | |
| 27 | + should 'add meta tags with article info' do | |
| 28 | + a = TinyMceArticle.create(name: 'Article to be shared', body: 'This article should be shared with all social networks', profile: profile) | |
| 29 | + | |
| 30 | + get :view_page, profile: profile.identifier, page: [ a.name.to_slug ] | |
| 31 | + | |
| 32 | + assert_tag tag: 'meta', attributes: { name: 'twitter:title', content: /#{a.name} - #{a.profile.name}/ } | |
| 33 | + assert_tag tag: 'meta', attributes: { name: 'twitter:description', content: a.body } | |
| 34 | + assert_no_tag tag: 'meta', attributes: { name: 'twitter:image' } | |
| 35 | + assert_tag tag: 'meta', attributes: { property: 'og:type', content: 'article' } | |
| 36 | + assert_tag tag: 'meta', attributes: { property: 'og:url', content: /\/#{profile.identifier}\/#{a.name.to_slug}/ } | |
| 37 | + assert_tag tag: 'meta', attributes: { property: 'og:title', content: /#{a.name} - #{a.profile.name}/ } | |
| 38 | + assert_tag tag: 'meta', attributes: { property: 'og:site_name', content: a.profile.name } | |
| 39 | + assert_tag tag: 'meta', attributes: { property: 'og:description', content: a.body } | |
| 40 | + assert_no_tag tag: 'meta', attributes: { property: 'og:image' } | |
| 41 | + end | |
| 42 | + | |
| 43 | + should 'add meta tags with article images' do | |
| 44 | + a = TinyMceArticle.create(name: 'Article to be shared with images', body: 'This article should be shared with all social networks <img src="/images/x.png" />', profile: profile) | |
| 45 | + | |
| 46 | + get :view_page, profile: profile.identifier, page: [ a.name.to_slug ] | |
| 47 | + assert_tag tag: 'meta', attributes: { name: 'twitter:image', content: /\/images\/x.png/ } | |
| 48 | + assert_tag tag: 'meta', attributes: { property: 'og:image', content: /\/images\/x.png/ } | |
| 49 | + end | |
| 50 | + | |
| 51 | +end | ... | ... |
plugins/metadata/test/functional/home_controller_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,33 @@ |
| 1 | +require 'test_helper' | |
| 2 | +require 'home_controller' | |
| 3 | + | |
| 4 | +# Re-raise errors caught by the controller. | |
| 5 | +class HomeController; def rescue_action(e) raise e end; end | |
| 6 | + | |
| 7 | +class HomeControllerTest < ActionController::TestCase | |
| 8 | + | |
| 9 | + def setup | |
| 10 | + @controller = HomeController.new | |
| 11 | + @request = ActionController::TestRequest.new | |
| 12 | + @response = ActionController::TestResponse.new | |
| 13 | + | |
| 14 | + Noosfero::Plugin.stubs(:all).returns([MetadataPlugin.name]) | |
| 15 | + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([MetadataPlugin.new]) | |
| 16 | + end | |
| 17 | + | |
| 18 | + should 'display meta tags for social media' do | |
| 19 | + get :index | |
| 20 | + assert_tag :tag => 'meta', :attributes => { :name => 'twitter:card', :content => 'summary' } | |
| 21 | + assert_tag :tag => 'meta', :attributes => { :name => 'twitter:title', :content => assigns(:environment).name } | |
| 22 | + assert_tag :tag => 'meta', :attributes => { :name => 'twitter:description', :content => assigns(:environment).name } | |
| 23 | + assert_no_tag :tag => 'meta', :attributes => { :name => 'twitter:image' } | |
| 24 | + assert_tag :tag => 'meta', :attributes => { :property => 'og:type', :content => 'website' } | |
| 25 | + assert_tag :tag => 'meta', :attributes => { :property => 'og:url', :content => assigns(:environment).top_url } | |
| 26 | + assert_tag :tag => 'meta', :attributes => { :property => 'og:title', :content => assigns(:environment).name } | |
| 27 | + assert_tag :tag => 'meta', :attributes => { :property => 'og:site_name', :content => assigns(:environment).name } | |
| 28 | + assert_tag :tag => 'meta', :attributes => { :property => 'og:description', :content => assigns(:environment).name } | |
| 29 | + assert_no_tag :tag => 'meta', :attributes => { :property => 'article:published_time' } | |
| 30 | + assert_no_tag :tag => 'meta', :attributes => { :property => 'og:image' } | |
| 31 | + end | |
| 32 | + | |
| 33 | +end | ... | ... |
test/functional/application_controller_test.rb
| ... | ... | @@ -498,21 +498,6 @@ class ApplicationControllerTest < ActionController::TestCase |
| 498 | 498 | |
| 499 | 499 | end |
| 500 | 500 | |
| 501 | - should 'display meta tags for social media' do | |
| 502 | - get :index | |
| 503 | - assert_tag :tag => 'meta', :attributes => { :name => 'twitter:card', :value => 'summary' } | |
| 504 | - assert_tag :tag => 'meta', :attributes => { :name => 'twitter:title', :content => assigns(:environment).name } | |
| 505 | - assert_tag :tag => 'meta', :attributes => { :name => 'twitter:description', :content => assigns(:environment).name } | |
| 506 | - assert_no_tag :tag => 'meta', :attributes => { :name => 'twitter:image' } | |
| 507 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:type', :content => 'website' } | |
| 508 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:url', :content => assigns(:environment).top_url } | |
| 509 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:title', :content => assigns(:environment).name } | |
| 510 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:site_name', :content => assigns(:environment).name } | |
| 511 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:description', :content => assigns(:environment).name } | |
| 512 | - assert_no_tag :tag => 'meta', :attributes => { :property => 'article:published_time' } | |
| 513 | - assert_no_tag :tag => 'meta', :attributes => { :property => 'og:image' } | |
| 514 | - end | |
| 515 | - | |
| 516 | 501 | should 'register search_term occurrence on find_by_contents' do |
| 517 | 502 | controller = ApplicationController.new |
| 518 | 503 | controller.stubs(:environment).returns(Environment.default) | ... | ... |
test/functional/content_viewer_controller_test.rb
| ... | ... | @@ -1405,30 +1405,6 @@ class ContentViewerControllerTest < ActionController::TestCase |
| 1405 | 1405 | end |
| 1406 | 1406 | end |
| 1407 | 1407 | |
| 1408 | - should 'add meta tags with article info' do | |
| 1409 | - a = TinyMceArticle.create(:name => 'Article to be shared', :body => 'This article should be shared with all social networks', :profile => profile) | |
| 1410 | - | |
| 1411 | - get :view_page, :profile => profile.identifier, :page => [ a.name.to_slug ] | |
| 1412 | - | |
| 1413 | - assert_tag :tag => 'meta', :attributes => { :name => 'twitter:title', :content => /#{a.name} - #{a.profile.name}/ } | |
| 1414 | - assert_tag :tag => 'meta', :attributes => { :name => 'twitter:description', :content => a.body } | |
| 1415 | - assert_no_tag :tag => 'meta', :attributes => { :name => 'twitter:image' } | |
| 1416 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:type', :content => 'article' } | |
| 1417 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:url', :content => /\/#{profile.identifier}\/#{a.name.to_slug}/ } | |
| 1418 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:title', :content => /#{a.name} - #{a.profile.name}/ } | |
| 1419 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:site_name', :content => a.profile.name } | |
| 1420 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:description', :content => a.body } | |
| 1421 | - assert_no_tag :tag => 'meta', :attributes => { :property => 'og:image' } | |
| 1422 | - end | |
| 1423 | - | |
| 1424 | - should 'add meta tags with article images' do | |
| 1425 | - a = TinyMceArticle.create(:name => 'Article to be shared with images', :body => 'This article should be shared with all social networks <img src="/images/x.png" />', :profile => profile) | |
| 1426 | - | |
| 1427 | - get :view_page, :profile => profile.identifier, :page => [ a.name.to_slug ] | |
| 1428 | - assert_tag :tag => 'meta', :attributes => { :name => 'twitter:image', :content => /\/images\/x.png/ } | |
| 1429 | - assert_tag :tag => 'meta', :attributes => { :property => 'og:image', :content => /\/images\/x.png/ } | |
| 1430 | - end | |
| 1431 | - | |
| 1432 | 1408 | should 'manage private article visualization' do |
| 1433 | 1409 | community = Community.create(:name => 'test-community') |
| 1434 | 1410 | community.add_member(@profile) | ... | ... |