iqvoc 4.7.0 → 4.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/Gemfile +11 -11
  4. data/Gemfile.lock +178 -122
  5. data/README.md +39 -24
  6. data/{test/performance/browsing_test.rb → app/aides/inline_data_helper.rb} +23 -6
  7. data/app/aides/maker.rb +139 -0
  8. data/{lib → app/aides}/multi_logger.rb +0 -0
  9. data/app/aides/origin.rb +47 -0
  10. data/app/aides/rdfapi.rb +59 -0
  11. data/app/aides/skos_exporter.rb +151 -0
  12. data/app/aides/skos_importer.rb +348 -0
  13. data/app/assets/javascripts/iqvoc/entityselect.js.erb +7 -9
  14. data/app/controllers/application_controller.rb +1 -3
  15. data/app/controllers/collections/versions_controller.rb +1 -3
  16. data/app/controllers/concepts/versions_controller.rb +9 -3
  17. data/app/controllers/concerns/controller_extensions.rb +109 -0
  18. data/app/{concerns → controllers/concerns}/reverse_match_errors.rb +0 -0
  19. data/app/controllers/hierarchy_controller.rb +7 -3
  20. data/app/controllers/instance_configuration_controller.rb +1 -1
  21. data/app/controllers/pages_controller.rb +10 -0
  22. data/app/controllers/search_results_controller.rb +2 -2
  23. data/app/controllers/triplestore_sync_controller.rb +2 -4
  24. data/app/helpers/application_helper.rb +1 -1
  25. data/app/helpers/widget_helper.rb +3 -3
  26. data/app/jobs/export_job.rb +1 -3
  27. data/app/jobs/import_job.rb +1 -3
  28. data/app/models/ability.rb +59 -0
  29. data/app/models/abstract_user.rb +1 -1
  30. data/app/models/collection/base.rb +12 -3
  31. data/app/models/collection/member/skos/base.rb +1 -1
  32. data/app/models/concept/base.rb +15 -8
  33. data/app/models/concept/relation/base.rb +1 -1
  34. data/app/models/concept/relation/skos/base.rb +1 -1
  35. data/app/models/concept/skos/scheme.rb +1 -1
  36. data/app/models/concept/validations.rb +1 -1
  37. data/app/models/concerns/deep_cloning.rb +92 -0
  38. data/app/models/concerns/first_level_object_scopes.rb +9 -0
  39. data/app/{concerns → models/concerns}/first_level_object_validations.rb +9 -2
  40. data/app/models/concerns/rankable.rb +31 -0
  41. data/app/models/{search_extension.rb → concerns/search_extension.rb} +0 -0
  42. data/app/{concerns → models/concerns}/versioning.rb +0 -6
  43. data/app/models/configuration_setting.rb +1 -1
  44. data/app/models/labeling/skos/base.rb +2 -2
  45. data/app/models/match/skos/base.rb +2 -2
  46. data/app/models/note/skos/base.rb +7 -6
  47. data/app/models/note/skos/change_note.rb +1 -1
  48. data/{lib/iqvoc/rdf_sync.rb → app/services/rdf_sync_service.rb} +3 -3
  49. data/app/view_models/concept_view.rb +1 -1
  50. data/app/views/collections/_form.html.erb +2 -2
  51. data/app/views/concepts/scheme/edit.html.erb +1 -1
  52. data/app/views/pages/components.html.erb +45 -0
  53. data/app/views/pages/version.html.erb +6 -0
  54. data/app/views/partials/concept/_reverse_match_notice.html.erb +0 -1
  55. data/app/views/search_results/_sidebar.html.erb +3 -3
  56. data/config/application.rb +4 -1
  57. data/config/boot.rb +1 -2
  58. data/config/database.yml.postgresql +23 -0
  59. data/config/engine.rb +0 -2
  60. data/config/environments/heroku.rb +1 -1
  61. data/config/initializers/inflections.rb +9 -3
  62. data/config/initializers/iqvoc.rb +1 -7
  63. data/config/initializers/mime_types.rb +0 -1
  64. data/config/locales/de.yml +2 -1
  65. data/config/locales/en.yml +11 -10
  66. data/config/routes.rb +2 -0
  67. data/config/travis/database.yml.mysql +9 -0
  68. data/config/travis/database.yml.postgresql +7 -0
  69. data/config/travis/database.yml.sqlite +5 -0
  70. data/db/migrate/20141204151558_add_foreign_key_constraints.rb +23 -0
  71. data/iqvoc.gemspec +2 -2
  72. data/lib/generators/app/template.rb +15 -7
  73. data/lib/iqvoc.rb +2 -1
  74. data/lib/iqvoc/configuration/core.rb +18 -4
  75. data/lib/iqvoc/configuration/instance_configuration.rb +125 -0
  76. data/lib/iqvoc/configuration/navigation.rb +63 -0
  77. data/lib/iqvoc/environments/development.rb +4 -0
  78. data/lib/iqvoc/environments/production.rb +11 -12
  79. data/lib/iqvoc/environments/test.rb +4 -1
  80. data/lib/iqvoc/version.rb +2 -2
  81. data/lib/tasks/exporter.rake +1 -4
  82. data/lib/tasks/importer.rake +1 -5
  83. data/lib/tasks/sync.rake +1 -2
  84. data/test/controllers/concept_movement_test.rb +11 -11
  85. data/test/controllers/hierarchy_test.rb +83 -79
  86. data/test/controllers/reverse_match_test.rb +2 -2
  87. data/test/integration/alphabetical_test.rb +2 -3
  88. data/test/integration/browse_concepts_and_labels_test.rb +2 -2
  89. data/test/integration/collection_circularity_test.rb +6 -6
  90. data/test/integration/concept_scheme_browsing_test.rb +2 -2
  91. data/test/integration/edit_concepts_test.rb +1 -1
  92. data/test/integration/export_test.rb +5 -3
  93. data/test/integration/import_test.rb +4 -1
  94. data/test/integration/instance_configuration_browsing_test.rb +2 -2
  95. data/test/integration/navigation_test.rb +2 -2
  96. data/test/integration/note_annotations_test.rb +12 -11
  97. data/test/integration/reverse_match_job_test.rb +19 -10
  98. data/test/integration/search_test.rb +6 -6
  99. data/test/integration/tree_test.rb +3 -3
  100. data/test/integration/untranslated_test.rb +1 -1
  101. data/test/models/concept_test.rb +13 -14
  102. data/test/models/inline_data_test.rb +9 -9
  103. data/test/models/instance_configuration_test.rb +7 -3
  104. data/test/models/origin_test.rb +9 -59
  105. data/test/models/rdf_sync_test.rb +2 -4
  106. data/test/models/rdfapi_test.rb +0 -2
  107. data/test/models/skos_collection_import_test.rb +3 -4
  108. data/test/models/skos_export_test.rb +3 -5
  109. data/test/models/skos_import_test.rb +12 -10
  110. data/test/test_helper.rb +0 -1
  111. data/vendor/assets/stylesheets/{jquery-ui.css.scss → jquery-ui.scss} +0 -0
  112. data/vendor/assets/stylesheets/{jquery-ui.structure.css.scss → jquery-ui.structure.scss} +0 -0
  113. data/vendor/assets/stylesheets/{jquery-ui.theme.css.scss → jquery-ui.theme.scss} +0 -0
  114. metadata +34 -28
  115. data/lib/iqvoc/ability.rb +0 -60
  116. data/lib/iqvoc/controller_extensions.rb +0 -111
  117. data/lib/iqvoc/deep_cloning.rb +0 -90
  118. data/lib/iqvoc/inline_data_helper.rb +0 -45
  119. data/lib/iqvoc/instance_configuration.rb +0 -123
  120. data/lib/iqvoc/maker.rb +0 -141
  121. data/lib/iqvoc/navigation.rb +0 -61
  122. data/lib/iqvoc/origin.rb +0 -111
  123. data/lib/iqvoc/rankable.rb +0 -33
  124. data/lib/iqvoc/rdfapi.rb +0 -60
  125. data/lib/iqvoc/skos_exporter.rb +0 -153
  126. data/lib/iqvoc/skos_importer.rb +0 -337
@@ -0,0 +1,348 @@
1
+ class SkosImporter
2
+ class_attribute :first_level_object_classes, :second_level_object_classes
3
+ self.first_level_object_classes = [
4
+ Iqvoc::Concept.base_class,
5
+ Iqvoc::Collection.base_class
6
+ ]
7
+ self.second_level_object_classes = Iqvoc::Concept.labeling_classes.keys +
8
+ Iqvoc::Concept.note_classes +
9
+ Iqvoc::Concept.relation_classes +
10
+ Iqvoc::Concept.match_classes +
11
+ Iqvoc::Concept.notation_classes +
12
+ Iqvoc::Concept.additional_association_classes.keys +
13
+ [Iqvoc::Concept.root_class] +
14
+ [Iqvoc::Collection.member_class]
15
+
16
+ def self.prepend_first_level_object_classes(args)
17
+ self.first_level_object_classes.unshift(*args)
18
+ end
19
+
20
+ def initialize(object, default_namespace_url, logger = Rails.logger, publish = true, verbose = false)
21
+ @file = case object
22
+ when File
23
+ File.open(object)
24
+ when Array
25
+ object
26
+ else
27
+ open(object)
28
+ end
29
+
30
+ @default_namespace_url = default_namespace_url
31
+ @publish = publish
32
+ @verbose = verbose
33
+ @logger = logger
34
+
35
+ unless @file.is_a?(File) || @file.is_a?(Array)
36
+ raise "SkosImporter#import: Parameter 'file' should be a File or an Array."
37
+ end
38
+
39
+ # Some general Namespaces to support in any case
40
+ @prefixes = {
41
+ 'http://www.w3.org/2004/02/skos/core#' => 'skos:',
42
+ 'http://www.w3.org/2008/05/skos#' => 'skos:',
43
+ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' => 'rdf:',
44
+ default_namespace_url => ':'
45
+ }
46
+ # Add the namespaces specified in the Iqvoc config
47
+ Iqvoc.rdf_namespaces.each do |pref, uri|
48
+ @prefixes[uri] = "#{pref.to_s}:"
49
+ end
50
+
51
+ @seen_first_level_objects = {} # Concept cache (don't load any concept twice from db)
52
+
53
+ # Assign the default concept scheme singleton instance as a seen first level object upfront
54
+ # in order to handle a missing scheme definition in ntriple data
55
+ @seen_first_level_objects[Iqvoc::Concept.root_class.instance.origin] = Iqvoc::Concept.root_class
56
+
57
+ @new_subjects = {} # Concepts, collections, labels etc. to be published later
58
+
59
+ # Triples the importer doesn't understand immediately. Example:
60
+ #
61
+ # :a skos:prefLabel "foo". # => What is :a? Remember this and try again later
62
+ # ....
63
+ # :a rdf:type skos:Concept # => Now I know :a, good I remembered it's prefLabel...
64
+ @unknown_second_level_triples = Set.new
65
+
66
+ # Hash of arrays of arrays: { "_:n123" => [["pred1", "obj1"], ["pred2", "obj2"]] }
67
+ @blank_nodes = {}
68
+
69
+ @existing_origins = {} # To prevent the creation of first level objects we already have
70
+ first_level_object_classes.each do |klass|
71
+ klass.select('origin').load.each do |thing|
72
+ @existing_origins[thing.origin] = klass
73
+ end
74
+ end
75
+ end
76
+
77
+ def run
78
+ print_known_namespaces
79
+ print_known_import_classes
80
+ import @file
81
+ end
82
+
83
+ private
84
+
85
+ def import(file)
86
+ ActiveSupport.run_load_hooks(:skos_importer_before_import, self)
87
+
88
+ start = Time.now
89
+
90
+ @logger.info "default namespace: '#{@default_namespace_url}'"
91
+ @logger.info "publish: '#{@publish}'"
92
+
93
+ first_level_types = {} # type identifier ("namespace:SomeClass") to Iqvoc class assignment hash
94
+ first_level_object_classes.each do |klass|
95
+ first_level_types["#{klass.rdf_namespace}:#{klass.rdf_class}"] = klass
96
+ end
97
+ second_level_types = {}
98
+ second_level_object_classes.each do |klass|
99
+ second_level_types["#{klass.rdf_namespace}:#{klass.rdf_predicate}"] = klass
100
+ end
101
+
102
+ @logger.info 'SkosImporter: Importing triples...'
103
+ file.each_with_index do |line, index|
104
+ extracted_triple = *extract_triple(line)
105
+
106
+ if @verbose && has_unknown_namespaces?(extracted_triple)
107
+ @logger.warn "SkosImporter: Unknown namespaces. Skipping #{extracted_triple.join(' ')}"
108
+ end
109
+
110
+ unless has_valid_origin?(extracted_triple)
111
+ @logger.warn "SkosImporter: Invalid origin. Skipping #{extracted_triple.join(' ')}"
112
+ next
113
+ end
114
+
115
+ identify_blank_nodes(*extracted_triple) ||
116
+ import_first_level_objects(first_level_types, *extracted_triple) ||
117
+ import_second_level_objects(second_level_types, false, line)
118
+ end
119
+
120
+ # treeify blank nodes hash
121
+ @blank_nodes.each do |origin, bnode_struct|
122
+ tranform_blank_node(origin, bnode_struct)
123
+ end
124
+
125
+ @logger.info "Computing 'forward' defined triples..."
126
+ @unknown_second_level_triples.each do |line|
127
+ import_second_level_objects(second_level_types, true, line)
128
+ end
129
+
130
+ first_import_step_done = Time.now
131
+ @logger.info "Basic import done (took #{(first_import_step_done - start).to_i} seconds)."
132
+
133
+ published = publish
134
+
135
+ done = Time.now
136
+ @logger.info "Publishing of #{published} subjects done (took #{(done - first_import_step_done).to_i} seconds). #{@new_subjects.count - published} are in draft state."
137
+ @logger.info "Imported #{published} published and #{@new_subjects.count - published} draft subjects in #{(done - start).to_i} seconds."
138
+ @logger.info "First step took #{(first_import_step_done - start).to_i} seconds, publishing took #{(done - first_import_step_done).to_i} seconds."
139
+
140
+ ActiveSupport.run_load_hooks(:skos_importer_after_import, self)
141
+ end
142
+
143
+ def publish
144
+ published = 0
145
+ # Respect order of first level classes configured in FIRST_LEVEL_OBJECTS
146
+ # Example: XL labels have to be published before referencing concepts
147
+ sorted_new_subjects = @new_subjects.sort_by do |origin, klass|
148
+ first_level_object_classes.index(klass)
149
+ end
150
+
151
+ if @publish
152
+ @logger.info "Publishing #{@new_subjects.count} new subjects..."
153
+
154
+ sorted_new_subjects.each do |origin, klass|
155
+ subject = klass.find_by(origin: origin)
156
+ if subject.publishable?
157
+ subject.publish!
158
+ published += 1
159
+ else
160
+ @logger.warn "WARNING: Publishing failed! Subject ('#{subject.origin}') invalid: #{subject.errors.to_hash.inspect}"
161
+ end
162
+ end
163
+ end
164
+ published
165
+ end
166
+
167
+ def identify_blank_nodes(subject, predicate, object)
168
+ if blank_node?(subject)
169
+ @blank_nodes[subject] ||= []
170
+ @blank_nodes[subject] << [predicate, object]
171
+ true
172
+ else
173
+ false
174
+ end
175
+ end
176
+
177
+ def import_first_level_objects(types, subject, predicate, object)
178
+ if (predicate == 'rdf:type' && types[object] && subject =~ /^:(.+)$/)
179
+ # We've found a subject definition with a class we know and which is in our responsibility (":")
180
+ origin = $1
181
+
182
+ if (@existing_origins[origin])
183
+ if (types[object] == @existing_origins[origin])
184
+ @logger.info "SkosImporter: Subject with origin '#{origin}' already exists. Skipping duplicate creation (should be no problem)."
185
+ else
186
+ @logger.warn "SkosImporter: Subject with origin '#{origin} already exists but has another class (#{@existing_origins[origin]}) then the one I wanted to create (#{types[object]}). You seem to have a problem with your configuration!"
187
+ end
188
+ else
189
+ @logger.info "SkosImporter: Creating Subject: #{subject} #{predicate} #{object}" if @verbose
190
+ # FIXME
191
+
192
+ types[object].create do |klass|
193
+ klass.origin = origin
194
+ end
195
+ @seen_first_level_objects[origin] = types[object]
196
+ @new_subjects[origin] = types[object]
197
+ end
198
+ true
199
+ else
200
+ false
201
+ end
202
+ end
203
+
204
+ def import_second_level_objects(types, final, line)
205
+ subject, predicate, object = *extract_triple(line)
206
+
207
+ return unless (subject =~ /^:(.*)$/ && types[predicate]) # We're not responsible for this
208
+
209
+ # Load the subject and replace the string by the respective data object
210
+ subject_origin = $1
211
+ subject = load_first_level_object(subject_origin)
212
+ unless subject
213
+ if final
214
+ @logger.warn "SkosImporter: Couldn't find Subject with origin '#{subject_origin}. Skipping entry '#{subject} #{predicate} #{object}.'"
215
+ else
216
+ @unknown_second_level_triples << line
217
+ end
218
+ return false
219
+ end
220
+
221
+ # Load the data object for the object string if this is representing a thing in our domain
222
+ if (object =~ /^:(.*)$/ && types[predicate])
223
+ object_origin = $1
224
+ object = load_first_level_object(object_origin)
225
+ unless object
226
+ if final
227
+ @logger.warn "SkosImporter: Couldn't find Object with origin '#{object_origin}'. Skipping entry ':#{subject_origin} #{predicate} #{object_origin}.'"
228
+ else
229
+ @unknown_second_level_triples << line
230
+ end
231
+ return false
232
+ end
233
+ end
234
+
235
+ # If not in final mode every :my_concept :bla _:blank_node. triple should
236
+ # be saved for final mode. Why? Example:
237
+ #
238
+ # :a iqvoc:changeNote _:b01 # => I do not know know anything about the blank node now
239
+ # _:b01 dc:author "DHH"...
240
+ #
241
+ if blank_node?(object)
242
+ if final
243
+ object = @blank_nodes[object]
244
+ else
245
+ @unknown_second_level_triples << line
246
+ return false
247
+ end
248
+ end
249
+ begin
250
+ types[predicate].build_from_rdf(subject, predicate, object)
251
+ rescue InvalidStringLiteralError => e
252
+ @logger.warn e.message
253
+ end
254
+ end
255
+
256
+ def load_first_level_object(origin)
257
+ unless @seen_first_level_objects[origin]
258
+ klass = @existing_origins[origin]
259
+ if klass
260
+ @seen_first_level_objects[origin] = klass
261
+ end
262
+ end
263
+
264
+ # FIXME: bang
265
+ # FIXME: return something?
266
+ if klass = @seen_first_level_objects[origin]
267
+ klass.find_by!(origin: origin)
268
+ end
269
+ end
270
+
271
+ def blank_node?(str)
272
+ str.to_s =~ RDFAPI::BLANK_NODE_REGEXP
273
+ end
274
+
275
+ def extract_triple(line)
276
+ raise "'#{line}' doesn't look like valid ntriples data." unless line =~ /^(.*)\.\s*$/
277
+ line = $1.squish
278
+
279
+ triple = line.split(' ', 3) # The first one are uris the last can be a literal too
280
+
281
+ triple.each do |e| # Do some fun with the uris and literals
282
+ @prefixes.keys.each do |uri_prefix| # Use prefixes instead of full uris
283
+ e.gsub! /^<#{uri_prefix}([^>]*)>/ do |matches|
284
+ @prefixes[uri_prefix] + $1.gsub('.', '_')
285
+ end
286
+ end
287
+ e.squish!
288
+ end
289
+ triple
290
+ end
291
+
292
+ def has_unknown_namespaces?(triple)
293
+ triple.each do |obj|
294
+ return true if obj =~ /^<.*>$/
295
+ break
296
+ end
297
+ false
298
+ end
299
+
300
+ def has_valid_origin?(triple)
301
+ if blank_node?(triple.first)
302
+ origin = triple.first
303
+ else
304
+ # strip out leading ':' for origin validation
305
+ origin = triple.first[1..-1]
306
+ end
307
+
308
+ result = Origin.new(origin).valid?
309
+
310
+ result
311
+ end
312
+
313
+ # if blank node contains another blank node,
314
+ # move child blank node to his parent
315
+ def tranform_blank_node(origin, bnode_struct)
316
+ bnode_struct.each_index do |i|
317
+ bnode_origin = bnode_struct[i][1] # only origin could contain another blank node
318
+ if blank_node?(bnode_origin)
319
+ bnode_child_struct = @blank_nodes[bnode_origin]
320
+ bnode_struct[i][1] = bnode_child_struct # move to parent node
321
+ tranform_blank_node(bnode_origin, bnode_child_struct)
322
+
323
+ @blank_nodes.delete(bnode_origin) # remove old blank node
324
+ end
325
+ end
326
+ end
327
+
328
+ def print_known_namespaces
329
+ @logger.info "Known namespaces:"
330
+ @prefixes.each_with_index do |(uri, pref), i|
331
+ @logger.info "\t #{i+1}: #{pref} => #{uri}"
332
+ end
333
+ end
334
+
335
+ def print_known_import_classes
336
+ @logger.info "Known first level classes:"
337
+ first_level_object_classes.each_with_index do |floc, i|
338
+ @logger.info "\t #{i+1}: #{floc.rdf_namespace}:#{floc.rdf_class} => #{floc.to_s}"
339
+ end
340
+
341
+ @logger.info "Known second level classes:"
342
+ second_level_object_classes.each_with_index do |sloc, i|
343
+ @logger.info "\t #{i+1}: #{sloc.rdf_namespace}:#{sloc.rdf_predicate} => #{sloc.to_s}"
344
+ end
345
+ end
346
+
347
+ ActiveSupport.run_load_hooks(:skos_importer, self)
348
+ end
@@ -44,20 +44,20 @@ var EntitySelector = function(node) {
44
44
  }
45
45
  });
46
46
 
47
- var inputGroup = $('<div class="input-group" />').
47
+ this.inputGroup = $('<div class="input-group" />').
48
48
  append(this.input, this.indicator);
49
- this.container.append(inputGroup, selection).
49
+ this.container.append(this.inputGroup, selection).
50
50
  insertAfter(node).prepend(node);
51
51
 
52
52
  // XXX: does not belong here -- XXX: obsolete?
53
53
  var lang = this.el.data("language");
54
54
  if(lang) {
55
- $('<span class="input-group-addon" />').append(lang).prependTo(inputGroup);
55
+ $('<span class="input-group-addon" />').append(lang).
56
+ prependTo(this.inputGroup);
56
57
  }
57
58
 
58
59
  if(this.singular && this.entities.length) {
59
- this.input.hide();
60
- this.indicator.hide();
60
+ this.inputGroup.hide();
61
61
  }
62
62
  };
63
63
  // data transformations; target format is an array of objects with members
@@ -108,8 +108,7 @@ $.extend(EntitySelector.prototype, {
108
108
  }, 1);
109
109
 
110
110
  if(widget.singular) {
111
- widget.input.hide();
112
- widget.indicator.hide();
111
+ widget.inputGroup.hide();
113
112
  }
114
113
  }
115
114
  return false;
@@ -121,8 +120,7 @@ $.extend(EntitySelector.prototype, {
121
120
  widget.remove(entity.data("id"));
122
121
  entity.remove();
123
122
  if(widget.singular && !widget.entities.length) {
124
- widget.input.show();
125
- widget.indicator.show();
123
+ widget.inputGroup.show();
126
124
  }
127
125
  ev.preventDefault();
128
126
  },
@@ -14,10 +14,8 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require 'iqvoc/controller_extensions'
18
-
19
17
  class ApplicationController < ActionController::Base
20
- include Iqvoc::ControllerExtensions
18
+ include ControllerExtensions
21
19
 
22
20
  protect_from_forgery
23
21
  end
@@ -14,10 +14,8 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require 'iqvoc/rdf_sync'
18
-
19
17
  class Collections::VersionsController < ApplicationController
20
- include Iqvoc::RDFSync::Helper
18
+ include RDFSyncService::Helper
21
19
 
22
20
  def merge
23
21
  scope = Iqvoc::Collection.base_class.by_origin(params[:origin])
@@ -14,10 +14,8 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require 'iqvoc/rdf_sync'
18
-
19
17
  class Concepts::VersionsController < ApplicationController
20
- include Iqvoc::RDFSync::Helper
18
+ include RDFSyncService::Helper
21
19
 
22
20
  def merge
23
21
  concept_scope = Iqvoc::Concept.base_class.by_origin(params[:origin])
@@ -72,6 +70,14 @@ class Concepts::VersionsController < ApplicationController
72
70
  ActiveRecord::Base.transaction do
73
71
  new_version = current_concept.branch(current_user)
74
72
  new_version.save!
73
+ Iqvoc.change_note_class.create! do |note|
74
+ note.owner = new_version
75
+ note.language = I18n.locale.to_s
76
+ note.annotations_attributes = [
77
+ { namespace: 'dct', predicate: 'creator', value: current_user.name },
78
+ { namespace: 'dct', predicate: 'modified', value: DateTime.now.to_s }
79
+ ]
80
+ end
75
81
  end
76
82
  flash[:success] = t('txt.controllers.versioning.branched')
77
83
  redirect_to edit_concept_path(published: 0, id: new_version)
@@ -0,0 +1,109 @@
1
+ require 'active_support/concern'
2
+
3
+ module ControllerExtensions
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ prepend_before_action :set_locale
8
+ before_action :ensure_extension
9
+
10
+ helper :all
11
+ helper_method :current_user_session, :current_user, :concept_widget_data, :collection_widget_data, :label_widget_data
12
+
13
+ rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found
14
+ rescue_from CanCan::AccessDenied, with: :handle_access_denied
15
+ rescue_from ActionController::ParameterMissing, with: :handle_bad_request
16
+ end
17
+
18
+ protected
19
+
20
+ def default_url_options(options = nil)
21
+ { format: params[:format], lang: I18n.locale }.
22
+ merge(options || {})
23
+ end
24
+
25
+ # Force an extension to every url. (LOD)
26
+ def ensure_extension
27
+ unless params[:format] || !request.get?
28
+ flash.keep
29
+ redirect_to url_for(params.merge(format: (request.format && request.format.symbol) || :html))
30
+ end
31
+ end
32
+
33
+ def handle_access_denied(exception)
34
+ @exception = exception
35
+ @status = current_user ? 403 : 401
36
+ @user_session = UserSession.new if @status == 401
37
+ @return_url = request.fullpath
38
+ respond_to do |format|
39
+ format.html { render template: 'errors/access_denied', status: @status }
40
+ format.any { head @status }
41
+ end
42
+ end
43
+
44
+ def handle_not_found(exception)
45
+ @exception = exception
46
+ SearchResultsController.prepare_basic_variables(self)
47
+
48
+ respond_to do |format|
49
+ format.html { render template: 'errors/not_found', status: 404 }
50
+ format.any { head 404 }
51
+ end
52
+ end
53
+
54
+ def handle_bad_request(exception)
55
+ @exception = exception
56
+
57
+ respond_to do |format|
58
+ format.any { head 400 }
59
+ end
60
+ end
61
+
62
+ def set_locale
63
+ if params[:lang].present? && Iqvoc::Concept.pref_labeling_languages.include?(params[:lang])
64
+ I18n.locale = params[:lang]
65
+ else
66
+ I18n.locale = Iqvoc::Concept.pref_labeling_languages.first
67
+ end
68
+ end
69
+
70
+ def concept_widget_data(concept, rank = nil)
71
+ data = {
72
+ id: concept.origin,
73
+ name: (concept.pref_label && concept.pref_label.value.presence || ":#{concept.origin}") + (concept.additional_info ? " (#{concept.additional_info })" : '')
74
+ }
75
+ data[:rank] = rank if rank
76
+ data
77
+ end
78
+
79
+ def collection_widget_data(collection)
80
+ {
81
+ id: collection.origin,
82
+ name: collection.pref_label.to_s
83
+ }
84
+ end
85
+
86
+ def label_widget_data(label)
87
+ {
88
+ id: label.origin,
89
+ name: label.value
90
+ }
91
+ end
92
+
93
+ # Configurable Ability class
94
+ def current_ability
95
+ @current_ability ||= Iqvoc.ability_class.new(current_user)
96
+ end
97
+
98
+ def current_user_session
99
+ @current_user_session ||= UserSession.find
100
+ end
101
+
102
+ def current_user
103
+ @current_user ||= current_user_session && current_user_session.user
104
+ end
105
+
106
+ def with_layout?
107
+ !params[:layout]
108
+ end
109
+ end