triannon 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,4 +24,4 @@
24
24
  <%= @annotation.jsonld_iiif %>
25
25
  </pre>
26
26
 
27
- <%= link_to "Back to List", annotations_path %>
27
+ <%= link_to "Back to List", annotations_path(anno_root: @annotation.root_container) %>
data/config/routes.rb CHANGED
@@ -1,31 +1,82 @@
1
1
  Triannon::Engine.routes.draw do
2
2
 
3
- resources :annotations, except: [:update, :edit],
4
- # show action must explicitly forbid "new", "iiif" and "oa" as id values; couldn't
5
- # figure out how to do it with regexp constraint since beginning and end regex
6
- # matchers aren't allowed when enforcing formats for segment (e.g. :id)
7
- constraints: lambda { |request|
8
- id = request.env["action_dispatch.request.path_parameters"][:id]
9
- id !~ /^iiif$/ && id !~ /^oa$/ && id !~ /^search$/
10
- } do
11
- collection do
12
- get 'search', to: 'search#find'
13
- end
14
- end
3
+ # 1. can't use resourceful routing because of :anno_root (dynamic path segment)
15
4
 
5
+ # 2. couldn't figure out how to exclude specific values with regexp constraint since beginning and end regex matchers
6
+ # aren't allowed when enforcing formats for path segment (i.e. :anno_root, :id)
7
+
8
+ # get -> new action
9
+ get '/annotations/:anno_root/new', to: 'annotations#new'
10
+ get '/:anno_root/new', to: 'annotations#new',
11
+ constraints: lambda { |request|
12
+ anno_root = request.path_parameters[:anno_root]
13
+ id = request.path_parameters[:id]
14
+ anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/ && id !~ /^search$/ && id !~ /^new$/
15
+ }
16
+
17
+ # get -> search controller find action
18
+ get '/annotations/:anno_root/search', to: 'search#find'
19
+ get '/annotations/search', to: 'search#find'
20
+ get '/:anno_root/search', to: 'search#find',
21
+ constraints: lambda { |request|
22
+ anno_root = request.path_parameters[:anno_root]
23
+ anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/
24
+ }
16
25
  get '/search', to: 'search#find'
17
26
 
18
- root to: 'search#find'
27
+ # get w id -> show action
28
+ get '/annotations/:anno_root/:id(.:format)', to: 'annotations#show',
29
+ constraints: lambda { |request|
30
+ anno_root = request.path_parameters[:anno_root]
31
+ anno_root !~ /^search$/ && anno_root !~ /^new$/
32
+ }
33
+ get '/:anno_root/:id(.:format)', to: 'annotations#show',
34
+ constraints: lambda { |request|
35
+ anno_root = request.path_parameters[:anno_root]
36
+ id = request.path_parameters[:id]
37
+ anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/ && id !~ /^search$/ && id !~ /^new$/
38
+ }
19
39
 
20
- # allow jsonld context in path (only allow iiif or oa as values)
21
- # must explicitly forbid "new" as id values; couldn't figure
22
- # out how to do it with regexp constraint since beginning and end regex
23
- # matchers aren't allowed when enforcing formats for segment (e.g. :id)
24
- get '/annotations/:jsonld_context/:id(.:format)', to: 'annotations#show',
40
+ # get no id -> index action
41
+ get '/annotations/:anno_root', to: 'annotations#index',
25
42
  constraints: lambda { |request|
26
- jsonld_context = request.env["action_dispatch.request.path_parameters"][:jsonld_context]
27
- id = request.env["action_dispatch.request.path_parameters"][:id]
28
- (jsonld_context =~ /^iiif$/ || jsonld_context =~ /^oa$/ ) && id !~ /^new$/
29
- }
43
+ anno_root = request.path_parameters[:anno_root]
44
+ anno_root !~ /^search$/ && anno_root !~ /^new$/
45
+ }
46
+ get '/:anno_root', to: 'annotations#index',
47
+ constraints: lambda { |request|
48
+ anno_root = request.path_parameters[:anno_root]
49
+ anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/
50
+ }
51
+
52
+ # post -> create action
53
+ post '/annotations/:anno_root', to: 'annotations#create',
54
+ constraints: lambda { |request|
55
+ anno_root = request.path_parameters[:anno_root]
56
+ id = request.path_parameters[:id]
57
+ anno_root !~ /^search$/ && anno_root !~ /^new$/ && id !~ /^search$/ && id !~ /^new$/
58
+ }
59
+ post '/:anno_root', to: 'annotations#create',
60
+ constraints: lambda { |request|
61
+ anno_root = request.path_parameters[:anno_root]
62
+ anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/
63
+ }
64
+
65
+ # delete -> destroy action
66
+ delete '/annotations/:anno_root/:id(.:format)', to: 'annotations#destroy',
67
+ constraints: lambda { |request|
68
+ anno_root = request.path_parameters[:anno_root]
69
+ id = request.path_parameters[:id]
70
+ anno_root !~ /^search$/ && anno_root !~ /^new$/ && id !~ /^search$/ && id !~ /^new$/
71
+ }
72
+ delete '/:anno_root/:id(.:format)', to: 'annotations#destroy',
73
+ constraints: lambda { |request|
74
+ anno_root = request.path_parameters[:anno_root]
75
+ anno_root !~ /^annotations$/ && anno_root !~ /^search$/ && anno_root !~ /^new$/
76
+ }
77
+
78
+
79
+ get '/annotations', to: 'search#find'
80
+ root to: 'search#find'
30
81
 
31
82
  end
@@ -0,0 +1,25 @@
1
+ # Logging level
2
+ solr.log=logs/
3
+ log4j.rootLogger=INFO, file, CONSOLE
4
+
5
+ # Log warnings to the console
6
+ log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
7
+ log4j.appender.CONSOLE.Threshold=WARN
8
+ log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
9
+ log4j.appender.CONSOLE.layout.ConversionPattern=%-4r [%t] %-5p %c %x \u2013 %m%n
10
+
11
+ #- size rotation with log cleanup.
12
+ log4j.appender.file=org.apache.log4j.RollingFileAppender
13
+ log4j.appender.file.MaxFileSize=4MB
14
+ log4j.appender.file.MaxBackupIndex=9
15
+
16
+ #- File to log to and log format
17
+ log4j.appender.file.File=${solr.log}/solr.log
18
+ log4j.appender.file.layout=org.apache.log4j.PatternLayout
19
+ log4j.appender.file.layout.ConversionPattern=%-5p - %d{yyyy-MM-dd HH:mm:ss.SSS}; %C; %m\n
20
+
21
+ log4j.logger.org.apache.zookeeper=WARN
22
+ log4j.logger.org.apache.hadoop=WARN
23
+
24
+ # set to INFO to enable infostream log messages
25
+ log4j.logger.org.apache.solr.update.LoggingInfoStream=OFF
data/config/solr/solr.xml CHANGED
@@ -29,8 +29,10 @@
29
29
  If 'null' (or absent), cores will not be manageable via REST
30
30
  -->
31
31
  <cores adminPath="/admin/cores" defaultCoreName="development">
32
+ <!-- don't need development or test cores for triannon
32
33
  <core name="development" instanceDir="development-core" />
33
34
  <core name="test" instanceDir="test-core" />
35
+ -->
34
36
  <core name="triannon" instanceDir="triannon-core" />
35
37
  </cores>
36
38
  </solr>
@@ -10,6 +10,8 @@
10
10
  <field name="id" type="string" stored="true" indexed="true" multiValued="false" required="true"/>
11
11
  <field name="timestamp" type="date" stored="true" indexed="true" multiValued="false" default="NOW"/>
12
12
 
13
+ <field name="root" type="string" stored="true" indexed="true" multiValued="false"/>
14
+
13
15
  <field name="motivation" type="string" stored="true" indexed="true" multiValued="true"/>
14
16
  <!-- date field format: 1995-12-31T23:59:59Z; or w fractional seconds: 1995-12-31T23:59:59.999Z -->
15
17
  <field name="annotated_at" type="date" stored="true" indexed="true" multiValued="false"/>
@@ -4,11 +4,15 @@
4
4
  this file, see http://wiki.apache.org/solr/SolrConfigXml.
5
5
  -->
6
6
  <config>
7
- <luceneMatchVersion>4.7</luceneMatchVersion>
7
+ <luceneMatchVersion>4.10.4</luceneMatchVersion>
8
+
9
+ <!-- solr lib dirs -->
10
+ <lib dir="../lib/contrib/analysis-extras/lib" />
11
+ <lib dir="../lib/contrib/analysis-extras/lucene-libs" />
8
12
 
9
13
  <dataDir>${solr.data.dir:}</dataDir>
10
14
 
11
- <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/>
15
+ <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.StandardDirectoryFactory}"/>
12
16
  <codecFactory class="solr.SchemaCodecFactory"/>
13
17
  <schemaFactory class="ClassicIndexSchemaFactory"/>
14
18
 
@@ -24,7 +28,7 @@
24
28
  <str name="dir">${solr.data.dir:}</str>
25
29
  </updateLog>
26
30
  <autoCommit>
27
- <maxTime>15000</maxTime>
31
+ <maxTime>3000</maxTime>
28
32
  <openSearcher>false</openSearcher>
29
33
  </autoCommit>
30
34
  </updateHandler>
@@ -42,21 +46,23 @@
42
46
  It should only have the most common facets -->
43
47
  <listener event="newSearcher" class="solr.QuerySenderListener">
44
48
  <arr name="queries">
45
- <lst>
49
+ <lst>
46
50
  <!-- default query for all objects: populate facet caches -->
47
51
  <int name="rows">0</int>
48
52
  <str name="fl">score</str>
49
53
  <bool name="facet">true</bool>
50
54
  <int name="facet.mincount">1</int>
55
+ <str name="facet.field">root</str>
56
+ <str name="f.root.facet.method">enum</str>
51
57
  <str name="facet.field">motivation</str>
52
- <str name="f.motivation.facet.method">enum</str>
58
+ <str name="f.motivation.facet.method">enum</str>
53
59
  <str name="facet.field">target_type</str>
54
60
  <str name="f.target_type.facet.method">enum</str>
55
61
  <str name="facet.field">body_type</str>
56
62
  <str name="f.body_type.facet.method">enum</str>
57
63
  <str name="facet.field">annotated_at_tdate</str>
58
64
  </lst>
59
- <lst>
65
+ <lst>
60
66
  <!-- single object query: populate filter and fieldValue caches -->
61
67
  <str name="q">id:a*</str>
62
68
  <str name="defType">lucene</str>
@@ -64,11 +70,13 @@
64
70
  <str name="fl">score</str>
65
71
  <bool name="facet">true</bool>
66
72
  <int name="facet.mincount">1</int>
73
+ <str name="facet.field">root</str>
74
+ <str name="f.root.facet.method">enum</str>
67
75
  <str name="facet.field">motivation</str>
68
76
  <str name="f.motivation.facet.method">enum</str>
69
77
  <str name="facet.field">target_type</str>
70
78
  <str name="f.target_type.facet.method">enum</str>
71
- <str name="facet.field">body_type</str>
79
+ <str name="facet.field">body_type</str>
72
80
  <str name="f.body_type.facet.method">enum</str>
73
81
  <str name="facet.field">annotated_at_tdate</str>
74
82
  </lst>
@@ -78,20 +86,22 @@
78
86
  <!-- A First Searcher is opened when there is _no_ existing (current) Searcher. ("fast warmup") -->
79
87
  <listener event="firstSearcher" class="solr.QuerySenderListener">
80
88
  <arr name="queries">
81
- <lst>
89
+ <lst>
82
90
  <!-- default query for all objects: populate facet caches -->
83
91
  <int name="rows">0</int>
84
92
  <str name="fl">score</str>
85
93
  <bool name="facet">true</bool>
86
94
  <int name="facet.mincount">1</int>
95
+ <str name="facet.field">root</str>
96
+ <str name="f.root.facet.method">enum</str>
87
97
  <str name="facet.field">motivation</str>
88
98
  <str name="f.motivation.facet.method">enum</str>
89
99
  <str name="facet.field">target_type</str>
90
100
  <str name="f.target_type.facet.method">enum</str>
91
- <str name="facet.field">body_type</str>
101
+ <str name="facet.field">body_type</str>
92
102
  <str name="f.body_type.facet.method">enum</str>
93
103
  </lst>
94
- <lst>
104
+ <lst>
95
105
  <!-- single object query: populate filter and fieldValue caches -->
96
106
  <str name="q">id:a*</str>
97
107
  <str name="defType">lucene</str>
@@ -99,11 +109,13 @@
99
109
  <str name="fl">score</str>
100
110
  <bool name="facet">true</bool>
101
111
  <int name="facet.mincount">1</int>
112
+ <str name="facet.field">root</str>
113
+ <str name="f.root.facet.method">enum</str>
102
114
  <str name="facet.field">motivation</str>
103
115
  <str name="f.motivation.facet.method">enum</str>
104
116
  <str name="facet.field">target_type</str>
105
117
  <str name="f.target_type.facet.method">enum</str>
106
- <str name="facet.field">body_type</str>
118
+ <str name="facet.field">body_type</str>
107
119
  <str name="f.body_type.facet.method">enum</str>
108
120
  </lst>
109
121
  </arr>
@@ -123,9 +135,9 @@
123
135
  <requestHandler name="/select" class="solr.SearchHandler" default="true">
124
136
  <lst name="defaults">
125
137
  <str name="echoParams">explicit</str>
126
- <str name="sort">score desc, annotated_at_tdate desc</str>
127
- <int name="rows">20</int>
128
- <str name="fl">* score</str>
138
+ <str name="sort">score desc, annotated_at_tdate desc</str>
139
+ <int name="rows">2500</int>
140
+ <str name="fl">* score</str>
129
141
  <str name="wt">ruby</str>
130
142
  <str name="indent">true</str>
131
143
 
@@ -140,46 +152,48 @@
140
152
  <str name="df">anno_jsonld</str>
141
153
  <str name="q.op">AND</str>
142
154
 
143
- <str name="qf">
155
+ <str name="qf">
144
156
  body_chars_exact^3
145
157
  body_chars_unstem^2
146
158
  body_chars_stem
147
- annotated_by_unstem^2
148
- annotated_by_stem
149
- target_url
150
- body_url
151
- motivation
152
- id
153
- </str>
154
- <str name="pf"> <!-- (phrase boost within result set) -->
155
- body_chars_exact^15
159
+ annotated_by_unstem^2
160
+ annotated_by_stem
161
+ target_url
162
+ body_url
163
+ motivation
164
+ id
165
+ </str>
166
+ <str name="pf"> <!-- (phrase boost within result set) -->
167
+ body_chars_exact^15
156
168
  body_chars_unstem^10
157
169
  body_chars_stem^5
158
170
  annotated_by_unstem^10
159
171
  annotated_by_stem^5
160
- </str>
161
- <str name="pf3"> <!-- (token trigrams boost within result set) -->
172
+ </str>
173
+ <str name="pf3"> <!-- (token trigrams boost within result set) -->
162
174
  body_chars_exact^9
163
175
  body_chars_unstem^6
164
176
  body_chars_stem^3
165
177
  annotated_by_unstem^6
166
178
  annotated_by_stem^3
167
- </str>
168
- <str name="pf2"> <!--(token bigrams boost within result set) -->
179
+ </str>
180
+ <str name="pf2"> <!--(token bigrams boost within result set) -->
169
181
  body_chars_exact^6
170
182
  body_chars_unstem^4
171
183
  body_chars_stem^2
172
184
  annotated_by_unstem^4
173
185
  annotated_by_stem^2
174
- </str>
186
+ </str>
175
187
 
176
- <bool name="facet">true</bool>
188
+ <bool name="facet">true</bool>
177
189
  <int name="facet.mincount">1</int>
190
+ <str name="facet.field">root</str>
191
+ <str name="f.root.facet.method">enum</str>
178
192
  <str name="facet.field">motivation</str>
179
193
  <str name="f.motivation.facet.method">enum</str>
180
194
  <str name="facet.field">target_type</str>
181
195
  <str name="f.target_type.facet.method">enum</str>
182
- <str name="facet.field">body_type</str>
196
+ <str name="facet.field">body_type</str>
183
197
  <str name="f.body_type.facet.method">enum</str>
184
198
  <str name="facet.field">annotated_at_tdate</str>
185
199
 
@@ -191,7 +205,7 @@
191
205
  <lst name="defaults">
192
206
  <str name="echoParams">explicit</str>
193
207
  <str name="fl">*</str>
194
- <int name="rows">1</int>
208
+ <int name="rows">10</int> <!-- just in case; expecting 1 -->
195
209
  <str name="q">{!raw f=id v=$id}</str> <!-- use id=666 instead of q=id:666 -->
196
210
  <str name="wt">ruby</str>
197
211
  <str name="indent">true</str>
@@ -236,4 +250,3 @@
236
250
  </admin>
237
251
 
238
252
  </config>
239
-
@@ -1,25 +1,47 @@
1
1
  require_relative '../../app/services/triannon/ldp_writer'
2
2
 
3
3
  namespace :triannon do
4
- desc "set up jetty for triannon"
5
- task :jetty_setup => [:solr_jetty_setup, :disable_fedora_auth_in_jetty]
4
+ desc "clean out then reset jetty from scratch for Triannon - starts jetty"
5
+ task :jetty_reset => ['jetty:stop', 'jetty:clean', 'jetty:environment', :jetty_config, 'jetty:start']
6
6
 
7
- desc "set up triannon Solr in jetty"
8
- task :solr_jetty_setup do
7
+ desc "configure Fedora and Solr in jetty for triannon"
8
+ task :jetty_config => [:solr_jetty_config, :disable_fedora_auth_in_jetty]
9
+
10
+ # don't display this in rake -T
11
+ #desc "set up triannon core in jetty Solr"
12
+ task :solr_jetty_config do
9
13
  `cp -r config/solr/triannon-core jetty/solr`
10
14
  `cp config/solr/solr.xml jetty/solr`
15
+ `cp config/solr/log4j.properties jetty/resources`
11
16
  end
12
17
 
13
- desc "disable fedora basic authorization in jetty"
18
+ # don't display this in rake -T
19
+ #desc "disable fedora basic authorization in jetty"
14
20
  task :disable_fedora_auth_in_jetty do
15
21
  `cp config/jetty/etc/* jetty/etc`
16
22
  end
17
23
 
18
- desc 'Create the uber root annotation container'
24
+
25
+ # ------- root container tasks ----------
26
+
27
+ # don't display this in rake -T
28
+ #desc 'ONLY WORKS WITHIN RAILS APP: Create the uber root annotation container per triannon.yml'
19
29
  task :create_uber_root_container do
20
30
  unless File.exist? Triannon.triannon_file
21
- puts "Triannon config file missing: #{Triannon.triannon_file}"
31
+ puts "ERROR: Triannon config file missing: #{Triannon.triannon_file} - are you in the rails app root directory?"
32
+ raise "Triannon config file missing: #{Triannon.triannon_file}"
22
33
  end
23
34
  Triannon::LdpWriter.create_basic_container(nil, Triannon.config[:ldp]['uber_container'])
24
35
  end
25
- end
36
+
37
+ desc "ONLY WORKS WITHIN RAILS APP: Create root anno containers per triannon.yml"
38
+ task :create_root_containers => :create_uber_root_container do
39
+ unless File.exist? Triannon.triannon_file
40
+ puts "ERROR: Triannon config file missing: #{Triannon.triannon_file} - are you in the rails app root directory?"
41
+ raise "Triannon config file missing: #{Triannon.triannon_file}"
42
+ end
43
+ Triannon.config[:ldp]['anno_containers'].each { |container_name|
44
+ Triannon::LdpWriter.create_basic_container(Triannon.config[:ldp]['uber_container'], container_name)
45
+ }
46
+ end
47
+ end # namespace triannon
data/lib/triannon.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'linkeddata'
2
2
  require 'oa/graph'
3
- require 'rdf/iiif'
4
3
  require 'rdf/triannon_vocab'
5
4
  require 'bootstrap-sass'
6
5
  require 'faraday' # for writing to LDP store
@@ -9,6 +9,20 @@ module Triannon
9
9
  end
10
10
  end
11
11
 
12
+ # general error for LDP anno root container issues
13
+ class LDPContainerError < Triannon::Error
14
+ def initialize(message = nil)
15
+ super(message)
16
+ end
17
+ end
18
+
19
+ # used when LDP anno root container doesn't exist
20
+ class MissingLDPContainerError < Triannon::LDPContainerError
21
+ def initialize(message = nil)
22
+ super(message)
23
+ end
24
+ end
25
+
12
26
  # used to keep HTTP response info from LDP
13
27
  class LDPStorageError < Triannon::Error
14
28
  attr_accessor :ldp_resp_status, :ldp_resp_body
@@ -1,3 +1,3 @@
1
1
  module Triannon
2
- VERSION = "1.1.0"
2
+ VERSION = "2.0.0"
3
3
  end