Commit c770f8a428b74680b54f3c71d7b440e35307b901

Authored by Evandro Jr
2 parents 711552ab 7826abb9

Merge branch 'virtuoso_integration' of gitlab.com:participa/noosfero into virtuoso_integration

@@ -13,7 +13,7 @@ gem 'ruby-feedparser', '~> 0.7' @@ -13,7 +13,7 @@ gem 'ruby-feedparser', '~> 0.7'
13 gem 'daemons', '~> 1.1.5' 13 gem 'daemons', '~> 1.1.5'
14 gem 'thin', '~> 1.3.1' 14 gem 'thin', '~> 1.3.1'
15 gem 'hpricot', '~> 0.8.6' 15 gem 'hpricot', '~> 0.8.6'
16 -gem 'nokogiri', '~> 1.5.5' 16 +gem 'nokogiri', '~> 1.6.0'
17 gem 'rake', :require => false 17 gem 'rake', :require => false
18 gem 'rest-client', '~> 1.6.7' 18 gem 'rest-client', '~> 1.6.7'
19 gem 'exception_notification', '~> 4.0.1' 19 gem 'exception_notification', '~> 4.0.1'
plugins/virtuoso/Gemfile
@@ -2,3 +2,5 @@ gem 'rdf' @@ -2,3 +2,5 @@ gem 'rdf'
2 gem 'rdf-virtuoso' 2 gem 'rdf-virtuoso'
3 gem 'oai' 3 gem 'oai'
4 gem 'liquid' 4 gem 'liquid'
  5 +gem 'roadie'
  6 +gem 'roadie-rails'
plugins/virtuoso/db/migrate/20141113131439_create_custom_queries.rb
@@ -6,6 +6,7 @@ class CreateCustomQueries < ActiveRecord::Migration @@ -6,6 +6,7 @@ class CreateCustomQueries < ActiveRecord::Migration
6 t.string :name 6 t.string :name
7 t.text :query 7 t.text :query
8 t.text :template 8 t.text :template
  9 + t.text :stylesheet
9 t.boolean :enabled, :default => true 10 t.boolean :enabled, :default => true
10 t.timestamps 11 t.timestamps
11 end 12 end
plugins/virtuoso/features/edit_template.feature 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +Feature: edit template
  2 + As a noosfero user
  3 + I want to create and edit templates
  4 +
  5 + Background:
  6 + Given I am on the homepage
  7 + And plugin Virtuoso is enabled on environment
  8 + And the following users
  9 + | login | name |
  10 + | joaosilva | Joao Silva |
  11 + And I am logged in as "joaosilva"
  12 + And the following custom queries
  13 + | name | query | template |
  14 + | Default | query-1 | template-1 |
  15 +
  16 + @selenium
  17 + Scenario:
  18 + Given I am on joaosilva's control panel
  19 + And I follow "Manage Content"
  20 + And I should see "New content"
  21 + And I follow "New content"
  22 + And I should see "Triples template" within ".article-types"
  23 + When I follow "Triples template" within ".article-types"
  24 + And I follow "Copy" within ".custom-query"
  25 + Then the "SPARQL Query" field should contain "query-1"
plugins/virtuoso/features/step_definitions/virtuoso_plugin_steps.rb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +Given /^the following custom queries$/ do |table|
  2 + table.hashes.map{|item| item.dup}.each do |item|
  3 + VirtuosoPlugin::CustomQuery.create!(item.merge(:environment => Environment.default))
  4 + end
  5 +end
plugins/virtuoso/lib/ext/literal.rb
1 class RDF::Literal 1 class RDF::Literal
2 2
  3 + include ActionView::Helpers::SanitizeHelper
  4 +
3 def to_liquid 5 def to_liquid
4 - value 6 + strip_tags(value)
5 end 7 end
6 8
7 end 9 end
plugins/virtuoso/lib/virtuoso_plugin/custom_query.rb
@@ -2,7 +2,7 @@ class VirtuosoPlugin::CustomQuery < Noosfero::Plugin::ActiveRecord @@ -2,7 +2,7 @@ class VirtuosoPlugin::CustomQuery < Noosfero::Plugin::ActiveRecord
2 2
3 belongs_to :environment 3 belongs_to :environment
4 4
5 - attr_accessible :enabled, :environment, :query, :template, :name 5 + attr_accessible :enabled, :environment, :query, :template, :name, :stylesheet
6 6
7 validates_presence_of :name 7 validates_presence_of :name
8 8
plugins/virtuoso/lib/virtuoso_plugin/triples_management.rb
@@ -18,15 +18,21 @@ class VirtuosoPlugin::TriplesManagement @@ -18,15 +18,21 @@ class VirtuosoPlugin::TriplesManagement
18 def update_triple(graph_uri, from_triple, to_triple) 18 def update_triple(graph_uri, from_triple, to_triple)
19 from_subject = from_triple[:subject] 19 from_subject = from_triple[:subject]
20 from_predicate = from_triple[:predicate] 20 from_predicate = from_triple[:predicate]
21 - from_object = from_triple[:object] 21 + from_object = format_triple_term(from_triple[:object])
22 22
23 to_subject = to_triple[:subject] 23 to_subject = to_triple[:subject]
24 to_predicate = to_triple[:predicate] 24 to_predicate = to_triple[:predicate]
25 - to_object = to_triple[:object] 25 + to_object = format_triple_term(to_triple[:object])
26 26
27 - query = "WITH <#{graph_uri}> DELETE { <#{from_subject}> <#{from_predicate}> '#{from_object}' } INSERT { <#{to_subject}> <#{to_predicate}> '#{to_object}' }" 27 + query = "WITH <#{graph_uri}> DELETE { <#{from_subject}> <#{from_predicate}> #{from_object} } INSERT { <#{to_subject}> <#{to_predicate}> #{to_object} }"
28 28
29 plugin.virtuoso_client.query(query) 29 plugin.virtuoso_client.query(query)
30 end 30 end
31 31
  32 + protected
  33 +
  34 + def format_triple_term(term)
  35 + term =~ /^(http|https):\/\// ? "<#{term}>" : "'#{term}'"
  36 + end
  37 +
32 end 38 end
plugins/virtuoso/lib/virtuoso_plugin/triples_template.rb
@@ -8,10 +8,21 @@ class VirtuosoPlugin::TriplesTemplate &lt; Article @@ -8,10 +8,21 @@ class VirtuosoPlugin::TriplesTemplate &lt; Article
8 _('Triples template') 8 _('Triples template')
9 end 9 end
10 10
  11 + def self.initial_template
  12 + '
  13 + {% for row in results %}
  14 + <div>
  15 + {{row}}
  16 + </div>
  17 + {% endfor %}
  18 + '
  19 + end
  20 +
11 settings_items :query, :type => :string 21 settings_items :query, :type => :string
12 - settings_items :template, :type => :string 22 + settings_items :template, :type => :string, :default => initial_template
  23 + settings_items :stylesheet, :type => :string
13 24
14 - attr_accessible :query, :template 25 + attr_accessible :query, :template, :stylesheet
15 26
16 def to_html(options = {}) 27 def to_html(options = {})
17 article = self 28 article = self
@@ -27,12 +38,21 @@ class VirtuosoPlugin::TriplesTemplate &lt; Article @@ -27,12 +38,21 @@ class VirtuosoPlugin::TriplesTemplate &lt; Article
27 def template_content 38 def template_content
28 begin 39 begin
29 results = plugin.virtuoso_client.query(query) 40 results = plugin.virtuoso_client.query(query)
30 - liquid_template = Liquid::Template.parse("{% for row in results %}#{template}{% endfor %}")  
31 - liquid_template.render('results' => results) 41 + liquid_template = Liquid::Template.parse(template)
  42 + page = liquid_template.render('results' => results)
  43 + transform_html(page)
32 rescue => ex 44 rescue => ex
33 logger.info ex.to_s 45 logger.info ex.to_s
34 "Failed to process the template" 46 "Failed to process the template"
35 end 47 end
36 end 48 end
37 49
  50 + protected
  51 +
  52 + def transform_html(html)
  53 + document = Roadie::Document.new(html)
  54 + document.add_css(stylesheet) if stylesheet.present?
  55 + document.transform
  56 + end
  57 +
38 end 58 end
plugins/virtuoso/public/custom_query.js
@@ -2,6 +2,7 @@ jQuery(document).ready(function($) { @@ -2,6 +2,7 @@ jQuery(document).ready(function($) {
2 $('#copy_custom_query').on('click', function() { 2 $('#copy_custom_query').on('click', function() {
3 $.getJSON("/plugin/virtuoso/public/custom_query", {id: $('#select_custom_query').val()}, function(data) { 3 $.getJSON("/plugin/virtuoso/public/custom_query", {id: $('#select_custom_query').val()}, function(data) {
4 $('#article_query').val(data.custom_query.query); 4 $('#article_query').val(data.custom_query.query);
  5 + $('#article_stylesheet').val(data.custom_query.stylesheet);
5 tinymce.get('article_template').setContent(data.custom_query.template); 6 tinymce.get('article_template').setContent(data.custom_query.template);
6 }); 7 });
7 }); 8 });
plugins/virtuoso/test/functional/virtuoso_plugin_custom_queries_controller_test.rb
@@ -2,7 +2,7 @@ require &#39;test_helper&#39; @@ -2,7 +2,7 @@ require &#39;test_helper&#39;
2 2
3 class VirtuosoPluginCustomQueriesControllerTest < ActionController::TestCase 3 class VirtuosoPluginCustomQueriesControllerTest < ActionController::TestCase
4 setup do 4 setup do
5 - @custom_query = VirtuosoPlugin::CustomQuery.create!(:name => 'name', :query => 'query', :template => 'template', :environment => Environment.default) 5 + @custom_query = VirtuosoPlugin::CustomQuery.create!(:name => 'name', :query => 'query', :template => 'template', :stylesheet => 'stylesheet', :environment => Environment.default)
6 login_as(create_admin_user(Environment.default)) 6 login_as(create_admin_user(Environment.default))
7 end 7 end
8 8
@@ -19,7 +19,7 @@ class VirtuosoPluginCustomQueriesControllerTest &lt; ActionController::TestCase @@ -19,7 +19,7 @@ class VirtuosoPluginCustomQueriesControllerTest &lt; ActionController::TestCase
19 19
20 should "create custom_query" do 20 should "create custom_query" do
21 assert_difference('VirtuosoPlugin::CustomQuery.count') do 21 assert_difference('VirtuosoPlugin::CustomQuery.count') do
22 - post :create, custom_query: { name: @custom_query.name, enabled: @custom_query.enabled, query: @custom_query.query, template: @custom_query.template } 22 + post :create, custom_query: { name: @custom_query.name, enabled: @custom_query.enabled, query: @custom_query.query, template: @custom_query.template, stylesheet: @custom_query.stylesheet }
23 end 23 end
24 24
25 assert_redirected_to :action => :index 25 assert_redirected_to :action => :index
@@ -31,7 +31,7 @@ class VirtuosoPluginCustomQueriesControllerTest &lt; ActionController::TestCase @@ -31,7 +31,7 @@ class VirtuosoPluginCustomQueriesControllerTest &lt; ActionController::TestCase
31 end 31 end
32 32
33 should "update custom_query" do 33 should "update custom_query" do
34 - put :update, id: @custom_query, custom_query: { name: @custom_query.name, enabled: @custom_query.enabled, query: @custom_query.query, template: @custom_query.template } 34 + put :update, id: @custom_query, custom_query: { name: @custom_query.name, enabled: @custom_query.enabled, query: @custom_query.query, template: @custom_query.template, stylesheet: @custom_query.stylesheet }
35 assert_redirected_to :action => :index 35 assert_redirected_to :action => :index
36 end 36 end
37 37
plugins/virtuoso/test/unit/triples_template_test.rb
@@ -12,18 +12,39 @@ class TriplesTemplateTest &lt; ActiveSupport::TestCase @@ -12,18 +12,39 @@ class TriplesTemplateTest &lt; ActiveSupport::TestCase
12 article.stubs(:plugin).returns(mock) 12 article.stubs(:plugin).returns(mock)
13 article.plugin.expects(:virtuoso_client).at_least_once.returns(mock) 13 article.plugin.expects(:virtuoso_client).at_least_once.returns(mock)
14 article.plugin.virtuoso_client.expects(:query).returns([{'var' => 'Hello '}, {'var' => 'World'}]) 14 article.plugin.virtuoso_client.expects(:query).returns([{'var' => 'Hello '}, {'var' => 'World'}])
15 - article.template = "{{row.var}}" 15 + article.template = "{% for row in results %}{{row.var}}{% endfor %}"
16 16
17 - assert_equal 'Hello World', article.template_content 17 + assert_match /Hello World/, article.template_content
18 end 18 end
19 19
20 should 'display error message when failed to execute the query' do 20 should 'display error message when failed to execute the query' do
21 article.stubs(:plugin).returns(mock) 21 article.stubs(:plugin).returns(mock)
22 article.plugin.expects(:virtuoso_client).at_least_once.returns(mock) 22 article.plugin.expects(:virtuoso_client).at_least_once.returns(mock)
23 article.plugin.virtuoso_client.expects(:query).raises(RuntimeError.new) 23 article.plugin.virtuoso_client.expects(:query).raises(RuntimeError.new)
24 - article.template = "{{row.var}}" 24 + article.template = "{% for row in results %}{{row.var}}{% endfor %}"
25 25
26 assert_equal "Failed to process the template", article.template_content 26 assert_equal "Failed to process the template", article.template_content
27 end 27 end
28 28
  29 + should 'transform css into inline stylesheet' do
  30 + article.stubs(:plugin).returns(mock)
  31 + article.plugin.expects(:virtuoso_client).at_least_once.returns(mock)
  32 + article.plugin.virtuoso_client.expects(:query).returns([{'var' => 'Hello '}, {'var' => 'World'}])
  33 + article.template = "{% for row in results %}<p>{{row.var}}</p>{% endfor %}"
  34 + article.stylesheet = "p {color: red}"
  35 +
  36 + content = article.template_content
  37 + assert_match /<p style="color:red">Hello <\/p>/, content
  38 + assert_match /<p style="color:red">World<\/p>/, content
  39 + end
  40 +
  41 + should 'do not allow js injection' do
  42 + article.stubs(:plugin).returns(mock)
  43 + article.plugin.expects(:virtuoso_client).at_least_once.returns(mock)
  44 + article.plugin.virtuoso_client.expects(:query).returns([{'var' => RDF::Literal.new('<script>alert("hello");</script>')}])
  45 + article.template = "{% for row in results %}{{row.var}}{% endfor %}"
  46 +
  47 + assert_no_match /<script>/, article.template_content
  48 + end
  49 +
29 end 50 end
plugins/virtuoso/views/cms/virtuoso_plugin/_tinymce_template_editor.html.erb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<% extend TinymceHelper %>
  2 +
  3 +<%= tinymce_js %>
  4 +
  5 +<script>
  6 + function tinymce_macros_setup(editor) {}
  7 +
  8 + jQuery(document).ready(function($) {
  9 + <%= tinymce_init_js(:valid_children => "+body[style]", :convert_urls => false) %>
  10 + });
  11 +</script>
plugins/virtuoso/views/cms/virtuoso_plugin/_triples_template.html.erb
1 <div class="virtuoso-triples-template"> 1 <div class="virtuoso-triples-template">
2 <%= required_fields_message %> 2 <%= required_fields_message %>
3 3
4 - <%= render :file => 'shared/tiny_mce' %> 4 + <%= render :partial => 'cms/virtuoso_plugin/tinymce_template_editor' %>
5 5
6 <%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '64', :maxlength => 150)) %> 6 <%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '64', :maxlength => 150)) %>
7 7
@@ -20,6 +20,13 @@ @@ -20,6 +20,13 @@
20 </span> 20 </span>
21 </div> 21 </div>
22 22
  23 + <div class="stylesheet">
  24 + <span class="label"><%= _('Stylesheet') %></span>
  25 + <span>
  26 + <%= text_area(:article, :stylesheet, :style => 'width: 98%; height: 100px;') %>
  27 + </span>
  28 + </div>
  29 +
23 <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true} %> 30 <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true} %>
24 <%= render :partial => 'general_fields' %> 31 <%= render :partial => 'general_fields' %>
25 </div> 32 </div>
plugins/virtuoso/views/virtuoso_plugin_custom_queries/_form.html.erb
@@ -24,6 +24,10 @@ @@ -24,6 +24,10 @@
24 <%= f.text_area :template %> 24 <%= f.text_area :template %>
25 </div> 25 </div>
26 <div class="field"> 26 <div class="field">
  27 + <%= f.label :stylesheet %><br />
  28 + <%= f.text_area :stylesheet %>
  29 + </div>
  30 + <div class="field">
27 <%= f.label :enabled %><br /> 31 <%= f.label :enabled %><br />
28 <%= f.check_box :enabled %> 32 <%= f.check_box :enabled %>
29 </div> 33 </div>