Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
41a2525
update Instance model to use Goo not a raw Sparql query
syphax-bouazzouni Jun 19, 2025
89d7675
extract the classes tree and sorting to external modules
syphax-bouazzouni Jun 19, 2025
7fce23e
add the skos new models for collection, schemes and skosxl with tests
syphax-bouazzouni Jun 19, 2025
3d03c1f
add for classes the properties to know on which scheme and collection…
syphax-bouazzouni Jun 19, 2025
bcea238
update the logic of submission roots to filter by schemes or collections
syphax-bouazzouni Jun 19, 2025
0184224
add for the ontology endpoint links to its related schemes, collectio…
syphax-bouazzouni Jun 19, 2025
c39d833
add tests to check the submission roots filtring by scheme or collection
syphax-bouazzouni Jun 19, 2025
6bb3412
add internal skos mappings extraction
syphax-bouazzouni Jun 19, 2025
891cbac
fix tests for allegrograph
syphax-bouazzouni Jun 19, 2025
07fca4c
Merge branch 'pr/feature/better-skos' of https://github.com/ontoporta…
mdorf Jun 20, 2025
b0c76fe
Merge branch 'ontoportal-lirmm-pr/feature/better-skos' into ontoporta…
mdorf Jun 20, 2025
ecff718
unit tests fixed
mdorf Jun 30, 2025
ae10867
Correct ui.name capitalization
jvendetti Jul 14, 2025
0343de3
Add helper method to render email templates
jvendetti Jul 14, 2025
106630f
Merge branch 'develop' into ontoportal-lirmm/feature/enhanced-skos-su…
alexskr Jul 15, 2025
6752f53
Merge pull request #249 from ncbo/ontoportal-lirmm/feature/enhanced-s…
alexskr Jul 15, 2025
504d242
Add a notification for Cloudflare Analytics
jvendetti Jul 15, 2025
d57b1cf
Make render_template private
jvendetti Jul 15, 2025
2e0b612
Fix some RuboCop warnings
jvendetti Jul 15, 2025
ac14d9c
Add unit tests for render_template method
jvendetti Jul 15, 2025
d95d004
Add unit tests for analytics notifications
jvendetti Jul 15, 2025
ec203c7
Fix some RuboCop warnings
jvendetti Jul 15, 2025
3249a03
Improve setup and teardown
jvendetti Jul 15, 2025
d55bddd
Merge pull request #250 from ncbo/cloudflare-analytics/369
jvendetti Jul 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified bin/owlapi-wrapper-1.5.0.jar
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion dip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ interaction:

test-ag:
description: Run minitest unit tests
service: ruby-ag
service: ruby-agraph
command: bundle exec rake test


Expand Down
2 changes: 1 addition & 1 deletion lib/ontologies_linked_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
end

# We need to require deterministic - that is why we have the sort.
models = Dir.glob("#{project_root}/ontologies_linked_data/models/concerns//**/*.rb").sort
models = Dir.glob("#{project_root}/ontologies_linked_data/models/concerns/**/*.rb").sort
models.each do |m|
require m
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module LinkedData
module Concerns
module Concept
module InCollection
def self.included(base)
base.serialize_methods :isInActiveCollection
end

def isInActiveCollection
@isInActiveCollection
end

def inCollection?(collection)
self.memberOf.include?(collection)
end

def load_is_in_collection(collections = [])
included = collections.select { |s| inCollection?(s) }
@isInActiveCollection = included
end

end
end
end
end
26 changes: 26 additions & 0 deletions lib/ontologies_linked_data/concerns/concepts/concept_in_scheme.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module LinkedData
module Concerns
module Concept
module InScheme
def self.included(base)
base.serialize_methods :isInActiveScheme
end

def isInActiveScheme
@isInActiveScheme
end

def inScheme?(scheme)
self.inScheme.include?(scheme)
end

def load_is_in_scheme(schemes = [])
included = schemes.select { |s| inScheme?(s) }
included = [self.submission.get_main_concept_scheme] if included.empty? && schemes&.empty?
@isInActiveScheme = included
end

end
end
end
end
55 changes: 55 additions & 0 deletions lib/ontologies_linked_data/concerns/concepts/concept_sort.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module LinkedData
module Concerns
module Concept
module Sort
module ClassMethods
def compare_classes(class_a, class_b)
label_a = ""
label_b = ""
class_a.bring(:prefLabel) if class_a.bring?(:prefLabel)
class_b.bring(:prefLabel) if class_b.bring?(:prefLabel)

begin
label_a = class_a.prefLabel unless (class_a.prefLabel.nil? || class_a.prefLabel.empty?)
rescue Goo::Base::AttributeNotLoaded
label_a = ""
end

begin
label_b = class_b.prefLabel unless (class_b.prefLabel.nil? || class_b.prefLabel.empty?)
rescue Goo::Base::AttributeNotLoaded
label_b = ""
end

label_a = class_a.id if label_a.empty?
label_b = class_b.id if label_b.empty?

[label_a.downcase] <=> [label_b.downcase]
end

def sort_classes(classes)
classes.sort { |class_a, class_b| compare_classes(class_a, class_b) }
end

def sort_tree_children(root_node)
sort_classes!(root_node.children)
root_node.children.each { |ch| sort_tree_children(ch) }
end

private



def sort_classes!(classes)
classes.sort! { |class_a, class_b| LinkedData::Models::Class.compare_classes(class_a, class_b) }
classes
end
end

def self.included(base)
base.extend(ClassMethods)
end
end
end
end
end
139 changes: 139 additions & 0 deletions lib/ontologies_linked_data/concerns/concepts/concept_tree.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
module LinkedData
module Concerns
module Concept
module Tree
def tree(concept_schemes: [], concept_collections: [], roots: nil)
bring(parents: [:prefLabel]) if bring?(:parents)
return self if parents.nil? || parents.empty?
extra_include = [:hasChildren, :isInActiveScheme, :isInActiveCollection]
roots = self.submission.roots( extra_include, concept_schemes:concept_schemes) if roots.nil?
path = path_to_root(roots)
threshold = 99

return self if path.nil?

attrs_to_load = %i[prefLabel synonym obsolete]
attrs_to_load << :subClassOf if submission.hasOntologyLanguage.obo?
attrs_to_load += self.class.concept_is_in_attributes if submission.skos?
self.class.in(submission)
.models(path)
.include(attrs_to_load).all
load_children(path, threshold: threshold)

path.reverse!
path.last.instance_variable_set("@children", [])

childrens_hash = {}
path.each do |m|
next if m.id.to_s["#Thing"]
m.children.each do |c|
childrens_hash[c.id.to_s] = c
c.load_computed_attributes(to_load:extra_include ,
options: {schemes: concept_schemes, collections: concept_collections})
end
m.load_computed_attributes(to_load:extra_include ,
options: {schemes: concept_schemes, collections: concept_collections})
end

load_children(childrens_hash.values, threshold: threshold)

build_tree(path)
end

def tree_sorted(concept_schemes: [], concept_collections: [], roots: nil)
tr = tree(concept_schemes: concept_schemes, concept_collections: concept_collections, roots: roots)
self.class.sort_tree_children(tr)
tr
end

def paths_to_root(tree: false, roots: nil)
bring(parents: [:prefLabel, :synonym, :definition]) if bring?(:parents)
return [] if parents.nil? || parents.empty?

paths = [[self]]
traverse_path_to_root(self.parents.dup, paths, 0, tree, roots) unless tree_root?(self, roots)
paths.each do |p|
p.reverse!
end
paths
end

def path_to_root(roots)
paths = [[self]]
paths = paths_to_root(tree: true, roots: roots)
#select one path that gets to root
path = nil
paths.each do |p|
p.reverse!
unless (p.map { |x| x.id.to_s } & roots.map { |x| x.id.to_s }).empty?
path = p
break
end
end

if path.nil?
# do one more check for root classes that don't get returned by the submission.roots call
paths.each do |p|
root_node = p.last
root_parents = root_node.parents

if root_parents.empty?
path = p
break
end
end
end

path
end

def tree_root?(concept, roots)
(roots &&roots.map{|r| r.id}.include?(concept.id)) || concept.id.to_s["#Thing"]
end

private

def load_children(concepts, threshold: 99)
LinkedData::Models::Class
.partially_load_children(concepts, threshold, submission)
end

def build_tree(path)
root_node = path.first
tree_node = path.first
path.delete_at(0)
while tree_node &&
!tree_node.id.to_s["#Thing"] &&
!tree_node.children.empty? && (!path.empty?) do
next_tree_node = nil
tree_node.load_has_children
tree_node.children.each_index do |i|
if tree_node.children[i].id.to_s == path.first.id.to_s
next_tree_node = path.first
children = tree_node.children.dup
children[i] = path.first
tree_node.instance_variable_set("@children", children)
children.each do |c|
c.load_has_children
end
else
tree_node.children[i].instance_variable_set("@children", [])
end
end

if !path.empty? && next_tree_node.nil?
tree_node.children << path.shift
end
tree_node = next_tree_node
path.delete_at(0)
end

root_node
end

end
end

end
end

Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
module LinkedData
module Models
module SKOS
module RootsFetcher

def skos_roots(concept_schemes, page, paged, pagesize)
classes = []
class_ids, count = roots_by_has_top_concept(concept_schemes, page, paged, pagesize)

class_ids, count = roots_by_top_concept_of(concept_schemes, page, paged, pagesize) if class_ids.empty?

class_ids.each do |id|
classes << LinkedData::Models::Class.find(id).in(self).disable_rules.first
end

classes = Goo::Base::Page.new(page, pagesize, count, classes) if paged
classes
end

private

def roots_by_query(query_body, page, paged, pagesize)
root_skos = <<-eos
SELECT DISTINCT ?root WHERE {
GRAPH #{self.id.to_ntriples} {
#{query_body}
}}
eos
count = 0

count, root_skos = add_pagination(query_body, page, pagesize, root_skos) if paged

#needs to get cached
class_ids = []

Goo.sparql_query_client.query(root_skos, { graphs: [self.id] }).each_solution do |s|
class_ids << s[:root]
end

[class_ids, count]
end

def roots_by_has_top_concept(concept_schemes, page, paged, pagesize)
query_body = <<-eos
?x #{RDF::SKOS[:hasTopConcept].to_ntriples} ?root .
#{concept_schemes_filter(concept_schemes)}
eos
roots_by_query query_body, page, paged, pagesize
end

def roots_by_top_concept_of(concept_schemes, page, paged, pagesize)
query_body = <<-eos
?root #{RDF::SKOS[:topConceptOf].to_ntriples} ?x.
#{concept_schemes_filter(concept_schemes)}
eos
roots_by_query query_body, page, paged, pagesize
end

def add_pagination(query_body, page, pagesize, root_skos)
count = count_roots(query_body)

offset = (page - 1) * pagesize
root_skos = "#{root_skos} LIMIT #{pagesize} OFFSET #{offset}"
[count, root_skos]
end

def count_roots(query_body)
query = <<-eos
SELECT (COUNT(?x) as ?count) WHERE {
GRAPH #{self.id.to_ntriples} {
#{query_body}
}}
eos
rs = Goo.sparql_query_client.query(query)
count = 0
rs.each do |sol|
count = sol[:count].object
end
count
end

def concept_schemes_filter(concept_schemes)
concept_schemes = current_schemes(concept_schemes)
concept_schemes = concept_schemes.map { |x| RDF::URI.new(x.to_s).to_ntriples }
concept_schemes.empty? ? '' : "FILTER (?x IN (#{concept_schemes.join(',')}))"
end

def current_schemes(concept_schemes)
if concept_schemes.nil? || concept_schemes.empty?
main_concept_scheme = get_main_concept_scheme
concept_schemes = main_concept_scheme ? [main_concept_scheme] : []
end
concept_schemes
end

end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module LinkedData
module Models
module SKOS
module ConceptSchemes
def get_main_concept_scheme(default_return: ontology_uri)
all = all_concepts_schemes
unless all.nil?
all = all.map { |x| x.id }
return default_return if all.include?(ontology_uri)
end
end

def all_concepts_schemes
LinkedData::Models::SKOS::Scheme.in(self).all
end
end
end
end
end

Loading