Commit 8a1be65dea5b6df9a8122f498e2a82cb8ef9ff38

Authored by Braulio Bhavamitra
1 parent ee532d16

metadata: Support key attr specification (fix tests)

app/helpers/layout_helper.rb
... ... @@ -116,8 +116,5 @@ module LayoutHelper
116 116 end
117 117 end
118 118  
119   - def meta_description_tag(article=nil)
120   - article ? CGI.escapeHTML(truncate(strip_tags(article.body.to_s), :length => 200)) : environment.name
121   - end
122 119 end
123 120  
... ...
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/lib/ext/article.rb
... ... @@ -2,31 +2,42 @@ require_dependency &#39;article&#39;
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.environment.default_language },
  19 + 'locale:alternate' => proc{ |a, c| a.environment.languages - [a.environment.default_language] },
  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 &quot;#{File.dirname __FILE__}/profile&quot;
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 &quot;#{File.dirname __FILE__}/profile&quot;
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,12 @@ require_dependency &#39;environment&#39;
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 + site_name: proc{ |e, plugin| e.name },
  7 + description: proc{ |e, plugin| e.name },
  8 + url: proc{ |e, plugin| e.top_url },
  9 + 'locale:locale' => proc{ |e, plugin| e.default_language },
  10 + 'locale:alternate' => proc{ |e, plugin| e.languages - [e.default_language] },
11 11 }
12 12  
13 13 end
... ...
plugins/metadata/lib/ext/person.rb
... ... @@ -3,8 +3,8 @@ require_dependency &quot;#{File.dirname __FILE__}/profile&quot;
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 &#39;product&#39;
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,26 @@ require_dependency &#39;profile&#39;
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 },
22 25 }
23 26  
24 27 end
... ...
plugins/metadata/lib/ext/uploaded_file.rb
... ... @@ -3,15 +3,15 @@ require_dependency &quot;#{File.dirname __FILE__}/article&quot;
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
... ... @@ -17,30 +17,64 @@ class MetadataPlugin &lt; 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 53 when Proc then instance_exec(&variable) rescue nil
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) rescue nil if values.is_a? Proc
  68 + next if values.blank?
  69 +
  70 + Array(values).each do |value|
  71 + value = value.call(object, plugin) rescue nil 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 &lt; 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
plugins/metadata/lib/metadata_plugin/specs.rb 0 → 100644
... ... @@ -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/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
... ...
test/functional/content_viewer_controller_test.rb
... ... @@ -1405,30 +1405,6 @@ class ContentViewerControllerTest &lt; 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)
... ...