From 14c645378af9b265cff7bf45f581da22fcf80ba5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Sep 2018 18:22:19 +0000 Subject: [PATCH] Bug 21359: Add RDF support to OAI-PMH harvester This patch allows the OAI-PMH harvester to process RDFXML and place it in an external triplestore. Currently, these RDFXML records must be linked to MARCXML records via a matching OAI-PMH repository and OAI-PMH identifier combination. --- C4/Installer/PerlDependencies.pm | 15 +- Koha/OAI/Harvester/Import/RDFXML.pm | 162 +++++++++++++++++++++ Koha/OAI/Harvester/Import/Record.pm | 126 +++++++++++++++- Koha/OAI/Harvester/Request.pm | 19 +++ Koha/OAI/Harvester/Worker/Download/Stream.pm | 2 + Koha/OAI/Harvester/Worker/Import.pm | 2 + Koha/Schema/Result/OaiHarvesterRequest.pm | 12 +- debian/scripts/koha-create | 8 +- installer/data/mysql/atomicupdate/bug_21359.sql | 6 + installer/data/mysql/kohastructure.sql | 1 + .../modules/tools/oai-pmh-harvester/dashboard.tt | 3 + .../en/modules/tools/oai-pmh-harvester/request.tt | 6 + t/db_dependent/OAI/Harvester/Importer/rdf.t | 53 +++++++ tools/oai-pmh-harvester/dashboard.pl | 1 + tools/oai-pmh-harvester/request.pl | 2 + 15 files changed, 399 insertions(+), 19 deletions(-) create mode 100644 Koha/OAI/Harvester/Import/RDFXML.pm create mode 100644 installer/data/mysql/atomicupdate/bug_21359.sql create mode 100755 t/db_dependent/OAI/Harvester/Importer/rdf.t diff --git a/C4/Installer/PerlDependencies.pm b/C4/Installer/PerlDependencies.pm index b19f3d1..14e4c20 100644 --- a/C4/Installer/PerlDependencies.pm +++ b/C4/Installer/PerlDependencies.pm @@ -893,6 +893,16 @@ our $PERL_DEPS = { required => '1', min_ver => '0.37', }, + 'RDF::Trine' => { + 'usage' => 'Managing RDF and triplestores', + 'required' => '1', + 'min_ver' => '1.017', + }, + 'RDF::Query' => { + 'usage' => 'Managing RDF and triplestores', + 'required' => '1', + 'min_ver' => '2.912', + }, 'POE' => { 'usage' => 'OAI-PMH harvester', 'required' => 1, @@ -903,11 +913,6 @@ our $PERL_DEPS = { 'required' => 1, 'min_ver' => '0.570', }, - 'RDF::Trine' => { - 'usage' => 'Managing RDF and triplestores', - 'required' => '1', - 'min_ver' => '1.017', - }, }; 1; diff --git a/Koha/OAI/Harvester/Import/RDFXML.pm b/Koha/OAI/Harvester/Import/RDFXML.pm new file mode 100644 index 0000000..712fa2a --- /dev/null +++ b/Koha/OAI/Harvester/Import/RDFXML.pm @@ -0,0 +1,162 @@ +package Koha::OAI::Harvester::Import::RDFXML; + +# Copyright 2017 Prosentient Systems +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . +# + +use Modern::Perl; +use Encode; +use RDF::Trine; +use RDF::Query; + +use C4::Context; +use Koha::RDF; + +sub new { + my ($class, $args) = @_; + $args = {} unless defined $args; + return bless ($args, $class); +} + +sub _parse_rdf_into_model { + my ($self, $args) = @_; + + #Create a RDFXML parser + my $parser = RDF::Trine::Parser->new('rdfxml'); + + #Create a model in memory into which we can parse the incoming triples for processing + my $store = RDF::Trine::Store::Memory->new(); + my $model = RDF::Trine::Model->new($store); + + my $dom = $self->{dom}; + + my $byte_string = $dom->toString(2); + + #Change a byte string to a character string + my $character_string = Encode::decode('UTF-8', $byte_string, Encode::FB_CROAK); + #NOTE: RDF::Trine::Parser::RDFXML expects characters and converts them to bytes, so + #we have to change to characters before parsing. + + #FIXME: Should you provide a base uri? Unfortunately, there's no way to do this reliably over OAI-PMH. + my $base_uri = undef; + + #NOTE: UTF-8 encoding problems have been found when using XML::SAX::PurePerl. Make sure + #that you're using a parser like XML::LibXML::SAX::Parser instead. You can verify using + #sax_parser_print.pl. + $parser->parse_into_model($base_uri, $character_string, $model); + + return $model; +} + +sub _get_primary_subject { + my ($self,$args) = @_; + + my $primary_subject; + my $model = $args->{model}; + my $type = $args->{type}; + + my $object = RDF::Trine::Node::Resource->new($type); + my $object_string = $object ? $object->as_string : '?object'; + + #NOTE: Select only a subject with a particular rdf:type, and filter out + #any matches which are also objects in the same model. This is essential + #for weeding out triples that share the same rdf:type value but are linked + #objects rather than the primary subject. + my $sparql = qq~ + SELECT DISTINCT ?subject + WHERE { + ?subject $object_string . + FILTER NOT EXISTS { ?os ?op ?subject } + } + ~; + my $query = RDF::Query->new($sparql); + my $iterator = $query->execute($model); + if ($iterator){ + my @all = $iterator->get_all; + if (scalar @all == 1 ){ + my $primary = shift @all; + $primary_subject = $primary->{subject}; + } + } + return $primary_subject; +} + +sub import_record { + my ($self,$args) = @_; + my $record_type = $args->{record_type}; + my $koha_id = $args->{koha_id}; + my $rdf_type = $args->{rdf_type}; + my $oai_pmh_repository = $args->{oai_pmh_repository}; + my $oai_pmh_identifier = $args->{oai_pmh_identifier}; + + my $action = "error"; + + #Create a model for our Koha triplestore backend + my $real_model = undef; + my $context = C4::Context->new(); + if ( $context && $context->triplestore('update') ){ + $real_model = $context->triplestore('update'); + } + my $memory_model = $self->_parse_rdf_into_model(); + my $iterator = $memory_model->as_stream; + if ($iterator){ + if ($memory_model && $rdf_type){ + my $incoming_subject = $self->_get_primary_subject({ + model => $memory_model, + type => $rdf_type, + }); + + if ($incoming_subject && $incoming_subject->is_resource){ + my $rdf = Koha::RDF->new(); + if ($rdf){ + $real_model->begin_bulk_ops; + + $rdf->DelNamedGraph({ + model => $real_model, + context => $incoming_subject, + }); + $rdf->AddNamedGraph({ + model => $real_model, + context => $incoming_subject, + iterator => $iterator, + }); + + #NOTE: Insert your own triples containing references to the OAI-PMH repository and the OAI-PMH identifier + if ($oai_pmh_repository){ + my $repository_predicate = RDF::Trine::Node::Resource->new('http://koha-community.org/vocab/oai-pmh/repository'); + my $repository_object = RDF::Trine::Node::Resource->new($oai_pmh_repository); + my $repository_quad = RDF::Trine::Statement::Quad->new($incoming_subject, $repository_predicate, $repository_object, $incoming_subject); + $real_model->add_statement($repository_quad); + } + if ($oai_pmh_identifier){ + my $identifier_predicate = RDF::Trine::Node::Resource->new('http://koha-community.org/vocab/oai-pmh/identifier'); + my $identifier_object = RDF::Trine::Node::Resource->new($oai_pmh_identifier); + my $identifier_quad = RDF::Trine::Statement::Quad->new($incoming_subject, $identifier_predicate, $identifier_object, $incoming_subject); + $real_model->add_statement($identifier_quad); + } + + $real_model->end_bulk_ops; + + $action = 'unknown'; #FIXME: RDF::Trine doesn't return meaningful values so we can't really say much else... + } + } + } + } + return ($action,$koha_id); +} + +1; diff --git a/Koha/OAI/Harvester/Import/Record.pm b/Koha/OAI/Harvester/Import/Record.pm index 9a67eb8..f0ad3d5 100755 --- a/Koha/OAI/Harvester/Import/Record.pm +++ b/Koha/OAI/Harvester/Import/Record.pm @@ -23,12 +23,15 @@ use XML::LibXML; use XML::LibXSLT; use URI; use File::Basename; +use RDF::Query; use C4::Context; use C4::Biblio; use Koha::Database; use Koha::OAI::Harvester::Import::MARCXML; +use Koha::OAI::Harvester::Import::RDFXML; +use Koha::RDF; =head1 API @@ -149,6 +152,11 @@ sub filter { } else { return $marcxml; } + } elsif ($namespace eq "http://www.w3.org/1999/02/22-rdf-syntax-ns#"){ + my $rdfxml = Koha::OAI::Harvester::Import::RDFXML->new({ dom => $results, }); + if ($rdfxml){ + return $rdfxml; + } } } } @@ -179,6 +187,42 @@ sub _find_koha_link { return $link_id; } + +sub _find_rdf_link { + my ($self, $args) = @_; + my ($subject,$graph); + my $repository = $self->{repository}; + my $identifier = $self->{header_identifier}; + + my $context = C4::Context->new; + my $triplestore = $context->triplestore('query'); + if ($triplestore){ + if ( URI->new($repository) && URI->new($identifier) ){ + my $sparql = qq~ + PREFIX koha-oai: + SELECT ?g ?s ?identifier ?repository + WHERE { + GRAPH ?g { + ?s koha-oai:identifier ?identifier . + ?s koha-oai:repository ?repository . + ?s koha-oai:identifier <$identifier> . + ?s koha-oai:repository <$repository> . + } + } + ~; + my $query = RDF::Query->new($sparql); + my $iterator = $query->execute($triplestore); + my @rows = $iterator->get_all; + if (scalar @rows == 1){ + my $row = $rows[0]; + $subject = $row->{s}; + $graph = $row->{g}; + } + } + } + return ($subject,$graph); +} + =head3 import_record my ($action,$record_id) = $oai_record->import_record({ @@ -198,16 +242,49 @@ sub import_record { my $framework = $args->{framework} || ''; my $record_type = $args->{record_type} || 'biblio'; my $matcher = $args->{matcher}; + my $rdf_type = $args->{rdf_type}; #NOTE: RDF my $action = "error"; + #NOTE: RDF #Find linkage between OAI-PMH repository-identifier and Koha record id my $linked_id = $self->_find_koha_link({ record_type => $record_type, }); + #NOTE: RDF + #Find linkage between OAI-PMH repository-identifier and RDF records in the triplestore + my ($linked_subject, $linked_graph); + my $context = C4::Context->new(); + if ( $context && $context->triplestore('query') ){ + ($linked_subject, $linked_graph) = $self->_find_rdf_link; + } + if ($self->is_deleted_upstream){ - #NOTE: If a record is deleted upstream, it will not contain a metadata element + #FIXME: If a record is deleted upstream, it will not contain a metadata element, so we don't know what metadata + #format we requested. Perhaps we should be recording the metadataPrefix during download and import, so we + #can have more targeted deletes. + #NOTE: "Other records, with different metadataPrefix but the same unique identifier, may remain available for the item." + #https://www.openarchives.org/OAI/openarchivesprotocol.html#DeletedRecords + + if ($linked_graph){ + my $model; + if ( $context && $context->triplestore('update') ){ + $model = $context->triplestore('update'); + } + my $rdf = Koha::RDF->new(); + if ($rdf){ + $model->begin_bulk_ops; + $rdf->DelNamedGraph({ + model => $model, + context => $linked_graph, + }); + $model->end_bulk_ops; + } + #NOTE: We don't set action here, since RDF::Trine doesn't return a useful value, plus + #the RDF is meaningless without the Koha record mentioned below anyway. + } + if ($linked_id){ $action = $self->delete_koha_record({ record_id => $linked_id, @@ -219,6 +296,9 @@ sub import_record { #NOTE: If there's no OAI-PMH repository-identifier pair in the database, #then there's no perfect way to find a linked record to delete. } + #NOTE: RDF + #TODO: Delete named graph found via $linked_graph... + #TODO: Do we also unlink the Koha record from this OAI record? I suppose so... } else { $self->set_filter($filter); @@ -227,21 +307,51 @@ sub import_record { my $import_record = $self->filter(); if ($import_record){ + #NOTE: You can inspect the object's class here for special type handling if necessary... ($action,$linked_id) = $import_record->import_record({ + oai_pmh_repository => $self->{repository}, + oai_pmh_identifier => $self->{header_identifier}, framework => $framework, record_type => $record_type, matcher => $matcher, koha_id => $linked_id, + linked_subject => $linked_subject, #NOTE: RDF + rdf_type => $rdf_type, #NOTE: RDF }); - if ($linked_id){ - #Link Koha record ID to OAI-PMH details for this record type, - #if linkage doesn't already exist. - $self->link_koha_record({ - record_type => $record_type, - koha_id => $linked_id, - }); + #FIXME: This is too hard-coded... + if ($import_record->isa('Koha::OAI::Harvester::Import::MARCXML')){ + if ($linked_id){ + #Link Koha record ID to OAI-PMH details for this record type, + #if linkage doesn't already exist. + $self->link_koha_record({ + record_type => $record_type, + koha_id => $linked_id, + }); + } + } + + #NOTE: Link Koha RDF to Imported RDF + if ( ($record_type && $linked_id) && ($linked_subject) ){ + my $rdf = Koha::RDF->new(); + my $triplestore; + my $context = C4::Context->new(); + if ( $context && $context->triplestore('update') ){ + $triplestore = $context->triplestore('update'); + } + if ( $triplestore && $rdf ){ + my $koha_uri = $rdf->mint_uri($record_type, $linked_id); + my $koha_subject = RDF::Trine::Node::Resource->new($koha_uri); + $rdf->AddSeeAlso({ + model => $triplestore, + subject => $koha_subject, + object => $linked_subject, + }); + } } + #NOTE: A link will only be successful when both a MARCXML record and a RDFXML record sharing the + #same OAI-PMH repository and OAI-PMH identifier are in Koha. + #NOTE: This action is idempotent. } } diff --git a/Koha/OAI/Harvester/Request.pm b/Koha/OAI/Harvester/Request.pm index 3824947..35e930a 100644 --- a/Koha/OAI/Harvester/Request.pm +++ b/Koha/OAI/Harvester/Request.pm @@ -140,9 +140,28 @@ sub validate { } else { $errors->{http_url}->{malformed} = 1; } + + #NOTE: RDF + $self->_validate_import_rdf_type({ + errors => $errors, + }); + return $errors; } +#NOTE: RDF +sub _validate_import_rdf_type { + my ($self,$args) = @_; + my $errors = $args->{errors}; + my $type = $self->import_rdf_type; + if ($type){ + my $uri = URI->new($type); + if ( ! $uri->scheme ){ + $errors->{import_rdf_type}->{malformed} = 1; + } + } +} + sub _harvester { my ( $self ) = @_; my $harvester; diff --git a/Koha/OAI/Harvester/Worker/Download/Stream.pm b/Koha/OAI/Harvester/Worker/Download/Stream.pm index c87580a..32276fd 100644 --- a/Koha/OAI/Harvester/Worker/Download/Stream.pm +++ b/Koha/OAI/Harvester/Worker/Download/Stream.pm @@ -152,6 +152,7 @@ sub do_work { matcher_code => $import_parameters->{matcher_code}, frameworkcode => $import_parameters->{frameworkcode}, record_type => $import_parameters->{record_type}, + rdf_type => $import_parameters->{rdf_type}, }; eval { my $json_result = to_json($result, { pretty => 1 }); @@ -171,6 +172,7 @@ sub do_work { matcher_code => $import_parameters->{matcher_code}, frameworkcode => $import_parameters->{frameworkcode}, record_type => $import_parameters->{record_type}, + rdf_type => $import_parameters->{rdf_type}, }; eval { my $json_result = to_json($result, { pretty => 1 }); diff --git a/Koha/OAI/Harvester/Worker/Import.pm b/Koha/OAI/Harvester/Worker/Import.pm index ec86736..80ebdf0 100644 --- a/Koha/OAI/Harvester/Worker/Import.pm +++ b/Koha/OAI/Harvester/Worker/Import.pm @@ -63,6 +63,7 @@ sub on_start { my $matcher_code = $result->{matcher_code}; my $frameworkcode = $result->{frameworkcode}; my $record_type = $result->{record_type}; + my $rdf_type = $result->{rdf_type}; #NOTE: RDF my $matcher; if ($matcher_code){ @@ -85,6 +86,7 @@ sub on_start { framework => $frameworkcode, record_type => $record_type, matcher => $matcher, + rdf_type => $rdf_type, #NOTE: RDF }); $debug && print STDOUT qq({ "import_result": { "task_uuid": "$task_uuid", "action": "$action", "filename": "$filename", "koha_id": "$linked_id" } }\n); } diff --git a/Koha/Schema/Result/OaiHarvesterRequest.pm b/Koha/Schema/Result/OaiHarvesterRequest.pm index e322281..e074027 100644 --- a/Koha/Schema/Result/OaiHarvesterRequest.pm +++ b/Koha/Schema/Result/OaiHarvesterRequest.pm @@ -133,6 +133,12 @@ __PACKAGE__->table("oai_harvester_requests"); is_nullable: 0 size: 45 +=head2 import_rdf_type + + data_type: 'varchar' + is_nullable: 1 + size: 255 + =cut __PACKAGE__->add_columns( @@ -186,6 +192,8 @@ __PACKAGE__->add_columns( { data_type => "integer", extra => { unsigned => 1 }, is_nullable => 0 }, "name", { data_type => "varchar", is_nullable => 0, size => 45 }, + "import_rdf_type", + { data_type => "varchar", is_nullable => 1, size => 255 }, ); =head1 PRIMARY KEY @@ -201,8 +209,8 @@ __PACKAGE__->add_columns( __PACKAGE__->set_primary_key("id"); -# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-04-07 11:26:24 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Vm/b4yurmr8WF7z+Fo6KEw +# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-05-30 16:44:41 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:LiH5KlQNzkZtjWujcT3DIw # You can replace this text with custom code or comments, and it will be preserved on regeneration diff --git a/debian/scripts/koha-create b/debian/scripts/koha-create index b6e2da3..503959a 100755 --- a/debian/scripts/koha-create +++ b/debian/scripts/koha-create @@ -655,14 +655,14 @@ eof generate_config_file zebra.passwd.in \ "/etc/koha/sites/$name/zebra.passwd" - # Generate and install OAI-PMH harvester config file - generate_config_file oai-pmh-harvester.yaml.in \ - "/etc/koha/sites/$name/oai-pmh-harvester.yaml" - # Generate and install triplestore config file generate_config_file triplestore.yaml.in \ "/etc/koha/sites/$name/triplestore.yaml" + # Generate and install OAI-PMH harvester config file + generate_config_file oai-pmh-harvester.yaml.in \ + "/etc/koha/sites/$name/oai-pmh-harvester.yaml" + # Create a GPG-encrypted file for requesting a DB to be set up. if [ "$op" = request ] then diff --git a/installer/data/mysql/atomicupdate/bug_21359.sql b/installer/data/mysql/atomicupdate/bug_21359.sql new file mode 100644 index 0000000..ae9067d --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_21359.sql @@ -0,0 +1,6 @@ +-- +-- Update table structure for table 'oai_harvester_requests' +-- + +ALTER TABLE oai_harvester_requests ADD COLUMN import_rdf_type varchar(255) DEFAULT NULL AFTER `name`; + diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 1e74154..ca378fb 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -4263,6 +4263,7 @@ CREATE TABLE IF NOT EXISTS `oai_harvester_requests` ( `import_matcher_code` varchar(10) DEFAULT NULL, `interval` int(10) unsigned NOT NULL, `name` varchar(45) NOT NULL, + `import_rdf_type` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/oai-pmh-harvester/dashboard.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/oai-pmh-harvester/dashboard.tt index 36fdccf..525a3b5 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/oai-pmh-harvester/dashboard.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/oai-pmh-harvester/dashboard.tt @@ -62,6 +62,9 @@ else if (data == "updated"){ display_string = _("Updated"); } + else if (data == "unknown"){ + display_string = _("Unknown"); + } return display_string; } }, diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/oai-pmh-harvester/request.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/oai-pmh-harvester/request.tt index ca2d98d..33a90e7 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/oai-pmh-harvester/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/oai-pmh-harvester/request.tt @@ -214,6 +214,12 @@ See record matching rules to add or edit rules. +
  • + + + If you're importing RDF, you need to specify a type for the primary entity or your import will fail. + [% IF (errors.import_rdf_type.malformed) %][This must be a properly formatted URI.][% END %] +
  • diff --git a/t/db_dependent/OAI/Harvester/Importer/rdf.t b/t/db_dependent/OAI/Harvester/Importer/rdf.t new file mode 100755 index 0000000..6058ab6 --- /dev/null +++ b/t/db_dependent/OAI/Harvester/Importer/rdf.t @@ -0,0 +1,53 @@ +#!/usr/bin/perl + +# Copyright 2017 Prosentient Systems +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . +# + +use Modern::Perl; +use Test::More tests => 2; + +use_ok("Koha::OAI::Harvester::Import::RDFXML"); + +subtest 'find primary entity' => sub { + + my $store = RDF::Trine::Store::Memory->new(); + my $model = RDF::Trine::Model->new($store); + + my $subject = RDF::Trine::Node::Resource->new("http://koha-community/resource/1"); + my $predicate = RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); + my $object = RDF::Trine::Node::Resource->new("http://koha-community/vocab/type/record"); + my $triple = RDF::Trine::Statement->new($subject,$predicate,$object); + $model->add_statement($triple); + my $other_predicate = RDF::Trine::Node::Resource->new("http://koha-community/vocab/hasAuthor"); + my $other_object = RDF::Trine::Node::Resource->new("http://koha-community/author/david-cook"); + my $other_triple = RDF::Trine::Statement->new($subject,$other_predicate,$other_object); + $model->add_statement($other_triple); + + my $resource2_subject = RDF::Trine::Node::Resource->new("http://koha-community/resource/2"); + my $resource2_predicate = RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); + my $resource2_object = RDF::Trine::Node::Resource->new("http://koha-community/vocab/type/awesome"); + my $resource2_triple = RDF::Trine::Statement->new($resource2_subject, $resource2_predicate, $resource2_object); + $model->add_statement($resource2_triple); + + my $importer = Koha::OAI::Harvester::Import::RDFXML->new(); + my $primary_subject = $importer->_get_primary_subject({ + model => $model, + type => 'http://koha-community/vocab/type/record', + }); + is($primary_subject && $primary_subject->as_string, "","Correctly found primary entity"); +}; diff --git a/tools/oai-pmh-harvester/dashboard.pl b/tools/oai-pmh-harvester/dashboard.pl index 16dd15f..c747ba3 100755 --- a/tools/oai-pmh-harvester/dashboard.pl +++ b/tools/oai-pmh-harvester/dashboard.pl @@ -78,6 +78,7 @@ if ( ($op eq "send") && $id ){ frameworkcode => $request->import_framework_code, matcher_code => $request->import_matcher_code, record_type => $request->import_record_type, + rdf_type => $request->import_rdf_type, #NOTE: RDF }, }, }; diff --git a/tools/oai-pmh-harvester/request.pl b/tools/oai-pmh-harvester/request.pl index 4d80b1a..db0356f 100755 --- a/tools/oai-pmh-harvester/request.pl +++ b/tools/oai-pmh-harvester/request.pl @@ -63,6 +63,7 @@ my $import_filter = $input->param('import_filter') // 'default'; my $import_framework_code = $input->param('import_framework_code'); my $import_record_type = $input->param('import_record_type'); my $import_matcher_code = $input->param('import_matcher_code'); +my $import_rdf_type = $input->param('import_rdf_type'); #NOTE: RDF my $interval = $input->param("interval") ? int ( $input->param("interval") ) : 0; my $name = $input->param("name"); @@ -89,6 +90,7 @@ if ($request){ import_framework_code => $import_framework_code, import_record_type => $import_record_type, import_matcher_code => $import_matcher_code, + import_rdf_type => $import_rdf_type, interval => $interval, }); } -- 2.1.4