iqvoc_skosxl 2.9.1 → 2.11.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +8 -10
  3. data/Gemfile.lock +475 -296
  4. data/README.md +1 -1
  5. data/app/assets/javascripts/iqvoc_skosxl/duplicate_check.js +104 -0
  6. data/app/assets/javascripts/iqvoc_skosxl/manifest.js +4 -0
  7. data/app/assets/javascripts/iqvoc_skosxl/new_label_modal.js +19 -0
  8. data/app/assets/javascripts/manifest.js +3 -3
  9. data/app/assets/stylesheets/manifest.scss +4 -0
  10. data/app/controllers/labels/versions_controller.rb +30 -50
  11. data/app/controllers/labels_controller.rb +71 -25
  12. data/app/controllers/rdf_controller.rb +8 -7
  13. data/app/controllers/xl_dashboard_controller.rb +43 -0
  14. data/app/helpers/iqvoc_skosxl_helper.rb +4 -0
  15. data/app/helpers/labels_helper.rb +8 -6
  16. data/app/models/application_record.rb +3 -0
  17. data/app/models/collection/skosxl/extension.rb +8 -0
  18. data/app/models/concept/skosxl/extension.rb +4 -2
  19. data/app/models/label/relation/base.rb +2 -2
  20. data/app/models/label/skosxl/base.rb +166 -29
  21. data/app/models/label/skosxl/properties/literal_form.rb +1 -1
  22. data/app/models/labeling/skosxl/alt_label.rb +12 -0
  23. data/app/models/labeling/skosxl/base.rb +65 -10
  24. data/app/models/labeling/skosxl/hidden_label.rb +2 -2
  25. data/app/models/labeling/skosxl/pref_label.rb +4 -0
  26. data/app/views/concepts/_form.html.erb +115 -0
  27. data/app/views/labels/_form.html.erb +11 -3
  28. data/app/views/labels/_language.html.erb +4 -0
  29. data/app/views/labels/_sidebar.html.erb +13 -7
  30. data/app/views/labels/duplicate.html.erb +4 -0
  31. data/app/views/labels/new.html.erb +1 -0
  32. data/app/views/labels/new_from_concept.html.erb +28 -0
  33. data/app/views/labels/notifications/_referenced_labels.html.erb +0 -1
  34. data/app/views/{rdf/show_label.iqrdf → labels/show.iqrdf} +1 -1
  35. data/app/views/labels/show_published.html.erb +5 -3
  36. data/app/views/labels/show_unpublished.html.erb +19 -22
  37. data/app/views/layouts/_label_in_concept_modal.html.erb +2 -0
  38. data/app/views/layouts/application.html.erb +51 -0
  39. data/app/views/partials/_modal.html.erb +17 -0
  40. data/app/views/partials/label/skosxl/_inline_base.html.erb +1 -0
  41. data/app/views/partials/label/skosxl/_new_link_base.html.erb +1 -1
  42. data/app/views/partials/labeling/skosxl/_base.html.erb +20 -13
  43. data/app/views/partials/labeling/skosxl/_edit_base.html.erb +3 -2
  44. data/config/application.rb +26 -14
  45. data/config/boot.rb +3 -3
  46. data/config/cable.yml +10 -0
  47. data/config/database.yml +21 -15
  48. data/config/database.yml.postgresql +12 -9
  49. data/config/environment.rb +1 -1
  50. data/config/initializers/content_security_policy.rb +25 -0
  51. data/config/initializers/filter_parameter_logging.rb +6 -2
  52. data/config/initializers/inflections.rb +4 -4
  53. data/config/initializers/iqvoc.rb +2 -0
  54. data/config/initializers/permissions_policy.rb +11 -0
  55. data/config/initializers/wrap_parameters.rb +2 -2
  56. data/config/initializers/zeitwerk.rb +7 -0
  57. data/config/locales/activerecord.de.yml +5 -2
  58. data/config/locales/activerecord.en.yml +3 -0
  59. data/config/locales/de.yml +13 -0
  60. data/config/locales/en.yml +13 -0
  61. data/config/routes.rb +8 -12
  62. data/config/storage.yml +34 -0
  63. data/db/migrate/20110408121540_extend_label.rb +3 -3
  64. data/db/migrate/20110408123644_add_label_relations.rb +1 -1
  65. data/db/migrate/20150108154312_add_fk_contraints_iqvoc_skosxl.rb +1 -1
  66. data/db/migrate/20150414083600_remove_fk_constraints_iqvoc_skosxl.rb +1 -1
  67. data/db/migrate/20231012174634_remove_locked_by_for_label.rb +5 -0
  68. data/db/schema.rb +173 -182
  69. data/iqvoc_skosxl.gemspec +2 -2
  70. data/lib/iqvoc/skosxl/version.rb +1 -1
  71. data/lib/iqvoc_skosxl.rb +8 -1
  72. data/public/assets/fonts/FiraMono-Regular-0b6138c5b386dc9125473fd851926f29.ttf +0 -0
  73. data/public/assets/fonts/FiraMono-Regular-690950e8d89c92cba41eeeb13f1de93e.woff +0 -0
  74. data/public/assets/fonts/FiraMono-Regular-98f97ed2dbf9d94d4fa5df048434b88d.eot +0 -0
  75. data/public/assets/fonts/FiraMono-Regular.eot +0 -0
  76. data/public/assets/fonts/FiraMono-Regular.ttf +0 -0
  77. data/public/assets/fonts/FiraMono-Regular.woff +0 -0
  78. data/public/assets/fonts/FiraSans-Bold-0de5f536bd0dc370449c0c67a49a6fe7.eot +0 -0
  79. data/public/assets/fonts/FiraSans-Bold-25037ef8d155e38b5df0c242a4c6cf2d.ttf +0 -0
  80. data/public/assets/fonts/FiraSans-Bold-494219a9639084eb9528ff47f79fcda1.woff +0 -0
  81. data/public/assets/fonts/FiraSans-Bold.eot +0 -0
  82. data/public/assets/fonts/FiraSans-Bold.ttf +0 -0
  83. data/public/assets/fonts/FiraSans-Bold.woff +0 -0
  84. data/public/assets/fonts/FiraSans-BoldItalic-5b3b812df9e1cb2b1f34baad65a2bdfb.ttf +0 -0
  85. data/public/assets/fonts/FiraSans-BoldItalic-90b8087c48feff2e828f658c49de5399.eot +0 -0
  86. data/public/assets/fonts/FiraSans-BoldItalic-b10e46158d50bf9b78968112acf87310.woff +0 -0
  87. data/public/assets/fonts/FiraSans-BoldItalic.eot +0 -0
  88. data/public/assets/fonts/FiraSans-BoldItalic.ttf +0 -0
  89. data/public/assets/fonts/FiraSans-BoldItalic.woff +0 -0
  90. data/public/assets/fonts/FiraSans-Book-659d252627051e785260ba445da8930f.woff +0 -0
  91. data/public/assets/fonts/FiraSans-Book-abc65ceb7bfaed729bff7a9d1367b7d4.eot +0 -0
  92. data/public/assets/fonts/FiraSans-Book-f0410501d5ecc5fe66bcdbc02b482c81.ttf +0 -0
  93. data/public/assets/fonts/FiraSans-Book.eot +0 -0
  94. data/public/assets/fonts/FiraSans-Book.ttf +0 -0
  95. data/public/assets/fonts/FiraSans-Book.woff +0 -0
  96. data/public/assets/fonts/FiraSans-ExtraLight-140f15ee97cb2099ff01c2b57dcd1a24.woff +0 -0
  97. data/public/assets/fonts/FiraSans-ExtraLight-28e5c2679df66406ebd117fbdded6753.eot +0 -0
  98. data/public/assets/fonts/FiraSans-ExtraLight-c15de70ebceffce178cbd2e82aa2c373.ttf +0 -0
  99. data/public/assets/fonts/FiraSans-ExtraLight.eot +0 -0
  100. data/public/assets/fonts/FiraSans-ExtraLight.ttf +0 -0
  101. data/public/assets/fonts/FiraSans-ExtraLight.woff +0 -0
  102. data/public/assets/fonts/FiraSans-Italic-ac4cb18fe14a7c90f29cdd2ce499ba59.woff +0 -0
  103. data/public/assets/fonts/FiraSans-Italic-bdea00fee0da5ca9176061e00c26a0da.eot +0 -0
  104. data/public/assets/fonts/FiraSans-Italic-e7e76a0ee170fd29b5d8100753eff569.ttf +0 -0
  105. data/public/assets/fonts/FiraSans-Italic.eot +0 -0
  106. data/public/assets/fonts/FiraSans-Italic.ttf +0 -0
  107. data/public/assets/fonts/FiraSans-Italic.woff +0 -0
  108. data/public/assets/fonts/FiraSans-Light-20adaf630b690c3e3184daaeae585f22.woff +0 -0
  109. data/public/assets/fonts/FiraSans-Light-3689e18b38d335ec0c43823adb6a2984.eot +0 -0
  110. data/public/assets/fonts/FiraSans-Light-55b04531e7a9ecdf58090d70b94b68e2.ttf +0 -0
  111. data/public/assets/fonts/FiraSans-Light-SC-098407a72b7ad46f7c2480d7ac11baf2.eot +0 -0
  112. data/public/assets/fonts/FiraSans-Light-SC-82763fe2ce9e6b897556c6f3c2aceb29.woff2 +0 -0
  113. data/public/assets/fonts/FiraSans-Light-SC-c73985985f0501c1845a5185b180fe6b.woff +0 -0
  114. data/public/assets/fonts/FiraSans-Light-SC-c9563f48d9cccd91f07e46801c27130f.ttf +0 -0
  115. data/public/assets/fonts/FiraSans-Light-SC.eot +0 -0
  116. data/public/assets/fonts/FiraSans-Light-SC.ttf +0 -0
  117. data/public/assets/fonts/FiraSans-Light-SC.woff +0 -0
  118. data/public/assets/fonts/FiraSans-Light-SC.woff2 +0 -0
  119. data/public/assets/fonts/FiraSans-Light.eot +0 -0
  120. data/public/assets/fonts/FiraSans-Light.ttf +0 -0
  121. data/public/assets/fonts/FiraSans-Light.woff +0 -0
  122. data/public/assets/fonts/FiraSans-Medium-082fab59048189168006bf2e914ba8b7.woff +0 -0
  123. data/public/assets/fonts/FiraSans-Medium-11706edfe8651c355b413bd24b4b5e10.eot +0 -0
  124. data/public/assets/fonts/FiraSans-Medium-3a0dacdeaba1b4c054f2d6cb5061965d.ttf +0 -0
  125. data/public/assets/fonts/FiraSans-Medium.eot +0 -0
  126. data/public/assets/fonts/FiraSans-Medium.ttf +0 -0
  127. data/public/assets/fonts/FiraSans-Medium.woff +0 -0
  128. data/public/assets/fonts/FiraSans-MediumItalic-6c8a2646d72641226527d574a8485b66.woff +0 -0
  129. data/public/assets/fonts/FiraSans-MediumItalic-b81e92794a6878b6c578d97b3ad5e6d7.ttf +0 -0
  130. data/public/assets/fonts/FiraSans-MediumItalic-eae7f4a3c4db9fe83025909ebfae5ad9.eot +0 -0
  131. data/public/assets/fonts/FiraSans-MediumItalic.eot +0 -0
  132. data/public/assets/fonts/FiraSans-MediumItalic.ttf +0 -0
  133. data/public/assets/fonts/FiraSans-MediumItalic.woff +0 -0
  134. data/public/assets/fonts/FiraSans-Regular-537188a19aeebdd74a92e114af7a02cb.ttf +0 -0
  135. data/public/assets/fonts/FiraSans-Regular-5d6a923de9be80ff5c2995cc03d93127.woff +0 -0
  136. data/public/assets/fonts/FiraSans-Regular-db689e5fea21ed4b7890811151968dc6.eot +0 -0
  137. data/public/assets/fonts/FiraSans-Regular.eot +0 -0
  138. data/public/assets/fonts/FiraSans-Regular.ttf +0 -0
  139. data/public/assets/fonts/FiraSans-Regular.woff +0 -0
  140. data/public/assets/fonts/FiraSans-UltraLight-3baefce4c224a0f0b26cdafe37dfa55d.eot +0 -0
  141. data/public/assets/fonts/FiraSans-UltraLight-e3909a352b87f853bb464836adfd602a.ttf +0 -0
  142. data/public/assets/fonts/FiraSans-UltraLight-f7289beeaa2353caf487553ee8b8ef03.woff +0 -0
  143. data/public/assets/fonts/FiraSans-UltraLight.eot +0 -0
  144. data/public/assets/fonts/FiraSans-UltraLight.ttf +0 -0
  145. data/public/assets/fonts/FiraSans-UltraLight.woff +0 -0
  146. data/public/assets/fonts/FontAwesome.otf +0 -0
  147. data/public/assets/fonts/fontawesome-webfont.eot +0 -0
  148. data/public/assets/fonts/fontawesome-webfont.svg +2671 -0
  149. data/public/assets/fonts/fontawesome-webfont.ttf +0 -0
  150. data/public/assets/fonts/fontawesome-webfont.woff +0 -0
  151. data/public/assets/fonts/fontawesome-webfont.woff2 +0 -0
  152. data/public/assets/images/ajax-loader-30d8e72bfdae694b1938658e1b087df0.gif +0 -0
  153. data/public/assets/images/ajax-loader.gif +0 -0
  154. data/public/assets/images/iqvoc_logo-165f17a46cf0a1bf9464db9d136fb843.svg +41 -0
  155. data/public/assets/images/iqvoc_logo.svg +41 -0
  156. data/public/assets/images/treeview-default-line-5e3c0e0c48f48c23c45aef7b72c739c0.gif +0 -0
  157. data/public/assets/images/treeview-default-line.gif +0 -0
  158. data/public/assets/javascripts/bootstrap.bundle.min-68b3c2f1c1f636f947fff1229d3ffbf5.js +7 -0
  159. data/public/assets/javascripts/bootstrap.bundle.min.js +31 -0
  160. data/public/assets/javascripts/jquery-d52dc3a9171f1fc89dd0f8e35e42c9d2.js +26 -0
  161. data/public/assets/javascripts/jquery.js +10701 -0
  162. data/public/assets/javascripts/manifest-d95423d4873e576e7ae0b6a57cf18ec5.js +5486 -0
  163. data/public/assets/javascripts/manifest.js +6981 -0
  164. data/public/assets/manifest.json +1 -0
  165. data/public/assets/stylesheets/manifest-bbb2857850990f13f777f3dec120a018.css +13 -0
  166. data/public/assets/stylesheets/manifest.css +13620 -0
  167. data/public/favicon.ico +0 -0
  168. data/test/controllers/rdf_rendering_test.rb +19 -0
  169. data/test/controllers/routing_test.rb +5 -1
  170. data/test/integration/concept_label_language_test.rb +1 -3
  171. data/test/integration/dashboard_test.rb +1 -1
  172. data/test/integration/duplicate_label_test.rb +52 -0
  173. data/test/integration/edit_labels_test.rb +2 -2
  174. data/test/integration/label_creation_test.rb +8 -0
  175. data/test/integration/label_relation_test.rb +2 -2
  176. data/test/integration/labels_order_test.rb +6 -6
  177. data/test/integration/search_test.rb +117 -0
  178. data/test/integration_test_helper.rb +2 -2
  179. data/test/models/concept_test.rb +12 -0
  180. data/test/models/skos_importer_test.rb +1 -1
  181. data/test/models/zeitwerk_compliance_test.rb +7 -0
  182. metadata +137 -26
  183. data/app/assets/stylesheets/manifest.css.scss +0 -4
  184. data/app/views/labels/_value_and_language.html.erb +0 -9
  185. data/config/initializers/backtrace_silencers.rb +0 -7
  186. data/config/initializers/cookies_serializer.rb +0 -3
  187. data/config/initializers/mime_types.rb +0 -4
  188. data/public/export/iqvoc_dump-2017-06-07_13-08.ttl +0 -70
@@ -12,9 +12,7 @@ class Label::SKOSXL::Base < Label::Base
12
12
  # ********** Hooks
13
13
 
14
14
  after_initialize do |label|
15
- if label.origin.blank?
16
- label.origin = Origin.new.to_s
17
- end
15
+ label.origin = Origin.new.to_s if label.origin.blank?
18
16
  end
19
17
 
20
18
  after_save do |label|
@@ -46,37 +44,66 @@ class Label::SKOSXL::Base < Label::Base
46
44
 
47
45
  @nested_relations = [] # Will be marked as nested attributes later
48
46
 
49
- has_many :labelings, class_name: 'Labeling::Base', foreign_key: 'target_id', dependent: :destroy
50
- has_many :concepts, through: :labelings, source: :owner
47
+ has_many :labelings,
48
+ class_name: 'Labeling::Base',
49
+ foreign_key: 'target_id',
50
+ dependent: :destroy,
51
+ inverse_of: :target
51
52
  include_to_deep_cloning(:labelings)
52
53
 
53
- has_many :relations, foreign_key: 'domain_id', class_name: 'Label::Relation::Base', dependent: :destroy
54
- # Which references are pointing to this label?
55
- has_many :referenced_by_relations, foreign_key: 'range_id', class_name: 'Label::Relation::Base', dependent: :destroy
54
+ has_many :concepts,
55
+ through: :labelings,
56
+ source: :owner
57
+
58
+ has_many :relations,
59
+ foreign_key: 'domain_id',
60
+ class_name: 'Label::Relation::Base',
61
+ dependent: :destroy,
62
+ inverse_of: :domain
63
+
64
+ # Which references are pointing to this label?
65
+ has_many :referenced_by_relations,
66
+ foreign_key: 'range_id',
67
+ class_name: 'Label::Relation::Base',
68
+ dependent: :destroy,
69
+ inverse_of: :range
56
70
  include_to_deep_cloning(:relations, :referenced_by_relations)
57
71
 
58
- has_many :notes, as: :owner, class_name: 'Note::Base', dependent: :destroy
59
- has_many :annotations, through: :notes, source: :annotations
72
+ has_many :notes,
73
+ as: :owner,
74
+ class_name: 'Note::Base',
75
+ dependent: :destroy,
76
+ inverse_of: :owner
77
+
78
+ has_many :annotations,
79
+ through: :notes,
80
+ source: :annotations
60
81
  include_to_deep_cloning(notes: :annotations)
61
82
 
62
83
  # ************** "Dynamic"/configureable relations
63
84
 
64
85
  Iqvoc::XLLabel.note_class_names.each do |note_class_name|
65
- has_many note_class_name.to_relation_name, as: :owner, class_name: note_class_name, dependent: :destroy
86
+ has_many note_class_name.to_relation_name,
87
+ as: :owner,
88
+ class_name: note_class_name,
89
+ dependent: :destroy,
90
+ inverse_of: :owner
66
91
  @nested_relations << note_class_name.to_relation_name
67
92
  end
68
93
 
69
94
  Iqvoc::XLLabel.relation_class_names.each do |relation_class_name|
70
95
  has_many relation_class_name.to_relation_name,
71
- foreign_key: 'domain_id',
72
- class_name: relation_class_name,
73
- extend: Label::Relation::BidirectionalRelationExtension,
74
- dependent: :destroy
96
+ foreign_key: 'domain_id',
97
+ class_name: relation_class_name,
98
+ extend: Label::Relation::BidirectionalRelationExtension,
99
+ dependent: :destroy,
100
+ inverse_of: :domain
75
101
 
76
102
  has_many "#{relation_class_name.to_relation_name}_of".to_sym,
77
- foreign_key: 'range_id',
78
- class_name: relation_class_name,
79
- dependent: :destroy
103
+ foreign_key: 'range_id',
104
+ class_name: relation_class_name,
105
+ dependent: :destroy,
106
+ inverse_of: :range
80
107
 
81
108
  # Serialized setters and getters (\r\n or , separated)
82
109
  define_method("inline_#{relation_class_name.to_relation_name}".to_sym) do
@@ -92,7 +119,10 @@ class Label::SKOSXL::Base < Label::Base
92
119
  end
93
120
 
94
121
  Iqvoc::XLLabel.additional_association_classes.each do |association_class, foreign_key|
95
- has_many association_class.name.to_relation_name, class_name: association_class.name, foreign_key: foreign_key, dependent: :destroy
122
+ has_many association_class.name.to_relation_name,
123
+ class_name: association_class.name,
124
+ foreign_key: foreign_key,
125
+ dependent: :destroy # TODO: add inverse_of???
96
126
  include_to_deep_cloning(association_class.deep_cloning_relations)
97
127
  association_class.referenced_by(self)
98
128
  end
@@ -114,18 +144,46 @@ class Label::SKOSXL::Base < Label::Base
114
144
  end
115
145
 
116
146
  def self.for_dashboard
117
- unpublished_or_follow_up.includes(:locking_user)
147
+ unpublished_or_follow_up
148
+ end
149
+
150
+ # ********** Class Methods
151
+
152
+ def self.dashboard_path
153
+ 'label_dashboard_path'
154
+ end
155
+
156
+ def class_path
157
+ 'label_path'
118
158
  end
119
159
 
120
160
  # ********** Methods
121
161
 
162
+ def <=>(other)
163
+ self.to_s.downcase <=> other.to_s.downcase
164
+ end
165
+
166
+ def ==(other)
167
+ language == other.try(:language) && value == other.try(:value) && rev == other.try(:rev)
168
+ end
169
+
170
+ def eql?(other)
171
+ self == other
172
+ end
173
+
174
+ def hash
175
+ [value, language, rev].hash
176
+ end
177
+
122
178
  def self.single_query(params = {})
123
179
  query_str = build_query_string(params)
124
180
 
125
- scope = by_query_value(query_str).
126
- by_language(params[:languages].to_a).includes(:concepts).references(:concepts)
127
- published.
128
- order("LOWER(#{Label::Base.table_name}.value)")
181
+ scope = self.by_query_value(query_str)
182
+ .by_language(params[:languages].to_a)
183
+ .includes(:concepts)
184
+ .references(:concepts)
185
+ .published
186
+ .order(Arel.sql("LENGTH(#{Label::Base.table_name}.value)"))
129
187
 
130
188
  if params[:collection_origin].present?
131
189
  collection = Collection::Base.where(origin: params[:collection_origin]).last
@@ -145,6 +203,46 @@ class Label::SKOSXL::Base < Label::Base
145
203
  scope = scope.includes(:concepts).merge(Iqvoc::Collection.base_class.published)
146
204
  end
147
205
 
206
+
207
+ # change note filtering
208
+ if params[:change_note_date_from].present? || params[:change_note_date_to].present?
209
+ change_note_relation = Iqvoc.change_note_class_name.to_relation_name
210
+
211
+ scope = scope.includes(change_note_relation.to_sym => :annotations)
212
+ .references(change_note_relation)
213
+ .references('note_annotations')
214
+
215
+
216
+ # change note type filtering
217
+ scope = case params[:change_note_type]
218
+ when 'created'
219
+ scope.where('note_annotations.predicate = ?', 'created')
220
+ when 'modified'
221
+ scope.where('note_annotations.predicate = ?', 'modified')
222
+ else
223
+ scope.where('note_annotations.predicate = ? OR note_annotations.predicate = ?', 'created', 'modified')
224
+ end
225
+
226
+ if params[:change_note_date_from].present?
227
+ begin
228
+ DateTime.parse(params[:change_note_date_from])
229
+ date_from = params[:change_note_date_from]
230
+ scope = scope.where('note_annotations.value >= ?', date_from)
231
+ rescue ArgumentError
232
+ Rails.logger.error "Invalid date was entered for search"
233
+ end
234
+ end
235
+
236
+ if params[:change_note_date_to].present?
237
+ begin
238
+ date_to = DateTime.parse(params[:change_note_date_to]).end_of_day.to_s
239
+ scope = scope.where('note_annotations.value <= ?', date_to)
240
+ rescue ArgumentError
241
+ Rails.logger.error "Invalid date was entered for search"
242
+ end
243
+ end
244
+ end
245
+
148
246
  scope = yield(scope) if block_given?
149
247
  scope.map { |result| SearchResult.new(result) }
150
248
  end
@@ -153,6 +251,10 @@ class Label::SKOSXL::Base < Label::Base
153
251
  'partials/label/skosxl/search_result'
154
252
  end
155
253
 
254
+ def self.inline_partial_name
255
+ 'partials/label/skosxl/inline_base'
256
+ end
257
+
156
258
  def self.new_link_partial_name
157
259
  'partials/label/skosxl/new_link_base'
158
260
  end
@@ -162,12 +264,12 @@ class Label::SKOSXL::Base < Label::Base
162
264
  end
163
265
 
164
266
  def notes_for_class(note_class)
165
- note_class = note_class.name if note_class < ActiveRecord::Base # Use the class name string
267
+ note_class = note_class.name if note_class < ApplicationRecord # Use the class name string
166
268
  notes.select{ |note| note.class.name == note_class }
167
269
  end
168
270
 
169
271
  def relations_for_class(relation_class)
170
- relation_class = relation_class.name if relation_class < ActiveRecord::Base # Use the class name string
272
+ relation_class = relation_class.name if relation_class < ApplicationRecord # Use the class name string
171
273
  relations.select{ |rel| rel.class.name == relation_class }
172
274
  end
173
275
 
@@ -178,19 +280,19 @@ class Label::SKOSXL::Base < Label::Base
178
280
  end
179
281
 
180
282
  def concepts_for_labeling_class(labeling_class)
181
- labeling_class = labeling_class.name if labeling_class < ActiveRecord::Base # Use the class name string
283
+ labeling_class = labeling_class.name if labeling_class < ApplicationRecord # Use the class name string
182
284
  labelings.select{ |l| l.class.name == labeling_class.to_s }.map(&:owner)
183
285
  end
184
286
 
185
287
  def related_labels_for_relation_class(relation_class, only_published = true)
186
- relation_class = relation_class.name if relation_class < ActiveRecord::Base # Use the class name string
288
+ relation_class = relation_class.name if relation_class < ApplicationRecord # Use the class name string
187
289
  relations.select { |rel| rel.class.name == relation_class }
188
290
  .map(&:range)
189
291
  .select { |l| l.published? || !only_published }
190
292
  end
191
293
 
192
294
  def notes_for_class(note_class)
193
- note_class = note_class.name if note_class < ActiveRecord::Base # Use the class name string
295
+ note_class = note_class.name if note_class < ApplicationRecord # Use the class name string
194
296
  notes.select{ |note| note.class.name == note_class }
195
297
  end
196
298
 
@@ -224,4 +326,39 @@ class Label::SKOSXL::Base < Label::Base
224
326
  label_relations: Label::Relation::Base.by_domain(id).range_in_edit_mode
225
327
  }
226
328
  end
329
+
330
+ def duplicate(user)
331
+ clone = deep_clone(except: [:origin, :rev, :published_version_id, :published_at, :expired_at, :to_review], include: [:labelings])
332
+
333
+ clone.origin = Origin.new.to_s
334
+ clone.value += " [#{I18n.t('txt.models.label.copy')}]"
335
+
336
+ clone.labelings.select { |l| l.type == "Labeling::SKOSXL::PrefLabel" }.each do |l|
337
+ clone.labelings.delete(l)
338
+ clone.labelings.append Labeling::SKOSXL::AltLabel.new(owner_id: l.owner_id)
339
+ end
340
+
341
+ clone.build_initial_change_note(user)
342
+ clone.save!
343
+ clone
344
+ end
345
+
346
+ # initial created-ChangeNote creation
347
+ def build_initial_change_note(user)
348
+ send(Iqvoc::change_note_class_name.to_relation_name).new do |change_note|
349
+ change_note.value = I18n.t('txt.views.versioning.initial_version')
350
+ change_note.language = I18n.locale.to_s
351
+ change_note.position = 1
352
+ change_note.annotations_attributes = [
353
+ { namespace: 'dct', predicate: 'creator', value: user.name },
354
+ { namespace: 'dct', predicate: 'created', value: DateTime.now.to_s }
355
+ ]
356
+ end
357
+ end
358
+
359
+ def build_notes
360
+ Iqvoc::XLLabel.note_class_names.each do |note_class_name|
361
+ send(note_class_name.to_relation_name).build if send(note_class_name.to_relation_name).empty?
362
+ end
363
+ end
227
364
  end
@@ -16,6 +16,6 @@ class Label::SKOSXL::Properties::LiteralForm
16
16
  $1
17
17
  end
18
18
 
19
- rdf_subject.update_attributes(value: value, language: lang)
19
+ rdf_subject.update(value: value, language: lang)
20
20
  end
21
21
  end
@@ -1,4 +1,16 @@
1
1
  class Labeling::SKOSXL::AltLabel < Labeling::SKOSXL::Base
2
2
  self.rdf_namespace = 'skosxl'
3
3
  self.rdf_predicate = 'altLabel'
4
+
5
+ def self.view_section_sort_key(obj)
6
+ 60
7
+ end
8
+
9
+ def build_search_result_rdf(document, result)
10
+ result.Sdc::link(IqRdf.build_uri(owner.origin))
11
+ # also render prefLabel literal and uri to alt labelings
12
+ result.send(Labeling::SKOSXL::PrefLabel.rdf_namespace.camelcase).send(Labeling::SKOSXL::PrefLabel.rdf_predicate, IqRdf.build_uri(owner.pref_label.origin))
13
+ result.Skos.send(Labeling::SKOS::PrefLabel.rdf_predicate, owner.pref_label.value, lang: owner.pref_label.language)
14
+ build_rdf(document, result)
15
+ end
4
16
  end
@@ -4,7 +4,7 @@ class Labeling::SKOSXL::Base < Labeling::Base
4
4
  self.rdf_predicate = nil
5
5
 
6
6
  def self.target_in_edit_mode
7
- includes(:target).references(:labels).merge(Iqvoc::XLLabel.base_class.in_edit_mode)
7
+ includes(:target).references(:labels).merge(Iqvoc::XLLabel.base_class.unpublished)
8
8
  end
9
9
 
10
10
  def self.by_label_origin(origin)
@@ -35,16 +35,22 @@ class Labeling::SKOSXL::Base < Labeling::Base
35
35
  def self.single_query(params = {})
36
36
  query_str = build_query_string(params)
37
37
 
38
- scope = includes(:target).order("LOWER(#{Label::Base.table_name}.value)").references(:labels, :concepts)
38
+ scope = self.includes(:target)
39
+ .references(:labels, :concepts)
40
+ .joins(:target)
41
+ .order(Arel.sql("LENGTH(#{Label::Base.table_name}.value), #{Label::Base.table_name}.value ASC"))
42
+
39
43
  if params[:query].present?
40
- labels = Label::Base.by_query_value(query_str).by_language(params[:languages].to_a).published
44
+ labels = label_class.by_query_value(query_str)
45
+ .by_language(params[:languages].to_a)
46
+ .published
41
47
  scope = scope.merge(labels)
42
48
  else
43
- scope = scope.merge(Label::Base.by_language(params[:languages].to_a).published)
49
+ scope = scope.merge(label_class.by_language(params[:languages].to_a).published)
44
50
  end
45
51
 
46
52
  if params[:collection_origin].present?
47
- collection = Collection::Base.where(origin: params[:collection_origin]).last
53
+ collection = Iqvoc::Collection.base_class.where(origin: params[:collection_origin]).last
48
54
  if collection
49
55
  scope = scope.includes(owner: { collection_members: :collection })
50
56
  scope = scope.where("#{Collection::Member::Base.table_name}.collection_id" => collection.id)
@@ -54,11 +60,60 @@ class Labeling::SKOSXL::Base < Labeling::Base
54
60
  end
55
61
 
56
62
  # apply search entity type
57
- case params[:for]
58
- when 'concept'
59
- scope = scope.includes(:owner).merge(Iqvoc::Concept.base_class.published)
60
- when 'collection'
61
- scope = scope.includes(:owner).merge(Iqvoc::Collection.base_class.published)
63
+ scope = case params[:for]
64
+ when 'concept'
65
+ scope.includes(:owner).merge(Iqvoc::Concept.base_class.published)
66
+ when 'collection'
67
+ scope.includes(:owner).merge(Iqvoc::Collection.base_class.published)
68
+ else
69
+ # no additional conditions
70
+ scope.includes(:owner)
71
+ end
72
+
73
+ scope = if params[:include_expired]
74
+ scope.merge(Concept::Base.not_expired).or(scope.merge(Concept::Base.expired))
75
+ else
76
+ scope.merge(Concept::Base.not_expired)
77
+ end
78
+
79
+ # change note filtering
80
+ if params[:change_note_date_from].present? || params[:change_note_date_to].present?
81
+ change_note_relation = Iqvoc.change_note_class_name.to_relation_name
82
+ concepts = Concept::Base.base_class.published
83
+ .includes(change_note_relation.to_sym => :annotations)
84
+ .references(change_note_relation)
85
+ .references('note_annotations')
86
+
87
+ # change note type filtering
88
+ concepts = case params[:change_note_type]
89
+ when 'created'
90
+ concepts.where('note_annotations.predicate = ?', 'created')
91
+ when 'modified'
92
+ concepts.where('note_annotations.predicate = ?', 'modified')
93
+ else
94
+ concepts.where('note_annotations.predicate = ? OR note_annotations.predicate = ?', 'created', 'modified')
95
+ end
96
+
97
+ if params[:change_note_date_from].present?
98
+ begin
99
+ DateTime.parse(params[:change_note_date_from])
100
+ date_from = params[:change_note_date_from]
101
+ concepts = concepts.where('note_annotations.value >= ?', date_from)
102
+ rescue ArgumentError
103
+ Rails.logger.error "Invalid date was entered for search"
104
+ end
105
+ end
106
+
107
+ if params[:change_note_date_to].present?
108
+ begin
109
+ date_to = DateTime.parse(params[:change_note_date_to]).end_of_day.to_s
110
+ concepts = concepts.where('note_annotations.value <= ?', date_to)
111
+ rescue ArgumentError
112
+ Rails.logger.error "Invalid date was entered for search"
113
+ end
114
+ end
115
+
116
+ scope = scope.includes(:owner).merge(concepts)
62
117
  end
63
118
 
64
119
  scope = yield(scope) if block_given?
@@ -2,7 +2,7 @@ class Labeling::SKOSXL::HiddenLabel < Labeling::SKOSXL::Base
2
2
  self.rdf_namespace = 'skosxl'
3
3
  self.rdf_predicate = 'hiddenLabel'
4
4
 
5
- def self.view_section(obj)
6
- 'hidden'
5
+ def self.view_section_sort_key(obj)
6
+ 70
7
7
  end
8
8
  end
@@ -5,4 +5,8 @@ class Labeling::SKOSXL::PrefLabel < Labeling::SKOSXL::Base
5
5
  def self.only_one_allowed?
6
6
  true
7
7
  end
8
+
9
+ def self.view_section_sort_key(obj)
10
+ 50
11
+ end
8
12
  end
@@ -0,0 +1,115 @@
1
+ <%= bootstrap_form_for concept,
2
+ :as => :concept,
3
+ :url => concept.new_record? ? concepts_path : concept_path(:published => 0, :id => concept),
4
+ :layout => :horizontal do |f| %>
5
+
6
+ <!-- Base data -->
7
+ <fieldset>
8
+ <legend><%= t('txt.common.attributes') %></legend>
9
+ <%= f.text_field :follow_up, :class => 'datepicker' %>
10
+ <%= f.text_field :expired_at, :class => 'datepicker' %>
11
+
12
+ <%- Iqvoc::Concept.additional_association_classes.keys.each do |assoc_class| -%>
13
+ <%= render assoc_class.edit_partial_name(concept),
14
+ :concept => concept, :klass => assoc_class, :f => f %>
15
+ <%- end -%>
16
+ </fieldset>
17
+ <!-- / Base data -->
18
+
19
+ <!-- Labelings -->
20
+ <fieldset>
21
+ <legend><%= Labeling::Base.model_name.human(:count => 2) %></legend>
22
+ <% unless Iqvoc.const_defined?(:SKOSXL) %>
23
+ <p><%= t 'txt.common.hint_csv_input' %></p>
24
+ <% end %>
25
+ <%- Iqvoc::Concept.labeling_classes.each do |labeling_class, languages| -%>
26
+ <%- languages.each do |language| -%>
27
+ <%= render labeling_class.edit_partial_name(concept), :f => f,
28
+ :concept => concept, :klass => labeling_class, :language => language %>
29
+ <%- end -%>
30
+ <%- end -%>
31
+ <div class="form-group">
32
+ <div class="col-sm-2">
33
+ <%= link_to t("txt.views.labels.new"), concept_new_label_path, class: 'btn btn-outline-secondary new-label-modal' %>
34
+ </div>
35
+ </div>
36
+ </fieldset>
37
+ <!-- / Labelings -->
38
+
39
+ <!-- Concept relations -->
40
+ <fieldset>
41
+ <legend><%= Concept::Relation::Base.model_name.human(:count => 2) %></legend>
42
+ <% unless Iqvoc::Concept.broader_relation_class.edit_partial_name(concept).nil? %>
43
+ <%- if Iqvoc::Concept.broader_relation_class.narrower_editable -%>
44
+ <%= render Iqvoc::Concept.broader_relation_class.narrower_class.edit_partial_name(concept),
45
+ :concept => concept, :klass => Iqvoc::Concept.broader_relation_class.narrower_class, :f => f %>
46
+ <%- end -%>
47
+
48
+ <%= f.form_group :top_term do %>
49
+ <%= f.check_box :top_term,
50
+ :class => ("exclusive" if Iqvoc::Concept.broader_relation_class.singular?) %>
51
+ <% end %>
52
+
53
+ <%= render Iqvoc::Concept.broader_relation_class.edit_partial_name(concept),
54
+ :concept => concept, :klass => Iqvoc::Concept.broader_relation_class, :f => f %>
55
+ <% end %>
56
+
57
+ <%- Iqvoc::Concept.further_relation_classes.each do |relation_class| -%>
58
+ <%= render relation_class.edit_partial_name(concept),
59
+ :concept => concept, :klass => relation_class, :f => f %>
60
+ <%- end -%>
61
+ </fieldset>
62
+ <!-- / Concept relations -->
63
+
64
+ <!-- Collections -->
65
+ <fieldset>
66
+ <legend><%= Iqvoc::Collection.base_class.model_name.human(:count => 2) %></legend>
67
+ <%= f.form_group :assigned_collection_origins, :label => {:text => t('txt.common.type_to_search')} do %>
68
+ <%= text_field_tag "concept[assigned_collection_origins]",
69
+ concept.assigned_collection_origins.join(InlineDataHelper::JOINER),
70
+ :class => "entity_select",
71
+ :"data-query-url" => collections_path(:format => :json),
72
+ :"data-entity-uri" => collection_path(:id => "{id}"),
73
+ :"data-entities" => concept.collections.map { |c| collection_widget_data(c) }.to_json %>
74
+ <% end %>
75
+ </fieldset>
76
+ <!-- /Collection -->
77
+
78
+ <!-- Notes ohne Change Note class -->
79
+ <% Iqvoc::Concept.note_classes.reject { |n| n == Iqvoc.change_note_class }.each do |note_class| %>
80
+ <% unless note_class.edit_partial_name(concept).nil? %>
81
+ <%= render note_class.edit_partial_name(concept), :owner_klass => concept, :assoc_klass => note_class, :f => f %>
82
+ <% end %>
83
+ <% end %>
84
+ <!-- / Notes -->
85
+
86
+ <!-- Matches -->
87
+ <fieldset class="matches" data-datasets="<%= @datasets %>" data-remote-proxy-url="<%= alphabetical_concepts_path %>" data-translation-other="<%= t('txt.common.other') %>" data-no-results-msg="<%= t('txt.views.search_results.no_results') %>">
88
+ <legend><%= Match::Base.model_name.human(:count => 2) %></legend>
89
+ <% Iqvoc::Concept.match_classes.each do |match_class| %>
90
+ <%= render match_class.edit_partial_name(concept), :owner_klass => concept, :assoc_klass => match_class, :f => f %>
91
+ <% end %>
92
+ </fieldset>
93
+ <!-- / Matches -->
94
+
95
+ <!-- Notations -->
96
+ <% Iqvoc::Concept.notation_classes.each do |notation_class| %>
97
+ <%= render notation_class.edit_partial_name(concept), :owner_klass => concept, :assoc_klass => notation_class, :f => f %>
98
+ <% end %>
99
+ <!-- / Notations -->
100
+
101
+ <!-- Change Note class -->
102
+ <% note_class = Iqvoc.change_note_class %>
103
+ <% unless note_class.edit_partial_name(concept).nil? %>
104
+ <%= render note_class.edit_partial_name(concept), :owner_klass => concept, :assoc_klass => note_class, :f => f %>
105
+ <% end %>
106
+ <!-- / Change Note class -->
107
+
108
+ <hr />
109
+
110
+ <div class="mb-5">
111
+ <%= f.submit t("txt.common.save"), :class => "btn btn-primary" %>
112
+ <%= link_to t("txt.common.cancel"), concept.new_record? ? dashboard_path : concept_path(:published => 0, :id => concept), :class => "btn btn-outline-secondary" %>
113
+ </div>
114
+
115
+ <% end %>
@@ -5,7 +5,15 @@
5
5
 
6
6
  <fieldset id="label_base_data">
7
7
  <legend><%= t("txt.common.attributes") %></legend>
8
- <%= f.text_field :value %>
8
+ <%= f.text_field :value,
9
+ autofocus: true,
10
+ autocomplete: 'off',
11
+ data: {
12
+ 'query-url': labels_path(:format => :json),
13
+ 'entity-uri' => label_path(:id => '{id}'),
14
+ 'duplicate-message': t("txt.common.duplicate_labels"),
15
+ 'duplicate-check-mode': Iqvoc.config['label_duplicate_check_mode'] || 'exact_match',
16
+ } %>
9
17
 
10
18
  <%= f.select :language, Iqvoc.all_languages %>
11
19
 
@@ -42,8 +50,8 @@
42
50
 
43
51
  <hr />
44
52
 
45
- <div class="well">
53
+ <div class="mb-5">
46
54
  <%= f.submit t("txt.common.save"), :class => 'btn btn-primary' %>
47
- <%= link_to t("txt.common.cancel"), label_path(:id => label, :published => 0), :class => "btn btn-default" %>
55
+ <%= link_to t("txt.common.cancel"), label.new_record? ? dashboard_path : label_path(:id => label, :published => 0), :class => "btn btn-outline-secondary" %>
48
56
  </div>
49
57
  <% end %>
@@ -0,0 +1,4 @@
1
+ <div class="panel">
2
+ <h2><%= t("txt.views.labels.language") %></h2>
3
+ <%= label.language %>
4
+ </div>
@@ -1,13 +1,19 @@
1
1
  <% published_param = label.published? ? nil : 0 %>
2
2
 
3
3
  <%= sidebar do %>
4
- <%= sidebar_header t('txt.common.representations') %>
5
- <%= sidebar_item :icon => 'share', :text => 'HTML', :path => rdf_url(label.origin, :format => :html, :published => published_param, :lang => nil) %>
6
- <%= sidebar_item :icon => 'share', :text => 'RDF/XML', :path => rdf_url(label.origin, :format => :rdf, :published => published_param, :lang => nil), :id => 'rdf_link_xml' %>
7
- <%= sidebar_item :icon => 'share', :text => 'RDF/Turtle', :path => rdf_url(label.origin, :format => :ttl, :published => published_param, :lang => nil), :id => 'rdf_link_ttl' %>
8
- <%= sidebar_item :icon => 'share', :text => 'RDF/NTriples', :path => rdf_url(label.origin, :format => :nt, :published => published_param, :lang => nil), :id => 'rdf_link_nt' %>
4
+ <% unless label.new_record? %>
5
+ <%= sidebar_header t('txt.common.representations') %>
6
+ <%= sidebar_item :icon => 'share', :text => 'HTML', :path => rdf_url(label.origin, :format => :html, :published => published_param, :lang => nil) %>
7
+ <%= sidebar_item :icon => 'share', :text => 'RDF/XML', :path => rdf_url(label.origin, :format => :rdf, :published => published_param, :lang => nil), :id => 'rdf_link_xml' %>
8
+ <%= sidebar_item :icon => 'share', :text => 'RDF/Turtle', :path => rdf_url(label.origin, :format => :ttl, :published => published_param, :lang => nil), :id => 'rdf_link_ttl' %>
9
+ <%= sidebar_item :icon => 'share', :text => 'RDF/NTriples', :path => rdf_url(label.origin, :format => :nt, :published => published_param, :lang => nil), :id => 'rdf_link_nt' %>
10
+ <% end %>
9
11
 
10
12
  <%= sidebar_header 'Links' %>
11
- <%= sidebar_item :icon => 'link', :text => t('txt.models.label.uri'), :path => rdf_url(label.origin, :format => nil, :published => published_param, :lang => nil) %>
12
- <%= render Iqvoc::XLLabel.base_class.new_link_partial_name %>
13
+ <% unless label.new_record? %>
14
+ <%= sidebar_item :icon => 'link', :text => t('txt.models.label.uri'), :path => rdf_url(label.origin, :format => nil, :published => published_param, :lang => nil) %>
15
+ <% end %>
16
+ <% Iqvoc.first_level_classes.each do |klass| %>
17
+ <%= sidebar_item { render(klass.new_link_partial_name) } %>
18
+ <% end %>
13
19
  <% end %>
@@ -0,0 +1,4 @@
1
+ <%= page_header :title => t("txt.views.labels.new") %>
2
+
3
+ <%= error_messages_for @new_label %>
4
+ <%= render 'form', :label => @new_label %>
@@ -2,3 +2,4 @@
2
2
 
3
3
  <%= error_messages_for @label %>
4
4
  <%= render 'form', :label => @label %>
5
+ <%= render 'sidebar', :label => @label %>
@@ -0,0 +1,28 @@
1
+ <div class="modal-dialog modal-lg" role="document">
2
+ <div class="modal-content">
3
+ <div class="modal-header">
4
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
5
+ <span aria-hidden="true">&times;</span>
6
+ </button>
7
+ <h1 class="modal-title"><%= t("txt.views.labels.new") %></h1>
8
+ </div>
9
+ <%= bootstrap_form_for @label,
10
+ :as => :label,
11
+ :url => concept_create_label_path,
12
+ :layout => :horizontal, remote: true do |f| %>
13
+ <div class="modal-body">
14
+ <fieldset id="label_base_data">
15
+ <legend><%= t("txt.common.attributes") %></legend>
16
+ <%= f.text_field :value %>
17
+
18
+ <%= f.select :language, Iqvoc.all_languages %>
19
+ </fieldset>
20
+ </div>
21
+
22
+ <div class="modal-footer">
23
+ <%= f.submit t("txt.common.save"), :class => 'btn btn-primary', onclick: "$('#concept-teaser-modal').modal('hide');" %>
24
+ <button type="button" class="btn btn-outline-secondary" data-dismiss="modal"><%= t("txt.common.cancel") %></button>
25
+ </div>
26
+ <% end %>
27
+ </div>
28
+ </div>
@@ -6,7 +6,6 @@
6
6
  <%= label_relation.class.model_name.human %>
7
7
  <%= link_to(label_relation.range.value,
8
8
  label_path(:published => 0, :id => label_relation.range)) %>
9
- <%= t("txt.common.editor") %> <%= user_details(concept_relation.target.locking_user) %>
10
9
  </li>
11
10
  <% end %>
12
11
  </ul>