From f247f83d7970a2b5a1b3f605d3d490b02c6acbab Mon Sep 17 00:00:00 2001 From: "E. Lynette Rayle" Date: Mon, 5 Aug 2019 15:01:08 -0400 Subject: [PATCH] add ability to return a single term as n3 format for linked data This impacts all authorities supported through the linked data module and the discogs authority --- .../qa/linked_data_terms_controller.rb | 28 +++++++---- .../discogs/discogs_translation.rb | 6 +-- .../authorities/discogs/generic_authority.rb | 24 +++++++++- lib/qa/authorities/linked_data/find_term.rb | 19 +++++++- .../linked_data_terms_controller_spec.rb | 18 +++++++ .../discogs/generic_authority_spec.rb | 47 +++++++++++++++++++ 6 files changed, 125 insertions(+), 17 deletions(-) diff --git a/app/controllers/qa/linked_data_terms_controller.rb b/app/controllers/qa/linked_data_terms_controller.rb index b915453b..6b7b4bcb 100644 --- a/app/controllers/qa/linked_data_terms_controller.rb +++ b/app/controllers/qa/linked_data_terms_controller.rb @@ -59,10 +59,9 @@ def search # rubocop:disable Metrics/MethodLength, Metrics/AbcSize # get "/show/linked_data/:vocab/:subauthority/:id # @see Qa::Authorities::LinkedData::FindTerm#find def show # rubocop:disable Metrics/MethodLength, Metrics/AbcSize - term = @authority.find(id, subauth: subauthority, language: language, replacements: replacement_params, jsonld: jsonld?, performance_data: performance_data?) + term = @authority.find(id, subauth: subauthority, language: language, replacements: replacement_params, format: format, performance_data: performance_data?) cors_allow_origin_header(response) - content_type = jsonld? ? 'application/ld+json' : 'application/json' - render json: term, content_type: content_type + render json: term, content_type: content_type_for_format rescue Qa::TermNotFound msg = "Term Not Found - Fetch term #{id} unsuccessful for#{subauth_warn_msg} authority #{vocab_param}" logger.warn msg @@ -90,10 +89,9 @@ def show # rubocop:disable Metrics/MethodLength, Metrics/AbcSize # get "/fetch/linked_data/:vocab" # @see Qa::Authorities::LinkedData::FindTerm#find def fetch # rubocop:disable Metrics/MethodLength, Metrics/AbcSize - term = @authority.find(uri, subauth: subauthority, language: language, replacements: replacement_params, jsonld: jsonld?, performance_data: performance_data?) + term = @authority.find(uri, subauth: subauthority, language: language, replacements: replacement_params, format: format, performance_data: performance_data?) cors_allow_origin_header(response) - content_type = jsonld? ? 'application/ld+json' : 'application/json' - render json: term, content_type: content_type + render json: term, content_type: content_type_for_format rescue Qa::TermNotFound msg = "Term Not Found - Fetch term #{uri} unsuccessful for#{subauth_warn_msg} authority #{vocab_param}" logger.warn msg @@ -217,22 +215,32 @@ def format end def jsonld? - format.casecmp('jsonld').zero? + format.casecmp?('jsonld') + end + + def n3? + format.casecmp?('n3') + end + + def content_type_for_format + return 'application/ld+json' if jsonld? + return 'text/n3' if n3? + 'application/json' end def context? context = params.fetch(:context, 'false') - context.casecmp('true').zero? + context.casecmp?('true') end def details? details = params.fetch(:details, 'false') - details.casecmp('true').zero? + details.casecmp?('true') end def performance_data? performance_data = params.fetch(:performance_data, 'false') - performance_data.casecmp('true').zero? + performance_data.casecmp?('true') end def validate_auth_reload_token diff --git a/lib/qa/authorities/discogs/discogs_translation.rb b/lib/qa/authorities/discogs/discogs_translation.rb index fb02f7f7..b758b588 100644 --- a/lib/qa/authorities/discogs/discogs_translation.rb +++ b/lib/qa/authorities/discogs/discogs_translation.rb @@ -11,14 +11,14 @@ module DiscogsTranslation # to the URIs of corresponding objects in the Library of Congress vocabulary. # @param [Hash] the http response from discogs # @param [String] the subauthority - # @return [Array] jsonld - def build_graph(response, subauthority = "") + # @return [Array, String] requested RDF serialzation (supports: jsonld Array, n3 String) + def build_graph(response, subauthority = "", format: :jsonld) graph = RDF::Graph.new rdf_statements = compile_rdf_statements(response, subauthority) graph.insert_statements(rdf_statements) - graph.dump(:jsonld, standard_prefixes: true) + graph.dump(format, standard_prefixes: true) end # @param [Hash] the http response from discogs diff --git a/lib/qa/authorities/discogs/generic_authority.rb b/lib/qa/authorities/discogs/generic_authority.rb index d7d0e6bb..744b3620 100644 --- a/lib/qa/authorities/discogs/generic_authority.rb +++ b/lib/qa/authorities/discogs/generic_authority.rb @@ -35,10 +35,12 @@ def search(q, tc) # # @param [String] the Discogs id of the selected item # @param [Class] QA::TermsController - # @return either json results or jsonld + # @return results in requested format (supports: json, jsonld, n3) def find(id, tc) response = tc.params["subauthority"].include?("all") ? fetch_discogs_results(id) : json(find_url(id, tc.params["subauthority"])) - return build_graph(response) unless tc.params["format"] != "jsonld" || response["message"].present? + return response if response["message"].present? + return build_graph(response, format: :jsonld) if jsonld?(tc) + return build_graph(response, format: :n3) if n3?(tc) response end @@ -147,5 +149,23 @@ def get_context_for_string(item) def get_context_for_array(item) item.present? ? item : [""] end + + def format(tc) + return 'json' unless tc.params.key?('format') + return 'json' if tc.params['format'].blank? + tc.params['format'] + end + + def jsonld?(tc) + format(tc).casecmp?('jsonld') + end + + def n3?(tc) + format(tc).casecmp?('n3') + end + + def graph_format?(tc) + jsonld?(tc) || n3?(tc) + end end end diff --git a/lib/qa/authorities/linked_data/find_term.rb b/lib/qa/authorities/linked_data/find_term.rb index 04fc8ad1..cd7e5df1 100644 --- a/lib/qa/authorities/linked_data/find_term.rb +++ b/lib/qa/authorities/linked_data/find_term.rb @@ -39,12 +39,20 @@ def initialize(term_config) # "http://schema.org/name":["Cornell University","Ithaca (N.Y.). Cornell University"], # "http://www.w3.org/2004/02/skos/core#altLabel":["Ithaca (N.Y.). Cornell University"], # "http://schema.org/sameAs":["http://id.loc.gov/authorities/names/n79021621","https://viaf.org/viaf/126293486"] } } - def find(id, language: nil, replacements: {}, subauth: nil, jsonld: false, performance_data: false) # rubocop:disable Metrics/ParameterLists + def find(id, language: nil, replacements: {}, subauth: nil, format: nil, jsonld: false, performance_data: false) # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength + # TODO: When jsonld parameter is removed, the format parameter should default to 'json'. Not making this change now for backward compatibility of the default for jsonld parameter. raise Qa::InvalidLinkedDataAuthority, "Unable to initialize linked data term sub-authority #{subauth}" unless subauth.nil? || term_subauthority?(subauth) @language = language_service.preferred_language(user_language: language, authority_language: term_config.term_language) @id = id @performance_data = performance_data - @jsonld = jsonld + @format = format + @jsonld = jsonld if @format.blank? + if jsonld + Qa.deprecation_warning( + in_msg: 'Qa::Authorities::LinkedData::FindTerm', + msg: "jsonld parameter to find method is deprecated; use `format: 'jsonld'` instead" + ) + end url = authority_service.build_url(action_config: term_config, action: :term, action_request: normalize_id, substitutions: replacements, subauthority: subauth, language: @language) Rails.logger.info "QA Linked Data term url: #{url}" load_graph(url: url) @@ -80,6 +88,7 @@ def normalize_results def perform_normalization return "{}" unless full_graph.size.positive? return full_graph.dump(:jsonld, standard_prefixes: true) if jsonld? + return full_graph.dump(:n3, standard_prefixes: true) if n3? filter_graph extract_uri @@ -182,10 +191,16 @@ def optional_ldpaths opt_ldpaths.delete_if { |_k, v| v.blank? } end + # Give precedent to format parameter over jsonld parameter. NOTE: jsonld parameter for find method is deprecated. def jsonld? + return @format.casecmp?('jsonld') if @format @jsonld == true end + def n3? + @format && @format.casecmp?('n3') + end + def performance_data? @performance_data == true && !jsonld? end diff --git a/spec/controllers/linked_data_terms_controller_spec.rb b/spec/controllers/linked_data_terms_controller_spec.rb index b94eef1a..4299b3f5 100644 --- a/spec/controllers/linked_data_terms_controller_spec.rb +++ b/spec/controllers/linked_data_terms_controller_spec.rb @@ -425,6 +425,15 @@ expect(JSON.parse(response.body).keys).to match_array ["@context", "@graph"] end end + + context 'and it was requested as n3' do + it 'succeeds and returns term data as n3 content type' do + get :show, params: { id: '530369', vocab: 'OCLC_FAST', format: 'n3' } + expect(response).to be_successful + expect(response.content_type).to eq 'text/n3' + expect(response.body).to start_with "@prefix" + end + end end context 'when cors headers are enabled' do @@ -587,6 +596,15 @@ end end + context 'and it was requested as n3' do + it 'succeeds and returns term data as n3 content type' do + get :fetch, params: { uri: 'http://id.worldcat.org/fast/530369', vocab: 'LOD_TERM_URI_PARAM_CONFIG', format: 'n3' } + expect(response).to be_successful + expect(response.content_type).to eq 'text/n3' + expect(response.body).to start_with "@prefix" + end + end + context 'blank nodes not included in predicates list' do before do stub_request(:get, 'http://localhost/test_default/term?uri=http://id.worldcat.org/fast/530369wbn') diff --git a/spec/lib/authorities/discogs/generic_authority_spec.rb b/spec/lib/authorities/discogs/generic_authority_spec.rb index 6bc9df1f..2d1d4faf 100644 --- a/spec/lib/authorities/discogs/generic_authority_spec.rb +++ b/spec/lib/authorities/discogs/generic_authority_spec.rb @@ -136,6 +136,28 @@ end end + context "n3 format and subauthority master" do + let(:tc) { instance_double(Qa::TermsController) } + let :results do + authority.find("950011", tc) + end + before do + allow(Qa::TermsController).to receive(:new).and_return(tc) + allow(tc).to receive(:params).and_return('format' => "n3", 'subauthority' => "master") + end + + it "returns the Discogs data converted to n3 for a given id" do + expect(results).to start_with "@prefix" + expect(results).to include("Blue Moon / You Go To My Head") + expect(results).to include("Billie Holiday And Her Orchestra") + expect(results).to include("Haven Gillespie") + expect(results).to include("1952") + expect(results).to include("Jazz") + expect(results).to include("Barney Kessel") + expect(results).to include("Guitar") + end + end + context "json-ld format and subauthority all" do let(:tc) { instance_double(Qa::TermsController) } let :results do @@ -161,6 +183,31 @@ expect(results).to include("1952") end end + + context "n3 format and subauthority all" do + let(:tc) { instance_double(Qa::TermsController) } + let :results do + authority.find("7143179", tc) + end + before do + allow(Qa::TermsController).to receive(:new).and_return(tc) + allow(tc).to receive(:params).and_return('format' => "n3", 'subauthority' => "all") + end + + it "returns the Discogs data converted to n3 for a given id" do + expect(results).to start_with "@prefix" + expect(results).to include("You Go To My Head") + expect(results).to include("Rodgers & Hart") + expect(results).to include("Ray Brown") + expect(results).to include("1952") + expect(results).to include("Single") + expect(results).to include("mono") + expect(results).to include("45 RPM") + expect(results).to include("Vinyl") + expect(results).to include("http://id.loc.gov/vocabulary/carriers/sd") + expect(results).to include("1952") + end + end end end