talia_core 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/README.rdoc +6 -27
  2. data/VERSION.yml +3 -2
  3. data/config/database.yml +11 -11
  4. data/config/talia_core.yml +11 -6
  5. data/config/talia_core.yml.example +11 -6
  6. data/generators/talia_base/talia_base_generator.rb +3 -0
  7. data/generators/talia_base/templates/README +1 -1
  8. data/generators/talia_base/templates/app/controllers/source_data_controller.rb +1 -1
  9. data/generators/talia_base/templates/app/controllers/sources_controller.rb +31 -12
  10. data/generators/talia_base/templates/app/helpers/sources_helper.rb +77 -1
  11. data/generators/talia_base/templates/app/views/layouts/sources.html.erb +22 -0
  12. data/generators/talia_base/templates/app/views/sources/_data_list.html.erb +17 -0
  13. data/generators/talia_base/templates/app/views/sources/_property_item.html.erb +10 -0
  14. data/generators/talia_base/templates/app/views/sources/_property_list.html.erb +13 -0
  15. data/generators/talia_base/templates/app/views/sources/index.html.erb +16 -11
  16. data/generators/talia_base/templates/app/views/sources/semantic_templates/default/default.html.erb +8 -19
  17. data/generators/talia_base/templates/config/routes.rb +11 -0
  18. data/generators/talia_base/templates/migrations/create_semantic_relations.rb +2 -1
  19. data/generators/talia_base/templates/public/images/core/arrow.png +0 -0
  20. data/generators/talia_base/templates/public/images/core/building.png +0 -0
  21. data/generators/talia_base/templates/public/images/core/contents_top_left.gif +0 -0
  22. data/generators/talia_base/templates/public/images/core/document-horizontal-text.png +0 -0
  23. data/generators/talia_base/templates/public/images/core/document.png +0 -0
  24. data/generators/talia_base/templates/public/images/core/gear.png +0 -0
  25. data/generators/talia_base/templates/public/images/core/group.png +0 -0
  26. data/generators/talia_base/templates/public/images/core/header_bg.gif +0 -0
  27. data/generators/talia_base/templates/public/images/core/image.png +0 -0
  28. data/generators/talia_base/templates/public/images/core/imagebig.png +0 -0
  29. data/generators/talia_base/templates/public/images/core/left_edge.gif +0 -0
  30. data/generators/talia_base/templates/public/images/core/letter.png +0 -0
  31. data/generators/talia_base/templates/public/images/core/line.png +0 -0
  32. data/generators/talia_base/templates/public/images/core/logo.gif +0 -0
  33. data/generators/talia_base/templates/public/images/core/map.png +0 -0
  34. data/generators/talia_base/templates/public/images/core/period.png +0 -0
  35. data/generators/talia_base/templates/public/images/core/person.png +0 -0
  36. data/generators/talia_base/templates/public/images/core/person_default.png +0 -0
  37. data/generators/talia_base/templates/public/images/core/place.png +0 -0
  38. data/generators/talia_base/templates/public/images/core/source.png +0 -0
  39. data/generators/talia_base/templates/public/images/core/television.png +0 -0
  40. data/generators/talia_base/templates/public/images/core/text.png +0 -0
  41. data/generators/talia_base/templates/public/images/core/type.png +0 -0
  42. data/generators/talia_base/templates/public/images/core/video.png +0 -0
  43. data/generators/talia_base/templates/public/stylesheets/img/arrow.png +0 -0
  44. data/generators/talia_base/templates/public/stylesheets/main.css +276 -0
  45. data/generators/talia_base/templates/script/configure_talia +1 -1
  46. data/generators/talia_base/templates/script/setup_talia_backend +2 -0
  47. data/lib/core_ext/platform.rb +1 -0
  48. data/lib/core_ext/string.rb +6 -0
  49. data/lib/talia_core/active_source.rb +62 -3
  50. data/lib/talia_core/active_source_parts/class_methods.rb +36 -122
  51. data/lib/talia_core/active_source_parts/finders.rb +158 -0
  52. data/lib/talia_core/active_source_parts/predicate_handler.rb +7 -8
  53. data/lib/talia_core/active_source_parts/xml/generic_reader.rb +95 -11
  54. data/lib/talia_core/active_source_parts/xml/rdf_builder.rb +6 -13
  55. data/lib/talia_core/active_source_parts/xml/source_reader.rb +8 -3
  56. data/lib/talia_core/data_types/data_loader.rb +14 -6
  57. data/lib/talia_core/data_types/data_record.rb +5 -1
  58. data/lib/talia_core/data_types/iip_data.rb +1 -1
  59. data/lib/talia_core/data_types/mime_mapping.rb +8 -3
  60. data/lib/talia_core/errors.rb +4 -0
  61. data/lib/talia_core/initializer.rb +1 -8
  62. data/lib/talia_core/property_string.rb +58 -0
  63. data/lib/talia_core/semantic_collection_item.rb +3 -2
  64. data/lib/talia_core/semantic_collection_wrapper.rb +236 -198
  65. data/lib/talia_core/source.rb +130 -178
  66. data/lib/talia_core/source_types/collection.rb +15 -0
  67. data/lib/talia_core/source_types/dc_resource.rb +22 -0
  68. data/lib/talia_core/source_types/dummy_source.rb +22 -0
  69. data/lib/talia_core.rb +0 -1
  70. data/lib/talia_util/import_job_helper.rb +44 -16
  71. data/lib/talia_util/io_helper.rb +21 -1
  72. data/lib/talia_util/rake_tasks.rb +48 -72
  73. data/lib/talia_util/rdf_update.rb +22 -13
  74. data/lib/talia_util/test_helpers.rb +1 -1
  75. data/lib/talia_util.rb +0 -2
  76. data/test/core_ext/string_test.rb +5 -0
  77. data/test/talia_core/active_source_test.rb +151 -14
  78. data/test/talia_core/generic_xml_test.rb +46 -2
  79. data/test/talia_core/initializer_test.rb +0 -1
  80. data/test/talia_core/property_string_test.rb +78 -0
  81. data/test/talia_core/source_reader_test.rb +5 -1
  82. data/test/talia_core/source_test.rb +23 -32
  83. data/test/talia_util/import_job_helper_test.rb +1 -1
  84. data/test/talia_util/io_helper_test.rb +44 -0
  85. metadata +399 -373
  86. data/generators/talia_base/templates/app/views/sources/semantic_templates/default/province.html.erb +0 -19
  87. data/lib/acts_as_roled.rb +0 -11
  88. data/lib/talia_core/collection.rb +0 -13
  89. data/lib/talia_core/dc_resource.rb +0 -20
  90. data/lib/talia_core/dummy_source.rb +0 -20
  91. data/lib/talia_core/rails_ext/actionpack/action_controller/record_identifier.rb +0 -13
  92. data/lib/talia_core/rails_ext/actionpack/action_controller.rb +0 -1
  93. data/lib/talia_core/rails_ext/actionpack.rb +0 -1
  94. data/lib/talia_core/rails_ext.rb +0 -1
  95. data/lib/talia_util/data_import.rb +0 -91
  96. data/lib/talia_util/yaml_import.rb +0 -80
@@ -0,0 +1,276 @@
1
+ /* CSS Document */
2
+
3
+
4
+ /* ***************** ************** ************** */
5
+ /* ***************** TAG GENERICI ************** */
6
+ /* ***************** ************** ************** */
7
+ * {margin: 0; padding: 0;}
8
+
9
+
10
+ body {
11
+ text-align:left;
12
+ color:#333;
13
+ margin: 0;
14
+ padding: 0;
15
+ border: 0;
16
+ font-family: Avenir, "Lucida Grande", Verdana, "Bitstream Vera Sans", Arial, Helvetica, sans-serif;
17
+ font-size:0.8125em;
18
+ background: #FFF url(/images/core/left_edge.gif) top left repeat-y;
19
+ }
20
+
21
+
22
+ /* DEFINIZIONE TAG */
23
+ a{
24
+ color: #355a8e;
25
+ text-decoration: none;
26
+ outline: none;
27
+ }
28
+ a:hover{
29
+ color: #355a8e;
30
+ text-decoration: underline;
31
+ background-color: transparent;
32
+ }
33
+ h1{
34
+ font-size:1.3em;
35
+ margin-bottom: 5px;
36
+ }
37
+ h2{
38
+ font-size:1.2em;
39
+ margin-bottom: 5px;
40
+ }
41
+ h3{
42
+ font-size:1.1em;
43
+ margin-bottom: 5px;
44
+ }
45
+ p{
46
+ color:#333333;
47
+ line-height:1.7em;
48
+ font-size:0.9em;
49
+ margin-bottom: 5px;
50
+ }
51
+
52
+ td {
53
+ padding-right: 3ex;
54
+ }
55
+ /* DEFINIZIONE TAG */
56
+
57
+
58
+ /* Taglist */
59
+ div.tags {
60
+ margin-bottom: 0.5em;
61
+ margin-top: 0.5em;
62
+ padding: 0.3em;
63
+ background-color: #F1F1F1;
64
+ line-height: 1.5em;
65
+ }
66
+
67
+ span.tag {
68
+ background-color: #C0C0C0;
69
+ margin: 5px;
70
+ }
71
+
72
+ span.tag_selected {
73
+ background-color: #A0A0E0;
74
+ margin: 5px;
75
+ }
76
+
77
+ /* ***************** ************** ************** */
78
+ /* ***************** CLASSI RICORRENTI ************** */
79
+ /* ***************** ************** ************** */
80
+ .hidden{
81
+ display:none;
82
+ }
83
+
84
+ .floatClear{
85
+ clear:both;
86
+ }
87
+
88
+ /* ***************** ************** ************** */
89
+ /* ***************** HEADER ************** */
90
+ /* ***************** ************** ************** */
91
+
92
+
93
+ #title_bar h1{
94
+ padding: 13px 0 0 13px;
95
+ }
96
+ #title_bar h1 a{
97
+ font-size:1.7em;
98
+ color:#FFFFFF;
99
+ display: block;
100
+ width: 235px;
101
+ height: 97px;
102
+ background: transparent url(/images/core/logo.gif) top left no-repeat;
103
+ text-indent: -9999px;
104
+ }
105
+
106
+ #title_bar p.header_subtitle{
107
+ display: none;
108
+ }
109
+
110
+ div#title_bar{
111
+ height: 122px;
112
+ margin:0;
113
+ padding:0;
114
+ border:0;
115
+ width:100%;
116
+ background:#666 url(/images/core/header_bg.gif) top left repeat;
117
+ }
118
+
119
+ /* ***************** ************** ************** */
120
+ /* ***************** CONTENTS ************** */
121
+ /* ***************** ************** ************** */
122
+ #contents {
123
+ padding: 25px;
124
+ background:transparent url(/images/core/contents_top_left.gif) top left repeat-x;
125
+ }
126
+
127
+ /* ***************** ************** ************** */
128
+ /* ***************** FOOTER ************** */
129
+ /* ***************** ************** ************** */
130
+ /* tree: #footer h1, #footer p */
131
+ #footer.open{
132
+ margin: 0 0 0 300px;
133
+ }
134
+
135
+ /* !!!! SIDE BAR CHIUSO !!!! */
136
+ #footer.closed{
137
+ margin-left:73px;
138
+ }
139
+
140
+ #select-container {
141
+ margin-bottom: 3ex;
142
+ }
143
+
144
+
145
+ /* ***************** ************** ************** */
146
+ /* ***************** Barbz demo stuff ************** */
147
+ /* ***************** ************** ************** */
148
+ .sources_list ul {
149
+ width: 100%;
150
+ list-style: none;
151
+ }
152
+
153
+ .sources_list ul li {
154
+ border-bottom: 1px solid #d8d8d8;
155
+ width: 100%;
156
+ padding-bottom: 0;
157
+ float: left;
158
+ }
159
+
160
+ .sources_list ul li p {
161
+ float: left;
162
+ width: 100%;
163
+ background: #f9f9f9;
164
+ margin: 0;
165
+ padding:0 }
166
+
167
+ .sources_list ul li p .source_type {
168
+ display: block;
169
+ float: left;
170
+ width: 10%;
171
+ padding:6px 1%;
172
+ /*background:#f8f8f8 url(img/type.png) repeat-x bottom;*/
173
+ /*border-bottom: 1px solid #ccc;*/
174
+ voice-family: "\"}\"";
175
+ voice-family:inherit;
176
+ width:8%
177
+ }
178
+
179
+ .sources_list ul li p .source_title {
180
+ display: block;
181
+ float: left;
182
+ width: 45%;
183
+ font-size:12px ;
184
+ background: #f2f2f2;
185
+ font-weight: bold;
186
+ padding:6px 1% ;
187
+ voice-family: "\"}\"";
188
+ voice-family:inherit;
189
+ width:43%
190
+ }
191
+
192
+
193
+
194
+ .sources_list ul li p .source-data {
195
+ display: block;
196
+ float: left;
197
+ width: 35%;
198
+ padding: 7px 1% 7px 1%;
199
+ voice-family: "\"}\"";
200
+ voice-family:inherit;
201
+ width:33%
202
+ }
203
+
204
+ .sources_list ul li p .more {
205
+ width: 10%;
206
+ float: left;
207
+ padding: 6px 0; font-size:12px ;
208
+ background: url(img/arrow.png) no-repeat right;
209
+ display: block;
210
+ }
211
+
212
+
213
+
214
+ .sources_list ul li p .more a{
215
+ color: #999;
216
+ }
217
+
218
+ a img {
219
+ border: 0px none;
220
+ }
221
+
222
+ /* Styles for the Person template*/
223
+
224
+ div#tl {
225
+ margin-bottom: 30px;
226
+ margin-top: 30px;
227
+ }
228
+
229
+
230
+ .properties_list ul {
231
+ width: 100%;
232
+ list-style: none;
233
+ }
234
+
235
+ .properties_list ul li {
236
+ border-bottom: 1px solid #d8d8d8;
237
+ width: 100%;
238
+ padding-bottom: 0;
239
+ float: left;
240
+ }
241
+
242
+ .properties_list ul li p {
243
+ float: left;
244
+ width: 100%;
245
+ background: #f9f9f9;
246
+ margin: 0;
247
+ padding:0 }
248
+
249
+ .properties_list ul li p .predicate {
250
+ display: block;
251
+ float: left;
252
+ width: 10%;
253
+ padding:6px 1%;
254
+ /*background:#f8f8f8 url(img/type.png) repeat-x bottom;*/
255
+ /*border-bottom: 1px solid #ccc;*/
256
+ voice-family: "\"}\"";
257
+ voice-family:inherit;
258
+ width:8%
259
+ }
260
+
261
+ .properties_list ul li p .value {
262
+ display: block;
263
+ float: left;
264
+ width: 45%;
265
+ font-size:12px ;
266
+ background: #f2f2f2;
267
+ font-weight: bold;
268
+ padding:6px 1% ;
269
+ voice-family: "\"}\"";
270
+ voice-family:inherit;
271
+ width:43%
272
+ }
273
+ .person hr
274
+ {
275
+ margin-top:30px;
276
+ }
@@ -1,4 +1,4 @@
1
- #!/bin/env ruby
1
+ #!/Developer/Talia/jruby-1.3.1_2.3/bin/jruby
2
2
 
3
3
  require 'rubygems'
4
4
  gem 'activerecord'
@@ -24,6 +24,8 @@ if(Rails::VERSION::MAJOR > 2 ||(Rails::VERSION::MAJOR == 2 && Rails::VERSION::MI
24
24
  Commands::Plugin.parse!(['install', 'git://github.com/lackac/render_component.git', '-r', 'rails-edge'])
25
25
  end
26
26
 
27
+ puts "Install the auto completion plugin"
28
+ Commands::Plugin.parse!(['install', 'auto_complete'])
27
29
 
28
30
  puts "Install the adminstration backend"
29
31
  Rails::Generator::Scripts::Generate.new.run(%w(talia_admin))
@@ -4,6 +4,7 @@ module Platform # :nodoc:
4
4
  def jruby?
5
5
  RUBY_PLATFORM =~ /java/
6
6
  end
7
+
7
8
  end
8
9
 
9
10
  extend Platform
@@ -3,4 +3,10 @@ class String
3
3
  def to_permalink
4
4
  self.gsub(/\W+/, ' ').strip.downcase.titleize.gsub(/\ +/, '_')
5
5
  end
6
+
7
+ # Give a URI object created from the current string
8
+ def to_uri
9
+ N::URI.new(self)
10
+ end
11
+
6
12
  end
@@ -24,6 +24,7 @@ module TaliaCore
24
24
  include RDFS::ResourceLike
25
25
 
26
26
  extend ActiveSourceParts::ClassMethods
27
+ extend ActiveSourceParts::Finders
27
28
  extend ActiveSourceParts::SqlHelper
28
29
  include ActiveSourceParts::PredicateHandler
29
30
  extend ActiveSourceParts::PredicateHandler::ClassMethods
@@ -49,7 +50,7 @@ module TaliaCore
49
50
  :class_name => 'TaliaCore::SemanticRelation'
50
51
  has_many :subjects, :through => :related_subjects
51
52
 
52
- validates_format_of :uri, :with => /\A\S*:.*\Z/
53
+ validates_format_of :uri, :with => /\A\S*:.*\Z/, :message => '<{{value}}> does not look like an uri.'
53
54
  validates_uniqueness_of :uri
54
55
 
55
56
  before_destroy :remove_inverse_properties # Remove inverse properties when destroying an element
@@ -67,6 +68,11 @@ module TaliaCore
67
68
 
68
69
  validate :check_uri
69
70
 
71
+ # Uri in short notation
72
+ def short_uri
73
+ N::URI.new(self.uri).to_name_s
74
+ end
75
+
70
76
  # Helper
71
77
  def value_for(thing)
72
78
  self.class.value_for(thing)
@@ -77,6 +83,11 @@ module TaliaCore
77
83
  def to_s
78
84
  self[:uri]
79
85
  end
86
+
87
+ # Create a new uri object
88
+ def to_uri
89
+ self[:uri].to_uri
90
+ end
80
91
 
81
92
  # Works in the normal way for database attributes. If the value
82
93
  # is not an attribute, it tries to find objects related to this source
@@ -107,6 +118,53 @@ module TaliaCore
107
118
  alias :update_attributes_orig :update_attributes
108
119
  alias :update_attributes_orig! :update_attributes!
109
120
 
121
+
122
+ # Updates the source with the given properties. The 'mode' field indicates if
123
+ # and how the update will be performed. See the ImportJobHelper class for
124
+ # the different modes.
125
+ #
126
+ # As opposed to the *_attributes method, this will also handle file elements.
127
+ # The default mode is :skip (do nothing)
128
+ def update_source(properties, mode)
129
+ properties.to_options!
130
+ mode = :update if(self.is_a?(SourceTypes::DummySource)) # Dummy sources are always updated
131
+ mode ||= :skip
132
+ mode = mode.to_sym
133
+ return self if(mode == :skip) # If we're told to ignore updates
134
+
135
+ # Deal with already existing sources
136
+ files = properties.delete(:files)
137
+
138
+ if(mode == :overwrite)
139
+ # If we are to overwrite, delete all relations and update normally
140
+ self.semantic_relations.destroy_all
141
+ self.data_records.destroy_all
142
+ mode = :update
143
+ elsif(mode == :update && files && self.data_records.size > 0)
144
+ # On updating we should only remove the files if there are new ones
145
+ self.data_records.destroy_all
146
+ end
147
+
148
+ # Add any files
149
+ attach_files(files) if(files)
150
+
151
+ # Rewrite the type, if neccessary
152
+ type = properties[:type]
153
+ switch_type = type && (self.type != type)
154
+ # Warn to the log if we have a problematic type change
155
+ TaliaCore.logger.warn("WARNING: Type change from #{self.type} to #{type}") if(switch_type && !self.is_a?(SourceTypes::DummySource))
156
+ self.type = type if(switch_type)
157
+
158
+ # Now we should either be adding or updating
159
+ assit(mode == :update || mode == :add)
160
+ update = (mode == :update)
161
+
162
+ # Overwrite with or add the imported attributes
163
+ update ? rewrite_attributes(properties) : update_attributes(properties)
164
+
165
+ self
166
+ end
167
+
110
168
  # Updates *all* attributes of this source. For the database attributes, this works
111
169
  # exactly like ActiveRecord::Base#update_attributes
112
170
  #
@@ -304,6 +362,7 @@ module TaliaCore
304
362
  # given, it will retrieve only the specified data element
305
363
  def data(type = nil, location= nil)
306
364
  find_type = location ? :first : :all # Find just one element if a location is given
365
+ type = type.name if(type.is_a?(Class))
307
366
  options = {}
308
367
  options[:conditions] = [ "type = ?", type ] if(type && !location)
309
368
  options[:conditions] = [ "type = ? AND location = ?", type, location ] if(type && location)
@@ -331,13 +390,13 @@ module TaliaCore
331
390
  # string it will be returned as a string.
332
391
  def target_for(value)
333
392
  return value if(value.kind_of?(N::URI) || value.kind_of?(ActiveSource))
334
- assit_kind_of(String, value)
393
+ assit_block { |msg| msg << "Expected #{value.inspect} to be a String" unless(value.is_a?(String)) ; value.is_a?(String) }
335
394
  value.strip!
336
395
  if((value[0..0] == '<') && (value[-1..-1] == '>'))
337
396
  value = ActiveSource.expand_uri(value [1..-2])
338
397
  val_src = ActiveSource.find(:first, :conditions => { :uri => value })
339
398
  if(!val_src)
340
- value = DummySource.new(value)
399
+ value = SourceTypes::DummySource.new(value)
341
400
  value.save!
342
401
  else
343
402
  value = val_src
@@ -19,9 +19,13 @@ module TaliaCore
19
19
  # on creation. This will call the attach_files method on the object.
20
20
  def new(*args)
21
21
  the_source = if((args.size == 1) && (args.first.is_a?(Hash)))
22
+ options = args.first
23
+ options.to_options!
24
+
22
25
  # We have an option hash to init the source
23
- files = args.first.delete(:files) || args.first.delete('files')
24
- attributes = split_attribute_hash(args.first)
26
+ files = options.delete(:files)
27
+ options[:uri] = uri_string_for(options[:uri])
28
+ attributes = split_attribute_hash(options)
25
29
  the_source = super(attributes[:db_attributes])
26
30
  the_source.add_semantic_attributes(false, attributes[:semantic_attributes])
27
31
  the_source.attach_files(files) if(files)
@@ -41,7 +45,8 @@ module TaliaCore
41
45
  # like #new, but it will correctly initialize a source of the type given
42
46
  # in the hash. If no type is given, this will create a plain ActiveSource.
43
47
  def create_source(args)
44
- type = args.delete(:type) || args.delete('type') || 'ActiveSource'
48
+ args.to_options!
49
+ type = args.delete(:type) || 'TaliaCore::ActiveSource'
45
50
  klass = type.constantize
46
51
  klass.new(args)
47
52
  end
@@ -58,12 +63,17 @@ module TaliaCore
58
63
  # [*reader*] The reader class that the import should use
59
64
  # [*progressor*] The progress reporting object, which must respond to run_with_progress(message, size, &block)
60
65
  # [*errors*] If given, all erors will be looged to this array instead of raising
61
- # an exception
66
+ # an exception. See the create_multi_from method for more.
67
+ # [*duplicates*] How to treat alredy existing sources. See ImportJobHelper for more
68
+ # documentation
69
+ # [*base_file_uri*] The base uri to import file from
62
70
  def create_from_xml(xml, options = {})
63
- reader = options[:reader] ? options[:reader].to_s.classify.constantize : TaliaCore::ActiveSourceParts::Xml::SourceReader
64
- source_properties = reader.sources_from(xml, options[:progressor])
65
- self.progressor = options[:progressor]
66
- sources = create_multi_from(source_properties)
71
+ options.to_options!
72
+ options.assert_valid_keys(:reader, :progressor, :errors, :duplicates, :base_file_uri)
73
+ reader = options[:reader] ? options.delete(:reader).to_s.classify.constantize : TaliaCore::ActiveSourceParts::Xml::SourceReader
74
+ source_properties = reader.sources_from(xml, options[:progressor], options.delete(:base_file_uri))
75
+ self.progressor = options.delete(:progressor)
76
+ sources = create_multi_from(source_properties, options)
67
77
  (sources.size > 1) ? sources : sources.first
68
78
  end
69
79
 
@@ -72,32 +82,35 @@ module TaliaCore
72
82
  # correctly.
73
83
  #
74
84
  # Options:
75
- # [*errors*] If given, all erors will be looged to this array instead of raising
76
- # an exception
85
+ # [*errors*] If given, all erors will be logged to this array instead of raising
86
+ # an exception. Each "entry" in the error array will be an Error object
87
+ # containing the origianl stack trace of the error
88
+ # [*duplicates*] Indicates how to deal with sources that already exist in the
89
+ # datastore. See the ImportJobHelper class for a documentation of
90
+ # this option. Default is :skip
77
91
  def create_multi_from(sources, options = {})
92
+ options.to_options!
93
+ options.assert_valid_keys(:errors, :duplicates)
78
94
  source_objects = []
79
95
  run_with_progress('Writing imported', sources.size) do |progress|
80
96
  source_objects = sources.collect do |props|
97
+ props.to_options!
81
98
  src = nil
82
99
  begin
83
- if(src = ActiveSource.find(:first, :conditions => { :uri => (props[:uri] || props['uri']) }))
84
- # Deal with already existing sources
85
- src.rewrite_attributes(props)
86
- # Rewrite the type, if neccessary
87
- type = props[:type] || props['type']
88
- switch_type = type && (src.type != type)
89
- # Warn to the log if we have a problematic type change
90
- TaliaCore.logger.warn("WARNING: Type change from #{src.type} to #{type}") if(switch_type && !src.is_a?(DummySource))
91
- src.type = type if(switch_type)
92
- src
100
+ props[:uri] = uri_string_for(props[:uri])
101
+ assit(props[:uri], "Must have a valid uri at this step")
102
+ if(src = ActiveSource.find(:first, :conditions => { :uri => props[:uri] }))
103
+ src.update_source(props, options[:duplicates])
93
104
  else
94
105
  src = ActiveSource.create_source(props)
95
106
  end
96
107
  src.save!
97
108
  rescue Exception => e
98
109
  if(options[:errors])
99
- options[:errors] << "ERROR during import of #{props['uri'] || props[:uri]}: #{e.message}"
100
- TALIA_CORE.logger.warn("Problems importing #{props['uri'] || props[:uri]} (logged): #{e.message}")
110
+ err = ImportError.new("ERROR during import of #{props[:uri]}: #{e.message}")
111
+ err.set_backtrace(e.backtrace)
112
+ options[:errors] << err
113
+ TaliaCore.logger.warn("Problems importing #{props[:uri]} (logged): #{e.message}")
101
114
  else
102
115
  raise
103
116
  end
@@ -119,41 +132,6 @@ module TaliaCore
119
132
  end
120
133
  end
121
134
 
122
-
123
- # Finder also accepts uris as "ids". There are also some additional options
124
- # that are accepted:
125
- #
126
- # [*:find_through*] accepts and array with an predicate name and an object
127
- # value/uri, to search for predicates that match the given predicate/value
128
- # combination
129
- # [*:type*] specifically looks for sources with the given type.
130
- # [*:find_through_inv*] like :find_through, but for the "inverse" lookup
131
- # [*:prefetch_relations*] if set to "true", this will pre-load all semantic
132
- # relations for the sources (experimental, not fully implemented yet)
133
- def find(*args)
134
- prefetching = false
135
- if(args.last.is_a?(Hash))
136
- options = args.last
137
- prefetching = options.delete(:prefetch_relations)
138
- if(options.empty?) # If empty we remove the args hash, so that the 1-param uri search works
139
- args.pop
140
- else
141
- prepare_options!(args.last)
142
- end
143
- end
144
- result = if(args.size == 1 && (uri_s = uri_string_for(args[0])))
145
- src = super(:first, :conditions => { :uri => uri_s })
146
- raise(ActiveRecord::RecordNotFound, "Not found: #{uri_s}") unless(src)
147
- src
148
- else
149
- super
150
- end
151
-
152
- prefetch_relations_for(result) if(prefetching)
153
-
154
- result
155
- end
156
-
157
135
  # Semantic version of ActiveRecord::Base#update - the id may be a record id or an URL,
158
136
  # and the attributes may contain semantic attributes. See the update_attributes method
159
137
  # for details on how the semantic attributes behave.
@@ -233,7 +211,7 @@ module TaliaCore
233
211
 
234
212
  # The attributes stored in the database
235
213
  def db_attributes
236
- @db_attributes ||= ActiveSource.new.attribute_names
214
+ @db_attributes ||= (ActiveSource.new.attribute_names << 'id')
237
215
  end
238
216
 
239
217
  # Helper to define a "additional type" in subclasses which will
@@ -310,70 +288,6 @@ module TaliaCore
310
288
  result
311
289
  end
312
290
 
313
-
314
- # Takes the "advanced" options that can be passed to the find method and
315
- # converts them into "standard" find options.
316
- def prepare_options!(options)
317
- check_for_find_through!(options)
318
- check_for_type_find!(options)
319
- check_for_find_through_inv!(options)
320
- end
321
-
322
- # Checks if the :find_through option is set. If so, this expects the
323
- # option to have 2 values: The first representing the URL of the predicate
324
- # and the second the URL or value that should be matched.
325
- #
326
- # An optional third parameter can be used to force an object search on the
327
- # semantic_properties table (instead of active_sources) - if not present
328
- # this will be auto-guessed from the "object value", checking if it appears
329
- # to be an URL or not.
330
- #
331
- # ...find(:find_through => [N::RDF::something, 'value', true]
332
- def check_for_find_through!(options)
333
- if(f_through = options.delete(:find_through))
334
- assit_kind_of(Array, f_through)
335
- raise(ArgumentError, "Passed non-hash conditions with :find_through") if(options.has_key?(:conditions) && !options[:conditions].is_a?(Hash))
336
- raise(ArgumentError, "Cannot pass custom join conditions with :find_through") if(options.has_key?(:joins))
337
- predicate = f_through[0]
338
- obj_val = f_through[1]
339
- search_prop = (f_through.size > 2) ? f_through[2] : !(obj_val.to_s =~ /:/)
340
- options[:joins] = default_joins(!search_prop, search_prop)
341
- options[:conditions] ||= {}
342
- options[:conditions]['semantic_relations.predicate_uri'] = predicate.to_s
343
- if(search_prop)
344
- options[:conditions]['obj_props.value'] = obj_val.to_s
345
- else
346
- options[:conditions]['obj_sources.uri'] = obj_val.to_s
347
- end
348
- end
349
- end
350
-
351
- # Check for the :find_through_inv option. This expects the 2 basic values
352
- # in the same way as :find_through.
353
- #
354
- # find(:find_through_inv => [N::RDF::to_me, my_uri]
355
- def check_for_find_through_inv!(options)
356
- if(f_through = options.delete(:find_through_inv))
357
- assit_kind_of(Array, f_through)
358
- raise(ArgumentError, "Passed non-hash conditions with :find_through") if(options.has_key?(:conditions) && !options[:conditions].is_a?(Hash))
359
- raise(ArgumentError, "Cannot pass custom join conditions with :find_through") if(options.has_key?(:joins))
360
- options[:joins] = default_inv_joins
361
- options[:conditions] ||= {}
362
- options[:conditions]['semantic_relations.predicate_uri'] = f_through[0].to_s
363
- options[:conditions]['sub_sources.uri'] = f_through[1].to_s
364
- end
365
- end
366
-
367
-
368
- # Checks for the :type option in the find options. This is the same as
369
- # doing a :find_through on the rdf type
370
- def check_for_type_find!(options)
371
- if(f_type = options.delete(:type))
372
- options[:find_through] = [N::RDF::type, f_type.to_s, false]
373
- check_for_find_through!(options)
374
- end
375
- end
376
-
377
291
  end
378
292
  end
379
293
  end