diff --git a/plugins/virtuoso/Gemfile b/plugins/virtuoso/Gemfile new file mode 100644 index 0000000..6c259c5 --- /dev/null +++ b/plugins/virtuoso/Gemfile @@ -0,0 +1,3 @@ +gem 'rdf' +gem 'rdf-virtuoso' +gem 'oai' diff --git a/plugins/virtuoso/controllers/virtuoso_plugin_admin_controller.rb b/plugins/virtuoso/controllers/virtuoso_plugin_admin_controller.rb new file mode 100644 index 0000000..d5edf08 --- /dev/null +++ b/plugins/virtuoso/controllers/virtuoso_plugin_admin_controller.rb @@ -0,0 +1,23 @@ +class VirtuosoPluginAdminController < AdminController + + def index + settings = params[:settings] + settings ||= {} + @settings = Noosfero::Plugin::Settings.new(environment, VirtuosoPlugin, settings) + @harvest_running = VirtuosoPlugin::DspaceHarvest.new(environment).find_job.present? + + if request.post? + @settings.save! + session[:notice] = 'Settings succefully saved.' + redirect_to :action => 'index' + end + end + + def force_harvest + harvest = VirtuosoPlugin::DspaceHarvest.new(environment) + harvest.start + session[:notice] = _('Harvest started') + redirect_to :action => :index + end + +end diff --git a/plugins/virtuoso/lib/virtuoso_plugin.rb b/plugins/virtuoso/lib/virtuoso_plugin.rb new file mode 100644 index 0000000..f621956 --- /dev/null +++ b/plugins/virtuoso/lib/virtuoso_plugin.rb @@ -0,0 +1,11 @@ +class VirtuosoPlugin < Noosfero::Plugin + + def self.plugin_name + "Virtuoso integration" + end + + def self.plugin_description + _('Virtuoso integration') + end + +end diff --git a/plugins/virtuoso/lib/virtuoso_plugin/dspace_harvest.rb b/plugins/virtuoso/lib/virtuoso_plugin/dspace_harvest.rb new file mode 100644 index 0000000..28b8f1f --- /dev/null +++ b/plugins/virtuoso/lib/virtuoso_plugin/dspace_harvest.rb @@ -0,0 +1,71 @@ +#inspired by https://github.com/code4lib/ruby-oai/blob/master/lib/oai/harvester/harvest.rb +class VirtuosoPlugin::DspaceHarvest + + DC_CONVERSION = [:title, :creator, :subject, :description, :date, :type, :identifier, :language, :rights, :format] + + def initialize(environment) + @environment = environment + end + + def settings + @settings ||= Noosfero::Plugin::Settings.new(@environment, VirtuosoPlugin) + end + + def dspace_client + @dspace_client ||= OAI::Client.new("#{settings.dspace_uri}/oai/request") + end + + def virtuoso_client + @virtuoso_client ||= RDF::Virtuoso::Repository.new("#{settings.virtuoso_uri}/sparql", :update_uri => "#{settings.virtuoso_uri}/sparql-auth", :username => settings.virtuoso_username, :password => settings.virtuoso_password, :auth_method => 'digest', :timeout => 30) + end + + def triplify(record) + metadata = VirtuosoPlugin::DublinCoreMetadata.new(record.metadata) + puts "triplify #{record.header.identifier}" + + DC_CONVERSION.each do |c| + values = [metadata.send(c)].flatten.compact + values.each do |value| + query = RDF::Virtuoso::Query.insert_data([RDF::URI.new(metadata.identifier), RDF::URI.new("http://purl.org/dc/elements/1.1/#{c}"), value]).graph(RDF::URI.new(settings.dspace_uri)) + virtuoso_client.insert(query) + end + end + end + + def run + harvest_time = Time.now.utc + params = settings.last_harvest ? {:from => settings.last_harvest.utc} : {} + puts "starting harvest #{params}" + begin + records = dspace_client.list_records(params) + records.each do |record| + triplify(record) + end + rescue Exception => ex + puts ex.to_s + end + settings.last_harvest = harvest_time + settings.save! + puts "ending harvest #{harvest_time}" + end + + def start + if find_job.empty? + job = VirtuosoPlugin::DspaceHarvest::Job.new(@environment.id) + Delayed::Job.enqueue(job) + end + end + + def find_job + Delayed::Job.where(:handler => "--- !ruby/struct:VirtuosoPlugin::DspaceHarvest::Job\nenvironment_id: #{@environment.id}\n") + end + + class Job < Struct.new(:environment_id) + def perform + environment = Environment.find(environment_id) + harvest = VirtuosoPlugin::DspaceHarvest.new(environment) + harvest.run + end + end + +end diff --git a/plugins/virtuoso/lib/virtuoso_plugin/dublin_core_metadata.rb b/plugins/virtuoso/lib/virtuoso_plugin/dublin_core_metadata.rb new file mode 100644 index 0000000..408a33f --- /dev/null +++ b/plugins/virtuoso/lib/virtuoso_plugin/dublin_core_metadata.rb @@ -0,0 +1,20 @@ +class VirtuosoPlugin::DublinCoreMetadata + + include OAI::XPath + + attr_accessor :date, :title, :creator, :subject, :description, :date, :type, :identifier, :language, :rights, :format + + def initialize(element) + @title = xpath(element, './/dc:title') + @creator = xpath(element, './/dc:creator') + @subject = xpath_all(element, './/dc:subject').map(&:text) + @description = xpath(element, './/dc:description') + @date = xpath_all(element, './/dc:date').map(&:text) + @type = xpath(element, './/dc:type') + @identifier = xpath(element, './/dc:identifier') + @language = xpath(element, './/dc:language') + @rights = xpath_all(element, './/dc:rights').map(&:text) + @format = xpath(element, './/dc:format') + end + +end diff --git a/plugins/virtuoso/test/functional/virtuoso_plugin_admin_controller_test.rb b/plugins/virtuoso/test/functional/virtuoso_plugin_admin_controller_test.rb new file mode 100644 index 0000000..e86a04d --- /dev/null +++ b/plugins/virtuoso/test/functional/virtuoso_plugin_admin_controller_test.rb @@ -0,0 +1,38 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class VirtuosoPluginAdminControllerTest < ActionController::TestCase + + def setup + @environment = Environment.default + @profile = create_user('profile').person + login_as(@profile.identifier) + end + + attr_reader :environment + + should 'save virtuoso plugin settings' do + post :index, :settings => {'virtuoso_uri' => 'http://virtuoso.noosfero.com', + 'virtuoso_username' => 'username', + 'virtuoso_password' => 'password', + 'dspace_uri' => 'http://dspace.noosfero.com'} + @settings = Noosfero::Plugin::Settings.new(environment.reload, VirtuosoPlugin) + assert_equal 'http://virtuoso.noosfero.com', @settings.settings[:virtuoso_uri] + assert_equal 'username', @settings.settings[:virtuoso_username] + assert_equal 'password', @settings.settings[:virtuoso_password] + assert_equal 'http://dspace.noosfero.com', @settings.settings[:dspace_uri] + assert_redirected_to :action => 'index' + end + + should 'redirect to index after save' do + post :index, :settings => {"virtuoso_uri" => 'http://virtuoso.noosfero.com'} + assert_redirected_to :action => 'index' + end + + should 'create delayed job to start harvest on force action' do + harvest = VirtuosoPlugin::DspaceHarvest.new(environment) + assert !harvest.find_job.present? + get :force_harvest + assert harvest.find_job.present? + end + +end diff --git a/plugins/virtuoso/test/test_helper.rb b/plugins/virtuoso/test/test_helper.rb new file mode 100644 index 0000000..cca1fd3 --- /dev/null +++ b/plugins/virtuoso/test/test_helper.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../test/test_helper' diff --git a/plugins/virtuoso/test/unit/dspace_harvest_test.rb b/plugins/virtuoso/test/unit/dspace_harvest_test.rb new file mode 100644 index 0000000..85e7160 --- /dev/null +++ b/plugins/virtuoso/test/unit/dspace_harvest_test.rb @@ -0,0 +1,25 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class DspaceHarvestTest < ActiveSupport::TestCase + + def setup + @environment = Environment.default + end + + attr_reader :environment + + should 'create delayed job when start' do + harvest = VirtuosoPlugin::DspaceHarvest.new(environment) + assert !harvest.find_job.present? + harvest.start + assert harvest.find_job.present? + end + + should 'not duplicate harvest job' do + harvest = VirtuosoPlugin::DspaceHarvest.new(environment) + assert_difference "harvest.find_job.count", 1 do + 5.times { harvest.start } + end + end + +end diff --git a/plugins/virtuoso/views/virtuoso_plugin_admin/index.html.erb b/plugins/virtuoso/views/virtuoso_plugin_admin/index.html.erb new file mode 100644 index 0000000..ddc86e9 --- /dev/null +++ b/plugins/virtuoso/views/virtuoso_plugin_admin/index.html.erb @@ -0,0 +1,34 @@ +