triannon 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f3fb1a2a5664cb23544e3809666e40fbeac50bf7
4
- data.tar.gz: 530b85774e11c73ad4ace71448e200babf0e2887
3
+ metadata.gz: 0a7836e167aa59510f75b69435f06de72d75a4c6
4
+ data.tar.gz: efc5bc0bff62bfc9347590b2a13c0e144688e2ed
5
5
  SHA512:
6
- metadata.gz: d053edac7a6da6482140dc9c9eb4fda5ea467f772b1cc94a5fc05f0b866e2b2575d81278db451d6101b4856fa9ed4974b9677df28f26801f7483f7be375cba95
7
- data.tar.gz: 88807450e57ec3e5a801b8be3480dee4c4b7f5d2b46401e0abb0cbfdcbcdfa21306933d1d6b0aa521d251602f86df55bb6545e3ed8a9f81bc76323dd2e20d90d
6
+ metadata.gz: 04a8c245627c35a0c1d099a40c1d71138e25964f91f8f329c36b628beddd13eca016ef86cfccac88ec98b8dde7d280c79d19a869062752e901e01146fa862918
7
+ data.tar.gz: 67c3f60fa650ddbcaf6763582f1faf634d4b8766d56ebd3ae505894e96397eab2604d578d92bdb57c6f40da794a55398bdbf3047a8cfb26aad18e7cc9fbbd6e9
data/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  # Triannon
4
4
 
5
- Store Open Annotation in Fedora4 to support the Linked Data for Libraries use cases.
5
+ Store Open Annotation RDF in Fedora4 to support the Linked Data for Libraries use cases.
6
6
 
7
- ## Installation into Your Rails Application
7
+ ## Installation into Your Existing Rails Application
8
8
 
9
9
  Add this line to your Rails application's Gemfile
10
10
 
@@ -12,12 +12,14 @@ Add this line to your Rails application's Gemfile
12
12
  gem 'triannon'
13
13
  ```
14
14
 
15
- Then execute:
15
+ Then install the gems:
16
+
16
17
  ```console
17
18
  $ bundle install
18
19
  ```
19
20
 
20
21
  Then run the triannon generator:
22
+
21
23
  ```console
22
24
  $ rails g triannon:install
23
25
  ```
@@ -27,16 +29,20 @@ Edit the `config/triannon.yml` file:
27
29
  * `ldp:` Properties of LDP server
28
30
  * `url:` the baseurl of LDP server
29
31
  * `uber_container:` name of an LDP Basic Container holding specific anno containers
30
- * `anno_containers:` (Future: the names of LDP Basic Containers holding individual annos)
32
+ * `anno_containers:` (the names of LDP Basic Containers holding individual annos)
31
33
  * `solr_url:` Points to the baseurl of Solr instance configured for Triannon
32
34
  * `triannon_base_url:` Used as the base url for all annotations hosted by your Triannon server. Identifiers from the LDP server will be appended to this base-url. Generally something like "https://your-triannon-rails-box/annotations", as "/annotations" is added to the path by the Triannon gem
33
35
 
34
- Generate the uber root annotations container on your LDP server:
36
+ Generate the root annotations containers on your LDP server:
35
37
 
36
38
  ```console
37
- $ rake triannon:create_uber_root_container
39
+ $ rake triannon:create_root_containers
38
40
  ```
39
41
 
42
+ This will generate the uber_container and the anno_containers (aka 'root containers') under the uber_container.
43
+
44
+ NOTE: you MUST create the root containers before creating any annotations. All annotation MUST be created as a child of a root container.
45
+
40
46
  Set up caching for jsonld context documents:
41
47
 
42
48
  * by using Rack::Cache for RestClient:
@@ -49,9 +55,9 @@ gem 'rack-cache'
49
55
  gem 'rest-client-components'
50
56
  ```
51
57
 
52
- * bundle install
58
+ * bundle install
53
59
 
54
- * create a config/initializers/rest_client.rb
60
+ * create config/initializers/rest_client.rb
55
61
 
56
62
  ```ruby
57
63
  require 'restclient/components'
@@ -78,6 +84,19 @@ Search Parameters:
78
84
  * `bodyKeyword` - matches terms in body characters
79
85
  * `motivatedBy` - matches fragment part of motivation predicate URI, e.g. commenting, tagging, painting
80
86
 
87
+ * use HTTP `Accept` header with mime type to indicate desired format
88
+ * default: jsonld
89
+ * `Accept`: `application/ld+json`
90
+ * also supports turtle, rdfxml, json, html
91
+ * `Accept`: `application/x-turtle`
92
+
93
+ ### Get a list of annos in a particular root container
94
+ as a IIIF Annotation List (see http://iiif.io/api/presentation/2.0/#other-content-resources)
95
+
96
+ * `GET`: `http://(host)/annotations/(root container name)/search?targetUri=some.url.org`
97
+
98
+ Search Parameters as above.
99
+
81
100
  * use HTTP `Accept` header with mime type to indicate desired format
82
101
  * default: jsonld
83
102
  * `Accept`: `application/ld+json`
@@ -85,7 +104,9 @@ Search Parameters:
85
104
  * `Accept`: `application/x-turtle`
86
105
 
87
106
  ### Get a particular anno
88
- `GET`: `http://(host)/annotations/(anno_id)`
107
+ `GET`: `http://(host)/annotations/(root container)/(anno_id)`
108
+
109
+ NOTE: you may need to URL encode the anno_id (e.g. "6f%2F0e%2F79%2F92%2F6f0e7992-83f5-4f31-8bb7-94a23465fdfb" instead of "6f/0e/79/92/6f0e7992-83f5-4f31-8bb7-94a23465fdfb"), particularly from a web browser.
89
110
 
90
111
  * use HTTP `Accept` header with mime type to indicate desired format
91
112
  * default: jsonld
@@ -118,7 +139,7 @@ You can also use either of these methods (with the correct HTTP Accept header):
118
139
  Note that OA (Open Annotation) is the default context if none is specified.
119
140
 
120
141
  ### Create an anno
121
- `POST`: `http://(host)/annotations`
142
+ `POST`: `http://(host)/annotations/(root container)`
122
143
  * the body of the HTTP request should contain the annotation, as jsonld, turtle, or rdfxml
123
144
  * Wrap the annotation in an object, as such:
124
145
  * `{ "commit" => "Create Annotation", "annotation" => { "data" => oa_jsonld } }`
@@ -134,7 +155,9 @@ Note that OA (Open Annotation) is the default context if none is specified.
134
155
  * note that the "type" part is optional and refers to the type of the rel, which is the reference for all json-ld contexts.
135
156
 
136
157
  ### Delete an anno
137
- `DELETE`: `http://(host)/annotations/(anno_id)`
158
+ `DELETE`: `http://(host)/annotations/(root container)/(anno_id)`
159
+
160
+ NOTE: you may need to URL encode the anno_id (e.g. "6f%2F0e%2F79%2F92%2F6f0e7992-83f5-4f31-8bb7-94a23465fdfb" instead of "6f/0e/79/92/6f0e7992-83f5-4f31-8bb7-94a23465fdfb")
138
161
 
139
162
 
140
163
  # Running This Code in Development
@@ -143,71 +166,64 @@ There is a bundled rake task for running triannon in a test rails application, b
143
166
 
144
167
  ## One time setup
145
168
 
146
- ### Set up a local instance of Fedora4
147
- ```console
148
- $ rake jetty:download
149
- $ rake jetty:unzip
150
- $ rake jetty:environment
151
- $ rake triannon:jetty_setup
152
- ```
153
-
154
- triannon:jetty_setup task does the following:
155
- * turns off basic authorization in Fedora4
156
- * sets up a Triannon flavored Solr
157
-
158
169
  ### Set up the testing Rails app that uses triannon gem
170
+
159
171
  ```console
160
172
  $ rake engine_cart:generate # (first run only)
161
173
  ```
162
174
 
163
- ### Start jetty
175
+ ### Set up a local instance of Fedora4 and Solr
176
+
164
177
  ```console
165
- $ rake jetty:start
178
+ $ rake jetty:download
179
+ $ rake jetty:unzip
180
+ $ rake jetty:environment
181
+ $ rake triannon:jetty_config
166
182
  ```
167
183
 
168
- Note that jetty can be very sloooooooow to start up with Fedora and Solr.
169
-
170
- #### Check if Solr is up
171
- Go to http://localhost:8983/solr/#/triannon
172
- or to http://localhost:8983/solr/triannon/select
184
+ triannon:jetty_config task does the following:
185
+ * turns off basic authorization in Fedora4
186
+ * sets up a Triannon flavored Solr core
173
187
 
174
- If all is well, you will not get an error message; the triannon core exists in Solr. If all is not
175
- well, try:
188
+ ### Start jetty
176
189
 
177
190
  ```console
178
- $ rake jetty:stop
179
- $ rake triannon:jetty_setup
180
191
  $ rake jetty:start
181
192
  ```
182
193
 
183
- and then check again.
194
+ Note that jetty can be very sloooooooow (a couple of minutes) to start up with Fedora and Solr.
184
195
 
196
+ #### Check if Solr and Fedora are up
197
+ Go to
198
+ * http://localhost:8983/solr/#/triannon - Solr admin GUI page, you should not see any error text in your browser
199
+ * http://localhost:8983/solr/triannon/select - actual Solr query; should give http status other than 200 if there is a problem
185
200
 
186
- #### Check if Fedora4 is up
187
- Go to http://localhost:8983/fedora/rest/
201
+ Go to
202
+ * http://localhost:8983/fedora/rest/ - you should see a fedora object.
188
203
 
189
- If all is well, you will not get an error message. If all is not well, try:
204
+ If all is not well for Fedora or Solr, try:
190
205
 
191
206
  ```console
192
- $ rake jetty:stop
193
- $ rake jetty:clean
194
- $ rake triannon:jetty_startup
195
- $ rake jetty:start
207
+ $ rake triannon:jetty_reset
196
208
  ```
197
209
 
198
- and check for Solr and Fedora again.
210
+ This stops jetty, cleans out the jetty directory, recreates it anew from the download, configures jetty for Triannon, and starts jetty. It may take a long time (a couple of minutes) for jetty to restart.
211
+
212
+ Then check the Solr and Fedora urls again.
199
213
 
200
- #### Generate uber root annotations container
201
- After you ensure that Fedora4 is running:
214
+
215
+ #### Generate root annotations containers in Fedora
216
+ After you ensure that Fedora is running, you need to create the root anno containers using the configuration of test rails app created by engine_cart:
202
217
 
203
218
  ```console
204
219
  $ cd spec/internal
205
- $ rake triannon:create_uber_root_container
220
+ $ rake triannon:create_root_containers
206
221
  $ cd ../..
207
222
  ```
208
223
 
209
224
  #### Configure spec/internal/config/triannon.yml as specified above
210
- You probably won't need to change this file.
225
+ NOTE: You probably won't need to change this file - it will work with the jetty setup provided.
226
+
211
227
  ```console
212
228
  $ vi spec/internal/config/triannon.yml
213
229
  ```
@@ -221,7 +237,7 @@ $ <cntl + C> # to stop Rails application
221
237
  $ rake jetty:stop # to stop Fedora and Solr
222
238
  ```
223
239
 
224
- The app will be running at localhost:3000
240
+ The app will be running at localhost:3000, with root containers "foo" and "blah" available (and empty).
225
241
 
226
242
  # Running the Tests
227
243
 
@@ -24,11 +24,9 @@ module RdfResponseFormats
24
24
  end
25
25
  end
26
26
 
27
- # parse the Accept HTTP header for the value of profile if it is a request for
28
- # jsonld or json.
29
- # e.g. Accept: application/ld+json; profile="http://www.w3.org/ns/oa-context-20130208.json"
30
- # @return [String] url for jsonld @context or nil if missing or
31
- # non-jsonld/json format
27
+ # parse the Accept HTTP header for the value of profile if it is a request for jsonld or json.
28
+ # e.g. Accept: application/ld+json; profile="http://www.w3.org/ns/oa-context-20130208.json"
29
+ # @return [String] url for jsonld @context or nil if missing or non-jsonld/json format
32
30
  def context_url_from_accept
33
31
  if request.format == "jsonld" || request.format == "json"
34
32
  accept_str = request.accept
@@ -48,12 +46,10 @@ module RdfResponseFormats
48
46
  end
49
47
  end
50
48
 
51
- # parse the Accept HTTP Link for the value of rel if it is a request for
52
- # jsonld or json
53
- # e.g. Link: http://www.w3.org/ns/oa.json; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"
54
- # note that the "type" part is optional
55
- # @return [String] url for jsonld @context or nil if missing or
56
- # non-jsonld/json format
49
+ # parse the Accept HTTP Link for the value of rel if it is a request for jsonld or json
50
+ # e.g. Link: http://www.w3.org/ns/oa.json; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"
51
+ # note that the "type" part is optional
52
+ # @return [String] url for jsonld @context or nil if missing or non-jsonld/json format
57
53
  def context_url_from_link
58
54
  if request.format == "jsonld" || request.format == "json"
59
55
  link_str = request.headers["Link"]
@@ -5,6 +5,7 @@ module Triannon
5
5
  include RdfResponseFormats
6
6
 
7
7
  rescue_from Triannon::LDPStorageError, with: :ldp_storage_error
8
+ rescue_from Triannon::LDPContainerError, with: :ldp_container_error
8
9
  rescue_from Triannon::ExternalReferenceError, with: :ext_ref_error
9
10
  rescue_from Triannon::SearchError, with: :search_error
10
11
  before_action :default_format_jsonld, only: [:show]
@@ -12,7 +13,11 @@ module Triannon
12
13
 
13
14
  # GET /annotations
14
15
  def index
15
- redirect_to "/search"
16
+ if params[:anno_root].present?
17
+ redirect_to "/#{params[:anno_root]}#{search_path}"
18
+ else
19
+ redirect_to search_path
20
+ end
16
21
  end
17
22
 
18
23
  # GET /annotations/1
@@ -29,10 +34,10 @@ module Triannon
29
34
  }
30
35
  format.ttl {
31
36
  accept_return_type = mime_type_from_accept(["application/x-turtle", "text/turtle"])
32
- render :body => @annotation.graph.to_ttl, content_type: accept_return_type if accept_return_type }
37
+ render body: @annotation.graph.to_ttl, content_type: accept_return_type if accept_return_type }
33
38
  format.rdfxml {
34
39
  accept_return_type = mime_type_from_accept(["application/rdf+xml", "text/rdf+xml", "text/rdf"])
35
- render :body => @annotation.graph.to_rdfxml, content_type: accept_return_type if accept_return_type }
40
+ render body: @annotation.graph.to_rdfxml, content_type: accept_return_type if accept_return_type }
36
41
  format.json {
37
42
  accept_return_type = mime_type_from_accept(["application/json", "text/x-json", "application/jsonrequest"])
38
43
  context_url = context_url_from_link ? context_url_from_link : context_url_from_accept
@@ -44,7 +49,7 @@ module Triannon
44
49
  }
45
50
  format.xml {
46
51
  accept_return_type = mime_type_from_accept(["application/xml", "text/xml", "application/x-xml"])
47
- render :xml => @annotation.graph.to_rdfxml, content_type: accept_return_type if accept_return_type }
52
+ render xml: @annotation.graph.to_rdfxml, content_type: accept_return_type if accept_return_type }
48
53
  format.html { render :show }
49
54
  end
50
55
  end
@@ -68,12 +73,12 @@ module Triannon
68
73
  # it's from app html form
69
74
  params.require(:annotation).permit(:data)
70
75
  if params["annotation"]["data"]
71
- @annotation = Annotation.new({:data => params["annotation"]["data"]})
76
+ @annotation = Annotation.new(data: params["annotation"]["data"], root_container: params[:anno_root])
72
77
  end
73
78
  else
74
79
  # it's a direct post request
75
80
  content_type = request.headers["Content-Type"]
76
- @annotation = Annotation.new({:data => request.body.read, :expected_content_type => content_type})
81
+ @annotation = Annotation.new(data: request.body.read, expected_content_type: content_type, root_container: params[:anno_root])
77
82
  end
78
83
 
79
84
  if @annotation.save
@@ -83,30 +88,30 @@ module Triannon
83
88
  format.jsonld {
84
89
  context_url = context_url_from_link ? context_url_from_link : context_url_from_accept
85
90
  if context_url && context_url == OA::Graph::IIIF_CONTEXT_URL
86
- render :json => @annotation.jsonld_iiif, status: 201, content_type: "application/ld+json"
91
+ render json: @annotation.jsonld_iiif, status: 201, content_type: "application/ld+json"
87
92
  else
88
- render :json => @annotation.jsonld_oa, status: 201, content_type: "application/ld+json"
93
+ render json: @annotation.jsonld_oa, status: 201, content_type: "application/ld+json"
89
94
  end
90
95
  }
91
96
  format.ttl {
92
97
  accept_return_type = mime_type_from_accept(["application/x-turtle", "text/turtle"])
93
- render :body => @annotation.graph.to_ttl, status: 201, content_type: accept_return_type if accept_return_type }
98
+ render body: @annotation.graph.to_ttl, status: 201, content_type: accept_return_type if accept_return_type }
94
99
  format.rdfxml {
95
100
  accept_return_type = mime_type_from_accept(["application/rdf+xml", "text/rdf+xml", "text/rdf"])
96
- render :body => @annotation.graph.to_rdfxml, status: 201, content_type: accept_return_type if accept_return_type }
101
+ render body: @annotation.graph.to_rdfxml, status: 201, content_type: accept_return_type if accept_return_type }
97
102
  format.json {
98
103
  accept_return_type = mime_type_from_accept(["application/json", "text/x-json", "application/jsonrequest"])
99
104
  context_url = context_url_from_link ? context_url_from_link : context_url_from_accept
100
105
  if context_url && context_url == OA::Graph::IIIF_CONTEXT_URL
101
- render :json => @annotation.jsonld_iiif, status: 201, content_type: accept_return_type if accept_return_type
106
+ render json: @annotation.jsonld_iiif, status: 201, content_type: accept_return_type if accept_return_type
102
107
  else
103
- render :json => @annotation.jsonld_oa, status: 201, content_type: accept_return_type if accept_return_type
108
+ render json: @annotation.jsonld_oa, status: 201, content_type: accept_return_type if accept_return_type
104
109
  end
105
110
  }
106
111
  format.xml {
107
112
  accept_return_type = mime_type_from_accept(["application/xml", "text/xml", "application/x-xml"])
108
- render :body => @annotation.graph.to_rdfxml, status: 201, content_type: accept_return_type if accept_return_type }
109
- format.html { redirect_to @annotation }
113
+ render body: @annotation.graph.to_rdfxml, status: 201, content_type: accept_return_type if accept_return_type }
114
+ format.html { redirect_to annotations_path(anno_root: params[:anno_root], id: @annotation.id) }
110
115
  end
111
116
  else
112
117
  render :new, status: 400
@@ -126,13 +131,13 @@ module Triannon
126
131
  # DELETE /annotations/1
127
132
  def destroy
128
133
  @annotation.destroy
129
- redirect_to annotations_url, status: 204, notice: 'Annotation was successfully destroyed.'
134
+ redirect_to annotations_path(anno_root: params[:anno_root]), status: 204, notice: 'Annotation was successfully destroyed.'
130
135
  end
131
136
 
132
137
  private
133
138
 
134
139
  def set_annotation
135
- @annotation = Annotation.find(params[:id])
140
+ @annotation = Annotation.find(params[:anno_root], params[:id])
136
141
  end
137
142
 
138
143
  # render Triannon::ExternalReferenceError
@@ -140,14 +145,19 @@ private
140
145
  render plain: err.message, status: 403
141
146
  end
142
147
 
148
+ # render Triannon::LDPContainer error
149
+ def ldp_container_error(err)
150
+ render plain: err.message, status: 403
151
+ end
152
+
143
153
  # render Triannon::LDPStorage error
144
154
  def ldp_storage_error(err)
145
- render :body => "<h2>#{err.message}</h2>" + err.ldp_resp_body, status: err.ldp_resp_status, content_type: "text/html"
155
+ render body: "<h2>#{err.message}</h2>" + err.ldp_resp_body, status: err.ldp_resp_status, content_type: "text/html"
146
156
  end
147
157
 
148
158
  # render Triannon::SearchError
149
159
  def search_error(err)
150
- render :body => "<h2>#{err.message}</h2>" + (err.search_resp_body ? err.search_resp_body : ""),
160
+ render body: "<h2>#{err.message}</h2>" + (err.search_resp_body ? err.search_resp_body : ""),
151
161
  status: err.search_resp_status ? err.search_resp_status : 400,
152
162
  content_type: "text/html"
153
163
  end
@@ -159,21 +169,21 @@ private
159
169
  case req_context
160
170
  when "iiif", "IIIF"
161
171
  if mime_type
162
- render :json => @annotation.jsonld_iiif, content_type: mime_type
172
+ render json: @annotation.jsonld_iiif, content_type: mime_type
163
173
  else
164
- render :json => @annotation.jsonld_iiif
174
+ render json: @annotation.jsonld_iiif
165
175
  end
166
176
  when "oa", "OA"
167
177
  if mime_type
168
- render :json => @annotation.jsonld_oa, content_type: mime_type
178
+ render json: @annotation.jsonld_oa, content_type: mime_type
169
179
  else
170
- render :json => @annotation.jsonld_oa
180
+ render json: @annotation.jsonld_oa
171
181
  end
172
182
  else
173
183
  if mime_type
174
- render :json => @annotation.jsonld_oa, content_type: mime_type
184
+ render json: @annotation.jsonld_oa, content_type: mime_type
175
185
  else
176
- render :json => @annotation.jsonld_oa
186
+ render json: @annotation.jsonld_oa
177
187
  end
178
188
  end
179
189
  end
@@ -6,11 +6,11 @@ module Triannon
6
6
  after_save :solr_save
7
7
  after_destroy :solr_delete
8
8
 
9
- attr_accessor :id, :data, :expected_content_type
9
+ attr_accessor :id, :data, :expected_content_type, :root_container
10
10
 
11
- validates_each :data do |record, attr, value|
12
- record.errors.add attr, 'less than 30 chars' if value.to_s.length < 30
13
- end
11
+ validates :data, :root_container, presence: true
12
+ # TODO: ensure root container exists in LDP store?? seems too expensive
13
+ validates :data, length: {minimum: 30}
14
14
 
15
15
  # full validation should be optional?
16
16
  # minimal: a subject with the right type and a hasTarget? (see url)
@@ -26,36 +26,33 @@ module Triannon
26
26
  a
27
27
  end
28
28
 
29
+ # @param [String] root_container - LDP parent container for annotation
29
30
  # @param [String] id the unique id of the annotation. Can include base_uri prefix or omit it.
30
- def self.find(id)
31
- oa_graph = Triannon::LdpLoader.load id
31
+ def self.find(root_container, id)
32
+ oa_graph = Triannon::LdpLoader.load(root_container, id)
32
33
  anno = Triannon::Annotation.new
33
34
  anno.graph = oa_graph
34
35
  anno.id = id
36
+ anno.root_container = root_container
35
37
  anno
36
38
  end
37
39
 
38
- # @deprecated - was used by old annotations#index action, before redirect to search (2015-04)
39
- def self.all
40
- Triannon::LdpLoader.find_all
41
- end
42
-
43
40
  # Instance Methods ----------------------------------------------------------------
44
41
 
45
42
  def save
46
43
  _run_save_callbacks do
47
44
  # TODO: check if valid anno?
48
- @id = Triannon::LdpWriter.create_anno self if graph && graph.size > 2
45
+ @id = Triannon::LdpWriter.create_anno(self, root_container) if graph && graph.size > 2
49
46
  # reload from storage to get the anno id within the graph
50
47
  # TODO: do graph manipulation to add id instead?
51
- @graph = Triannon::LdpLoader.load id
48
+ @graph = Triannon::LdpLoader.load(root_container, id)
52
49
  id
53
50
  end
54
51
  end
55
52
 
56
53
  def destroy
57
54
  _run_destroy_callbacks do
58
- Triannon::LdpWriter.delete_anno @id
55
+ Triannon::LdpWriter.delete_anno "#{root_container}/#{id}"
59
56
  end
60
57
  end
61
58
 
@@ -103,12 +100,12 @@ protected
103
100
 
104
101
  # Add annotation to Solr as a Solr document
105
102
  def solr_save
106
- solr_writer.write(graph) if id_as_url && !id_as_url.empty?
103
+ solr_writer.write(graph, root_container) if id_as_url.present?
107
104
  end
108
105
 
109
106
  # Delete annotation from Solr
110
107
  def solr_delete
111
- solr_writer.delete(id) if id
108
+ solr_writer.delete("#{root_container}/#{id}") if id.present?
112
109
  end
113
110
 
114
111
  private