From 36a5b68c38a02e0b221ba7b7bfc1169dc14ea01f Mon Sep 17 00:00:00 2001 From: Syphax bouazzouni Date: Mon, 6 May 2024 13:54:13 +0200 Subject: [PATCH] display the language tags when serializing the results to JSON --- Gemfile | 7 +- Gemfile.lock | 30 +++---- lib/ontologies_linked_data/serializer.rb | 19 ++++- .../serializers/json.rb | 83 ++++++++++++++----- 4 files changed, 98 insertions(+), 41 deletions(-) diff --git a/Gemfile b/Gemfile index 84eff580..37b7e871 100644 --- a/Gemfile +++ b/Gemfile @@ -16,6 +16,8 @@ gem 'rest-client' gem 'rsolr' gem 'rubyzip', '~> 1.0' gem 'thin' +gem 'request_store' + # Testing group :test do @@ -31,7 +33,6 @@ end group :development do gem 'rubocop', require: false end - # NCBO gems (can be from a local dev path or from rubygems/git) -gem 'goo', github: 'ncbo/goo', branch: 'master' -gem 'sparql-client', github: 'ncbo/sparql-client', branch: 'master' +gem 'goo', github: 'ontoportal-lirmm/goo', branch: 'pr/sync-agroportal-bioportal' +gem 'sparql-client', github: 'ncbo/sparql-client', branch: 'develop' diff --git a/Gemfile.lock b/Gemfile.lock index 435dfb4d..957f7ee9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,17 @@ GIT - remote: https://github.com/ncbo/goo.git - revision: ef2d816df2d263c905bd034efd449a964fa4890f - branch: master + remote: https://github.com/ncbo/sparql-client.git + revision: 1657f0dd69fd4b522d3549a6848670175f5e98cc + branch: develop + specs: + sparql-client (1.0.1) + json_pure (>= 1.4) + net-http-persistent (= 2.9.4) + rdf (>= 1.0) + +GIT + remote: https://github.com/ontoportal-lirmm/goo.git + revision: f2751fe9324e48a0a5c2a8b15580ab879fc53a2b + branch: pr/sync-agroportal-bioportal specs: goo (0.0.2) addressable (~> 2.8) @@ -14,16 +24,6 @@ GIT sparql-client uuid -GIT - remote: https://github.com/ncbo/sparql-client.git - revision: e89c26aa96f184dbe9b52d51e04fb3d9ba998dbc - branch: master - specs: - sparql-client (1.0.1) - json_pure (>= 1.4) - net-http-persistent (= 2.9.4) - rdf (>= 1.0) - GEM remote: https://rubygems.org/ specs: @@ -182,8 +182,7 @@ GEM macaddr (~> 1.0) PLATFORMS - arm64-darwin-22 - x86_64-darwin-21 + x86_64-linux DEPENDENCIES activesupport (~> 4) @@ -204,6 +203,7 @@ DEPENDENCIES rack rack-test (~> 0.6) rake (~> 10.0) + request_store rest-client rsolr rubocop diff --git a/lib/ontologies_linked_data/serializer.rb b/lib/ontologies_linked_data/serializer.rb index 78446ed3..c1d9f630 100644 --- a/lib/ontologies_linked_data/serializer.rb +++ b/lib/ontologies_linked_data/serializer.rb @@ -84,10 +84,15 @@ def self.response(options = {}) end def self.serialize(type, obj, params, request) - only = params["display"] || [] - only = only.split(",") unless only.kind_of?(Array) - only, all = [], true if only[0].eql?("all") - options = {:only => only, :all => all, :params => params, :request => request} + + lang = self.get_language(params) + + only = params['display'] || [] + only = only.split(',') unless only.is_a?(Array) + all = only[0] == 'all' + only = all ? [] : only + + options = { only: only, lang: lang, all: all, params: params, request: request } LinkedData::Serializers.serialize(obj, type, options) end @@ -103,5 +108,11 @@ def self.print_stacktrace? end end + def self.get_language(params) + lang = params['lang'] || params['language'] || Goo.main_languages&.first.to_s || 'en' + lang = lang.split(',').map {|l| l.downcase.to_sym} + return lang.length == 1 ? lang.first : lang + end + end end \ No newline at end of file diff --git a/lib/ontologies_linked_data/serializers/json.rb b/lib/ontologies_linked_data/serializers/json.rb index 7d8c5034..5386fb78 100644 --- a/lib/ontologies_linked_data/serializers/json.rb +++ b/lib/ontologies_linked_data/serializers/json.rb @@ -6,16 +6,20 @@ class JSON CONTEXTS = {} def self.serialize(obj, options = {}) + + hash = obj.to_flex_hash(options) do |hash, hashed_obj| current_cls = hashed_obj.respond_to?(:klass) ? hashed_obj.klass : hashed_obj.class + result_lang = self.get_languages(get_object_submission(hashed_obj), options[:lang]) if result_lang.nil? # Add the id to json-ld attribute if current_cls.ancestors.include?(LinkedData::Hypermedia::Resource) && !current_cls.embedded? && hashed_obj.respond_to?(:id) prefixed_id = LinkedData::Models::Base.replace_url_id_to_prefix(hashed_obj.id) hash["@id"] = prefixed_id.to_s end + # Add the type - hash["@type"] = current_cls.type_uri.to_s if hash["@id"] && current_cls.respond_to?(:type_uri) + hash["@type"] = type(current_cls, hashed_obj) if hash["@id"] # Generate links # NOTE: If this logic changes, also change in xml.rb @@ -30,17 +34,57 @@ def self.serialize(obj, options = {}) # Generate context if current_cls.ancestors.include?(Goo::Base::Resource) && !current_cls.embedded? if generate_context?(options) - context = generate_context(hashed_obj, hash.keys, options) if generate_context?(options) + context = generate_context(hashed_obj, hash.keys, options) hash.merge!(context) end end + hash['@context']['@language'] = result_lang if hash['@context'] end - MultiJson.dump(hash) end private + def self.get_object_submission(obj) + obj.class.respond_to?(:attributes) && obj.class.attributes.include?(:submission) ? obj.submission : nil + end + + def self.get_languages(submission, user_languages) + result_lang = user_languages + + if submission + submission.bring :naturalLanguage + languages = get_submission_languages(submission.naturalLanguage) + # intersection of the two arrays , if the requested language is not :all + result_lang = user_languages == :all ? languages : Array(user_languages) & languages + result_lang = result_lang.first if result_lang.length == 1 + end + + result_lang + end + + def self.get_submission_languages(submission_natural_language = []) + submission_natural_language = submission_natural_language.values.flatten if submission_natural_language.is_a?(Hash) + submission_natural_language.map { |natural_language| natural_language.to_s['iso639'] && natural_language.to_s.split('/').last[0..1].to_sym }.compact + end + + def self.type(current_cls, hashed_obj) + if current_cls.respond_to?(:type_uri) + # For internal class + proc = current_cls + elsif hashed_obj.respond_to?(:type_uri) + # For External and Interportal class + proc = hashed_obj + end + + collection = hashed_obj.respond_to?(:collection) ? hashed_obj.collection : nil + if collection + proc.type_uri(collection).to_s + else + proc.type_uri.to_s + end + end + def self.generate_context(object, serialized_attrs = [], options = {}) return remove_unused_attrs(CONTEXTS[object.hash], serialized_attrs) unless CONTEXTS[object.hash].nil? hash = {} @@ -52,17 +96,19 @@ def self.generate_context(object, serialized_attrs = [], options = {}) linked_model = current_cls.model_settings[:range][attr] end - predicate = nil if linked_model && linked_model.ancestors.include?(Goo::Base::Resource) && !embedded?(object, attr) # linked object - predicate = {"@id" => linked_model.type_uri.to_s, "@type" => "@id"} - elsif current_cls.model_settings[:attributes][attr][:namespace] + predicate = { "@id" => linked_model.type_uri.to_s, "@type" => "@id" } + else + # use the original predicate property if set + predicate_attr = current_cls.model_settings[:attributes][attr][:property] || attr # predicate with custom namespace - predicate = "#{Goo.vocabulary[current_cls.model_settings[:attributes][attr][:namespace]].to_s}#{attr}" + # if the namespace can be resolved by the namespaces added in Goo then it will be resolved. + predicate = "#{Goo.vocabulary(current_cls.model_settings[:attributes][attr][:namespace])&.to_s}#{predicate_attr}" end hash[attr] = predicate unless predicate.nil? end - context = {"@context" => hash} + context = { "@context" => hash } CONTEXTS[object.hash] = context context = remove_unused_attrs(context, serialized_attrs) unless options[:params] && options[:params]["full_context"].eql?("true") context @@ -75,12 +121,12 @@ def self.generate_links_context(object) links.each do |link| links_context[link.type] = link.type_uri.to_s end - return {"@context" => links_context} + return { "@context" => links_context } end def self.remove_unused_attrs(context, serialized_attrs = []) - new_context = context["@context"].reject {|k,v| !serialized_attrs.include?(k) && !k.to_s.start_with?("@")} - {"@context" => new_context} + new_context = context["@context"].reject { |k, v| !serialized_attrs.include?(k) && !k.to_s.start_with?("@") } + { "@context" => new_context } end def self.embedded?(object, attribute) @@ -97,20 +143,19 @@ def self.generate_context?(options) params = options[:params] params.nil? || (params["no_context"].nil? || - !params["no_context"].eql?("true")) && - (params["display_context"].nil? || - !params["display_context"].eql?("false")) + !params["no_context"].eql?("true")) && + (params["display_context"].nil? || + !params["display_context"].eql?("false")) end def self.generate_links?(options) params = options[:params] params.nil? || (params["no_links"].nil? || - !params["no_links"].eql?("true")) && - (params["display_links"].nil? || - !params["display_links"].eql?("false")) + !params["no_links"].eql?("true")) && + (params["display_links"].nil? || + !params["display_links"].eql?("false")) end end end -end - +end \ No newline at end of file