From 6b85d0377bbcc8447765e651d03bd475dca5d0f8 Mon Sep 17 00:00:00 2001 From: Syphax Bouazzouni Date: Thu, 21 Jul 2022 11:10:09 +0200 Subject: [PATCH 1/2] add a script to import an ontology and its latest_sub from other portal --- bin/ncbo_ontology_import | 171 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100755 bin/ncbo_ontology_import diff --git a/bin/ncbo_ontology_import b/bin/ncbo_ontology_import new file mode 100755 index 00000000..f28ba255 --- /dev/null +++ b/bin/ncbo_ontology_import @@ -0,0 +1,171 @@ +#!/usr/bin/env ruby + +$0 = 'ncbo_cron' + +# Exit cleanly from an early interrupt +Signal.trap('INT') { exit 1 } + +# Setup the bundled gems in our environment +require 'bundler/setup' +# redis store for looking up queued jobs +require 'redis' + +require_relative '../lib/ncbo_cron' +require_relative '../config/config' +require 'net/http' + +# Script for importing ontologies + latest_submission into ontoportal appliance + + +require 'optparse' +ontologies_acronyms = '' +ontology_source = '' +source_api = '' +username = '' +opt_parser = OptionParser.new do |opts| + opts.banner = 'Usage: ncbo_ontology_import [options]' + opts.on('-o', '--ontology ACRONYM', 'Ontologies acronyms which we want to import (separated by comma)') do |acronym| + ontologies_acronyms = acronym + end + + opts.on('--from url', 'The ontoportal api url source of the ontology') do |url| + ontology_source = url.to_s + end + + opts.on('--from-api api', 'An apikey to acces the ontoportal api') do |api| + source_api = api.to_s + end + + opts.on('--admin-user username', 'The target admin user that will submit the ontology') do |user| + username = user.to_s + end + # Display the help screen, all programs are assumed to have this option. + opts.on( '-h', '--help', 'Display this screen') do + puts opts + exit + end +end +opt_parser.parse! + +# URL of the API and APIKEY of the Otoportal we want to import data FROM +SOURCE_API = ontology_source || 'http://data.bioontology.org' +SOURCE_APIKEY = source_api || '8b5b7825-538d-40e0-9e9e-5ab9274a9aeb' + + +# The username of the user that will have the administration rights on the ontology on the target portal +TARGETED_PORTAL_USER = username + +# The list of acronyms of ontologies to import +ONTOLOGIES_TO_IMPORT = ontologies_acronyms.split(',') || [] + + +def get_user(username) + user = LinkedData::Models::User.find(username).first + raise "The user #{username} does not exist" if user.nil? + user.bring_remaining +end + + +# A function to create a new ontology (if already Acronym already existing on the portal it will return HTTPConflict) +def create_ontology(ont_info) + + new_ontology = LinkedData::Models::Ontology.new + + new_ontology.acronym = ont_info['acronym'] + new_ontology.name = ont_info['name'] + new_ontology.administeredBy = [USER] + if ont_info['viewingRestriction'] == 'private' + # In case of private ontology (acl: list of user that have the right to see the ontology) + new_ontology.viewingRestriction = 'private' + new_ontology.acl = [USER] + end + new_ontology +end + +# A function that take the submission informations from the source Ontoportal to create a new submission +# 2 possibilities: +# - the source Ontoportal pulls the ontology from an URL (pullLocation is filled), in this case we directly pull from this URL +# - Or it stores it directly in the portal, in this case we pull it from the portal download link +def upload_submission(sub_info, ontology) + new_submission = LinkedData::Models::OntologySubmission.new + # Check if the source BioPortal is pulling the ontology from an URL + # If yes then we will pull the ontology from this place (allow auto update of the ontology when the ontology is changed in its source URL) + if sub_info['pullLocation'].nil? + sub_info['pullLocation'] = "#{sub_info['ontology']['links']['download']}?apikey=#{SOURCE_APIKEY}" + end + + # Build the json body + # hasOntologyLanguage options: OWL, UMLS, SKOS, OBO + # status: alpha, beta, production, retired + attr_to_reject = %w[id submissionStatus hasOntologyLanguage metrics ontology @id @type contact] + to_copy = sub_info.select do |k,v| + !v.nil? && !v.is_a?(Hash) && !v.to_s.empty? && !attr_to_reject.include?(k) + end + to_copy["ontology"] = ontology + to_copy["contact"] = [LinkedData::Models::Contact.where(email: USER.email).first] + to_copy["hasOntologyLanguage"] = LinkedData::Models::OntologyFormat.where(acronym: sub_info["hasOntologyLanguage"]).first + + to_copy.each do |key, value| + attribute_settings = new_submission.class.attribute_settings(key.to_sym) + + if attribute_settings + if attribute_settings[:enforce]&.include?(:date_time) + value = DateTime.parse(value) + elsif attribute_settings[:enforce]&.include?(:uri) && attribute_settings[:enforce]&.include?(:list) + value = value.map { |v| RDF::IRI.new(v) } + elsif attribute_settings[:enforce]&.include?(:uri) + value = RDF::IRI.new(value) + end + end + + new_submission.send("#{key}=", value) + end + + new_submission +end + + +USER = get_user username +#get apikey for admin user +TARGET_APIKEY = USER.apikey + +SOURCE_APIKEY == '' && abort('SOURCE_APIKEY has to be set') + +def result_log(ressource, errors) + if !errors + puts "#{ressource} imported successfully" + else + puts errors + end +end + +# Go through all ontologies acronym and get their latest_submission informations +ONTOLOGIES_TO_IMPORT.each do |ont| + sub_info = JSON.parse(Net::HTTP.get(URI.parse("#{SOURCE_API}/ontologies/#{ont}/latest_submission?apikey=#{SOURCE_APIKEY}&display=all"))) + puts "Import #{ont} " , + "From #{SOURCE_API}" + # if the ontology is already created then it will return HTTPConflict, no consequences + raise "The ontology #{ont} does not exist" if sub_info['ontology'].nil? + new_ontology = create_ontology(sub_info['ontology']) + errors = nil + if new_ontology.valid? + new_ontology.save + else + errors = new_ontology.errors + new_ontology = nil + end + result_log ont, errors + + new_ontology ||= LinkedData::Models::Ontology.where(acronym: ont).first + new_submission = upload_submission(sub_info, new_ontology) + if new_submission.valid? + new_submission.save + errors = nil + else + errors = new_submission.errors + end + result_log(sub_info["id"], errors) +end + + + From 30f702e557d21877296143c3c428fb8569326c7e Mon Sep 17 00:00:00 2001 From: Syphax Bouazzouni Date: Fri, 29 Jul 2022 17:32:22 +0200 Subject: [PATCH 2/2] make the SOURCE_APIKEY and SOURCE_API arguments mandatory --- bin/ncbo_ontology_import | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bin/ncbo_ontology_import b/bin/ncbo_ontology_import index f28ba255..db2e90c5 100755 --- a/bin/ncbo_ontology_import +++ b/bin/ncbo_ontology_import @@ -47,9 +47,9 @@ opt_parser = OptionParser.new do |opts| end opt_parser.parse! -# URL of the API and APIKEY of the Otoportal we want to import data FROM -SOURCE_API = ontology_source || 'http://data.bioontology.org' -SOURCE_APIKEY = source_api || '8b5b7825-538d-40e0-9e9e-5ab9274a9aeb' +# URL of the API and APIKEY of the Ontoportal we want to import data FROM +SOURCE_API = ontology_source +SOURCE_APIKEY = source_api # The username of the user that will have the administration rights on the ontology on the target portal @@ -129,7 +129,8 @@ USER = get_user username #get apikey for admin user TARGET_APIKEY = USER.apikey -SOURCE_APIKEY == '' && abort('SOURCE_APIKEY has to be set') +SOURCE_APIKEY == '' && abort('--from-api has to be set') +SOURCE_API == '' && abort('--from has to be set') def result_log(ressource, errors) if !errors