triannon 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +21 -16
- data/Rakefile +15 -18
- data/app/controllers/concerns/rdf_response_formats.rb +16 -14
- data/app/controllers/triannon/annotations_controller.rb +6 -6
- data/app/models/triannon/annotation.rb +5 -5
- data/app/models/triannon/annotation_ldp.rb +17 -16
- data/app/services/triannon/ldp_loader.rb +14 -4
- data/app/services/triannon/ldp_to_oa_mapper.rb +68 -59
- data/app/services/triannon/ldp_writer.rb +180 -59
- data/app/services/triannon/solr_searcher.rb +8 -8
- data/app/services/triannon/solr_writer.rb +12 -12
- data/config/jetty/etc/fedora-override-web.xml +67 -0
- data/config/routes.rb +2 -2
- data/config/triannon.yml +29 -6
- data/lib/generators/triannon/install_generator.rb +23 -3
- data/lib/rdf/triannon_vocab.rb +2 -2
- data/lib/tasks/triannon_tasks.rake +19 -5
- data/lib/triannon.rb +13 -20
- data/lib/triannon/iiif_anno_list.rb +4 -4
- data/lib/triannon/oa_graph_helper.rb +51 -0
- data/lib/triannon/version.rb +1 -1
- metadata +35 -39
- data/app/services/triannon/root_annotation_creator.rb +0 -36
- data/lib/triannon/graph.rb +0 -173
- data/lib/triannon/jsonld_context.rb +0 -13
@@ -1,36 +0,0 @@
|
|
1
|
-
module Triannon
|
2
|
-
|
3
|
-
class RootAnnotationCreator
|
4
|
-
|
5
|
-
# Creates an LDP Container to hold all the annotations
|
6
|
-
# Called from config/initializers/root_annotation_container.rb during app bootup
|
7
|
-
# @return [Boolean] true if the root container was created, false if the container already exists or if there were issues
|
8
|
-
def self.create
|
9
|
-
conn = Faraday.new :url => Triannon.config[:ldp_url]
|
10
|
-
resp = conn.head
|
11
|
-
unless resp.status == 404 || resp.status == 410
|
12
|
-
puts "Root annotation resource already exists."
|
13
|
-
return false
|
14
|
-
end
|
15
|
-
|
16
|
-
uri = RDF::URI.new Triannon.config[:ldp_url]
|
17
|
-
conn = Faraday.new :url => uri.parent.to_s
|
18
|
-
slug = uri.to_s.split('/').last
|
19
|
-
|
20
|
-
resp = conn.post do |req|
|
21
|
-
req.headers['Content-Type'] = 'text/turtle'
|
22
|
-
req.headers['Slug'] = slug
|
23
|
-
end
|
24
|
-
|
25
|
-
if resp.status == 201
|
26
|
-
puts "Created root annotation container #{Triannon.config[:ldp_url]}"
|
27
|
-
return true
|
28
|
-
else
|
29
|
-
puts "Unable to create root annotation container #{Triannon.config[:ldp_url]}"
|
30
|
-
return false
|
31
|
-
# TODO raise an exception if we get here?
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|
data/lib/triannon/graph.rb
DELETED
@@ -1,173 +0,0 @@
|
|
1
|
-
module Triannon
|
2
|
-
# a wrapper class for RDF::Graph that adds methods specific to Triannon
|
3
|
-
# this is intended to be used for an RDF::Graph of a single annotation
|
4
|
-
class Graph
|
5
|
-
|
6
|
-
# Class Methods ----------------------------------------------------------------
|
7
|
-
|
8
|
-
# given an RDF::Resource (an RDF::Node or RDF::URI), look for all the statements with that object
|
9
|
-
# as the subject, and recurse through the graph to find all descendant statements pertaining to the subject
|
10
|
-
# @param subject the RDF object to be used as the subject in the graph query. Should be an RDF::Node or RDF::URI
|
11
|
-
# @param [RDF::Graph] graph
|
12
|
-
# @return [Array[RDF::Statement]] all the triples with the given subject
|
13
|
-
def self.subject_statements(subject, graph)
|
14
|
-
result = []
|
15
|
-
graph.query([subject, nil, nil]).each { |stmt|
|
16
|
-
result << stmt
|
17
|
-
subject_statements(stmt.object, graph).each { |s| result << s }
|
18
|
-
}
|
19
|
-
result.uniq
|
20
|
-
end
|
21
|
-
|
22
|
-
# @return [RDF::Query] query for a subject :s with type of RDF::OpenAnnotation.Annotation
|
23
|
-
def self.anno_query
|
24
|
-
q = RDF::Query.new
|
25
|
-
q << [:s, RDF.type, RDF::OpenAnnotation.Annotation]
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
# Instance Methods ----------------------------------------------------------------
|
30
|
-
|
31
|
-
# instantiate this class for an RDF::Graph of a single annotation
|
32
|
-
def initialize(rdf_graph)
|
33
|
-
@graph = rdf_graph
|
34
|
-
end
|
35
|
-
|
36
|
-
# @return json-ld representation of graph with OpenAnnotation context as a url
|
37
|
-
def jsonld_oa
|
38
|
-
inline_context = @graph.dump(:jsonld, :context => Triannon::JsonldContext::OA_DATED_CONTEXT_URL)
|
39
|
-
hash_from_json = JSON.parse(inline_context)
|
40
|
-
hash_from_json["@context"] = Triannon::JsonldContext::OA_DATED_CONTEXT_URL
|
41
|
-
hash_from_json.to_json
|
42
|
-
end
|
43
|
-
|
44
|
-
# @return json-ld representation of graph with IIIF context as a url
|
45
|
-
def jsonld_iiif
|
46
|
-
inline_context = @graph.dump(:jsonld, :context => Triannon::JsonldContext::IIIF_CONTEXT_URL)
|
47
|
-
hash_from_json = JSON.parse(inline_context)
|
48
|
-
hash_from_json["@context"] = Triannon::JsonldContext::IIIF_CONTEXT_URL
|
49
|
-
hash_from_json.to_json
|
50
|
-
end
|
51
|
-
|
52
|
-
# Canned Query methods ----------------------------------------------------------------
|
53
|
-
|
54
|
-
# @return [String] the id of this annotation as a url string, or nil if it is a Node
|
55
|
-
def id_as_url
|
56
|
-
solution = @graph.query self.class.anno_query
|
57
|
-
if solution && solution.size == 1
|
58
|
-
rdf_resource = solution.first.s
|
59
|
-
rdf_resource.to_s if rdf_resource.is_a?(RDF::URI)
|
60
|
-
# TODO: raise exception if not a URI?
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# @return [Array<String>] Array of urls expressing the OA motivated_by values
|
65
|
-
def motivated_by
|
66
|
-
motivations = []
|
67
|
-
q = self.class.anno_query.dup
|
68
|
-
q << [:s, RDF::OpenAnnotation.motivatedBy, :motivated_by]
|
69
|
-
solution = @graph.query q
|
70
|
-
if solution && solution.size > 0
|
71
|
-
solution.each {|res|
|
72
|
-
motivations << res.motivated_by.to_s
|
73
|
-
}
|
74
|
-
end
|
75
|
-
# TODO: raise exception if none? (validation)
|
76
|
-
motivations
|
77
|
-
end
|
78
|
-
|
79
|
-
# @param [RDF::URI] predicate either RDF::OpenAnnotation.hasTarget or RDF::OpenAnnotation.hasBody
|
80
|
-
# @return [Array<String>] urls for the predicate, as an Array of Strings
|
81
|
-
def predicate_urls(predicate)
|
82
|
-
urls = []
|
83
|
-
predicate_solns = @graph.query [nil, predicate, nil]
|
84
|
-
predicate_solns.each { |predicate_stmt |
|
85
|
-
predicate_obj = predicate_stmt.object
|
86
|
-
urls << predicate_obj.to_str.strip if predicate_obj.is_a?(RDF::URI)
|
87
|
-
}
|
88
|
-
urls
|
89
|
-
end
|
90
|
-
|
91
|
-
# For all bodies that are of type ContentAsText, get the characters as a single String in the returned Array.
|
92
|
-
# @return [Array<String>] body chars as Strings, in an Array (one element for each contentAsText body)
|
93
|
-
def body_chars
|
94
|
-
result = []
|
95
|
-
q = RDF::Query.new
|
96
|
-
q << [nil, RDF::OpenAnnotation.hasBody, :body]
|
97
|
-
q << [:body, RDF.type, RDF::Content.ContentAsText]
|
98
|
-
q << [:body, RDF::Content.chars, :body_chars]
|
99
|
-
solns = @graph.query q
|
100
|
-
solns.each { |soln|
|
101
|
-
result << soln.body_chars.value
|
102
|
-
}
|
103
|
-
result
|
104
|
-
end
|
105
|
-
|
106
|
-
# @return [String] The datetime from the annotatedAt property, or nil
|
107
|
-
def annotated_at
|
108
|
-
solution = @graph.query [nil, RDF::OpenAnnotation.annotatedAt, nil]
|
109
|
-
if solution && solution.size == 1
|
110
|
-
solution.first.object.to_s
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
|
115
|
-
# Changing the Graph ----------------------------------------------------------------
|
116
|
-
|
117
|
-
# remove all RDF::OpenAnnotation.hasBody and .hasTarget statements
|
118
|
-
# and any other statements associated with body and target objects,
|
119
|
-
# leaving all statements to be stored as part of base object in LDP store
|
120
|
-
def remove_non_base_statements
|
121
|
-
remove_has_target_statements
|
122
|
-
remove_has_body_statements
|
123
|
-
end
|
124
|
-
|
125
|
-
# remove all RDF::OpenAnnotation.hasBody statements and any other statements associated with body objects
|
126
|
-
def remove_has_body_statements
|
127
|
-
remove_predicate_and_its_object_statements RDF::OpenAnnotation.hasBody
|
128
|
-
end
|
129
|
-
|
130
|
-
# remove all RDF::OpenAnnotation.hasTarget statements and any other statements associated with body objects
|
131
|
-
def remove_has_target_statements
|
132
|
-
remove_predicate_and_its_object_statements RDF::OpenAnnotation.hasTarget
|
133
|
-
end
|
134
|
-
|
135
|
-
# remove all such predicate statements and any other statements associated with predicates' objects
|
136
|
-
def remove_predicate_and_its_object_statements(predicate)
|
137
|
-
predicate_stmts = @graph.query([nil, predicate, nil])
|
138
|
-
predicate_stmts.each { |pstmt|
|
139
|
-
pred_obj = pstmt.object
|
140
|
-
Triannon::Graph.subject_statements(pred_obj, @graph).each { |s|
|
141
|
-
@graph.delete s
|
142
|
-
} unless !Triannon::Graph.subject_statements(pred_obj, @graph)
|
143
|
-
@graph.delete pstmt
|
144
|
-
}
|
145
|
-
end
|
146
|
-
|
147
|
-
# transform an outer blank node into a null relative URI
|
148
|
-
def make_null_relative_uri_out_of_blank_node
|
149
|
-
anno_stmts = @graph.query([nil, RDF.type, RDF::OpenAnnotation.Annotation])
|
150
|
-
anno_rdf_obj = anno_stmts.first.subject
|
151
|
-
if anno_rdf_obj.is_a?(RDF::Node)
|
152
|
-
# use null relative URI representation of blank node
|
153
|
-
anno_subject = RDF::URI.new
|
154
|
-
else # it's already a URI
|
155
|
-
anno_subject = anno_rdf_obj
|
156
|
-
end
|
157
|
-
Triannon::Graph.subject_statements(anno_rdf_obj, @graph).each { |s|
|
158
|
-
if s.subject == anno_rdf_obj && anno_subject != anno_rdf_obj
|
159
|
-
@graph << RDF::Statement({:subject => anno_subject,
|
160
|
-
:predicate => s.predicate,
|
161
|
-
:object => s.object})
|
162
|
-
@graph.delete s
|
163
|
-
end
|
164
|
-
}
|
165
|
-
end
|
166
|
-
|
167
|
-
# send unknown methods to RDF::Graph
|
168
|
-
def method_missing(sym, *args, &block)
|
169
|
-
@graph.send sym, *args, &block
|
170
|
-
end
|
171
|
-
|
172
|
-
end
|
173
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module Triannon
|
2
|
-
class JsonldContext
|
3
|
-
|
4
|
-
# TODO: perhaps this should no longer be a class -- these could be Triannon constants ...
|
5
|
-
|
6
|
-
OA_CONTEXT_URL = "http://www.w3.org/ns/oa.jsonld"
|
7
|
-
|
8
|
-
OA_DATED_CONTEXT_URL = "http://www.w3.org/ns/oa-context-20130208.json"
|
9
|
-
|
10
|
-
IIIF_CONTEXT_URL = "http://iiif.io/api/presentation/2/context.json"
|
11
|
-
|
12
|
-
end
|
13
|
-
end
|