lucid_works 0.6.29 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.rvmrc +1 -1
  2. data/Rakefile +25 -0
  3. data/config/locales/en.yml +171 -83
  4. data/lib/lucid_works/associations/has_many.rb +2 -2
  5. data/lib/lucid_works/associations/has_one.rb +1 -1
  6. data/lib/lucid_works/associations/proxy.rb +3 -3
  7. data/lib/lucid_works/associations.rb +2 -2
  8. data/lib/lucid_works/base.rb +21 -48
  9. data/lib/lucid_works/collection/click.rb +17 -0
  10. data/lib/lucid_works/collection/settings.rb +0 -1
  11. data/lib/lucid_works/collection.rb +22 -3
  12. data/lib/lucid_works/crawler.rb +13 -0
  13. data/lib/lucid_works/datasource/history.rb +5 -9
  14. data/lib/lucid_works/datasource/status.rb +8 -11
  15. data/lib/lucid_works/datasource.rb +67 -32
  16. data/lib/lucid_works/datasource_property.rb +18 -0
  17. data/lib/lucid_works/datasource_type.rb +23 -0
  18. data/lib/lucid_works/exceptions.rb +1 -0
  19. data/lib/lucid_works/field.rb +43 -2
  20. data/lib/lucid_works/fieldtype.rb +28 -0
  21. data/lib/lucid_works/gem_version.rb +1 -1
  22. data/lib/lucid_works/jdbcdriver.rb +30 -0
  23. data/lib/lucid_works/role.rb +59 -0
  24. data/lib/lucid_works/schema/attribute.rb +86 -0
  25. data/lib/lucid_works/schema/boolean_attribute.rb +34 -0
  26. data/lib/lucid_works/schema/custom_attribute.rb +15 -0
  27. data/lib/lucid_works/schema/integer_attribute.rb +32 -0
  28. data/lib/lucid_works/schema/iso8601_attribute.rb +31 -0
  29. data/lib/lucid_works/schema/string_attribute.rb +22 -0
  30. data/lib/lucid_works/schema.rb +66 -97
  31. data/lib/lucid_works/server.rb +14 -0
  32. data/lib/lucid_works.rb +12 -0
  33. data/spec/fixtures/fake_file_ds_to_be_deleted/.gitkeep +0 -0
  34. data/spec/fixtures/fake_file_ds_to_be_updated/.gitkeep +0 -0
  35. data/spec/fixtures/fake_file_ds_to_get_index_of/.gitkeep +0 -0
  36. data/spec/fixtures/fake_file_ds_to_get_schedule_of/.gitkeep +0 -0
  37. data/spec/fixtures/fake_file_ds_to_get_status_of/.gitkeep +0 -0
  38. data/spec/fixtures/fake_file_ds_to_mess_with_job_of/.gitkeep +0 -0
  39. data/spec/fixtures/fake_file_ds_to_test_progress/.gitkeep +0 -0
  40. data/spec/lib/lucid_works/associations/has_many_spec.rb +4 -3
  41. data/spec/lib/lucid_works/associations/has_one_spec.rb +4 -3
  42. data/spec/lib/lucid_works/base_spec.rb +110 -62
  43. data/spec/lib/lucid_works/collection/activity/history_spec.rb +1 -1
  44. data/spec/lib/lucid_works/collection_spec.rb +17 -17
  45. data/spec/lib/lucid_works/datasource/history_spec.rb +4 -4
  46. data/spec/lib/lucid_works/datasource/status_spec.rb +7 -7
  47. data/spec/lib/lucid_works/datasource_spec.rb +9 -8
  48. data/spec/lib/lucid_works/field_spec.rb +101 -2
  49. data/spec/lib/lucid_works/fieldtype_spec.rb +156 -0
  50. data/spec/lib/lucid_works/schema/attribute_spec.rb +136 -0
  51. data/spec/lib/lucid_works/schema_spec.rb +53 -27
  52. data/spec/spec_helper.rb +3 -50
  53. data/spec/support/active_model_lint.rb +21 -0
  54. data/spec/support/lucid_works.rb +52 -0
  55. metadata +36 -2
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm use 1.9.2-p180@lucidworks
1
+ rvm use 1.9.2-p180@lucidworks --create
data/Rakefile CHANGED
@@ -11,3 +11,28 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
11
11
  rdoc.rdoc_files.include('README.rdoc')
12
12
  rdoc.rdoc_files.include('lib/**/*.rb')
13
13
  end
14
+
15
+ class Hash
16
+ def recursively_sort
17
+ raise "Hash#recursively_sort requires Ruby 1.9" if RUBY_VERSION < "1.9"
18
+ sorted_array = self.sort
19
+ sorted_array.map! do |kv|
20
+ k, v = kv
21
+ v = v.recursively_sort if v.is_a?(Hash)
22
+ [k,v]
23
+ end
24
+ Hash[sorted_array]
25
+ end
26
+ end
27
+
28
+ namespace :l10n do
29
+
30
+ desc "Sort the EN locale file"
31
+ task :sort do
32
+ en_path = File.join(File.dirname(__FILE__), 'config', 'locales', "en.yml")
33
+ translations = YAML.load_file(en_path)
34
+ File.open(en_path, 'w') do |f|
35
+ YAML.dump translations.recursively_sort, f
36
+ end
37
+ end
38
+ end
@@ -1,51 +1,13 @@
1
1
  ---
2
2
  en:
3
3
  activemodel:
4
- models:
5
- lucid_works:
6
- activity:
7
- one: Activity
8
- other: Activities
9
- type:
10
- autocomplete: Generate autocomplete index
11
- click: Process click logs
12
- optimize: Optimize index
13
- spelling: Generate spellcheck index
14
- collection:
15
- one: Collection
16
- other: Collections
17
- settings:
18
- one: Settings
19
- other: Settings
20
- de_duplication:
21
- 'off': 'Off'
22
- overwrite: Overwrite
23
- tag: Tag
24
- datasource:
25
- one: Data source
26
- other: Data sources
27
- status:
28
- crawlState:
29
- ABORTED: Aborted
30
- ABORTING: Aborting
31
- EXCEPTION: Exception
32
- FINISHED: Finished
33
- IDLE: Idle
34
- RUNNING: Running
35
- STOPPED: Stopped
36
- STOPPING: Stopping
37
- type:
38
- external: External
39
- file: Local Filesystem
40
- jdbc: Database
41
- lucidworkslogs: LucidWorks Solr Logs
42
- sharepoint: Sharepoint
43
- solrxml: Solr XML
44
- web: Web Site
4
+ #
5
+ # This section is standard ActiveModel
6
+ # and is used by human_attribute_name
7
+ #
45
8
  attributes:
46
9
  lucid_works:
47
10
  collection:
48
- name: Name
49
11
  info:
50
12
  collection_name: Collection name
51
13
  data_dir: Data directory
@@ -65,15 +27,16 @@ en:
65
27
  root_dir: Root directory
66
28
  total_disk_bytes: Total disk bytes
67
29
  total_disk_space: Total disk space
30
+ name: Name
68
31
  settings:
69
32
  auto_complete: Auto complete
70
- boosts: Boosts
71
33
  boost_recent: Boost recent
34
+ boosts: Boosts
72
35
  click_boost_data: Click boost data
73
36
  click_boost_field: Click boost field
74
37
  click_enabled: Click scoring enabled
75
- default_sort: Default sort
76
38
  de_duplication: De-duplication
39
+ default_sort: Default sort
77
40
  display_facets: Display facets
78
41
  elevations: elevations
79
42
  index_time_stopwords: Exclude stop words from index
@@ -91,47 +54,172 @@ en:
91
54
  unsupervised_feedback_emphasis: Unsupervised feedback emphasis
92
55
  update_server_list: Update server list
93
56
  datasource:
94
- type: Type
95
- commitWithin: Commit within
96
- commit_within_min: "Commit within (minutes)"
97
- deleteAfter: Delete logs after
57
+ aliases: Site Aliases Mappings
58
+ auth: Authentication credentials
59
+ authorization: Authorization
98
60
  bounds: Constrain to
99
- max_bytes: Skip files larger than (bytes)
61
+ commit_on_finish: Commit when crawl finishes
62
+ commit_within: Commit within
63
+ commit_within_min: Commit within (minutes)
64
+ connector_type: Connector Type
65
+ deleteAfter: Delete logs after
66
+ domain: Domain
67
+ excluded_urls: Excluded URLs
68
+ fail_unsupported_file_types: Fail unsupported file types
100
69
  history:
101
- crawlStarted: Started
102
- crawlStopped: Stopped
103
- crawlState: State
104
- numNew: New
105
- numUpdated: Updated
106
- numDeleted: Deleted
107
- numUnchanged: Unchanged
108
- numFailed: Failed
70
+ crawl_started: Started
71
+ crawl_state: State
72
+ crawl_stopped: Stopped
73
+ num_deleted: Deleted
74
+ num_failed: Failed
75
+ num_new: New
76
+ num_unchanged: Unchanged
77
+ num_updated: Updated
78
+ host: Domain Name
79
+ ignore_robots: Ignore robots.txt
80
+ include_datasource_metadata: Include data source metadata
81
+ included_urls: Included URLs
82
+ kdcserver: Kerberos KDC server
83
+ log_extra_detail: Log extra detail
84
+ max_bytes: Skip files larger than (bytes)
85
+ my_site_base_url: MySite URL
86
+ no_duplicates: Suppress duplicates
87
+ password: Password
88
+ proxy_host: Proxy host
89
+ proxy_password: Proxy password
90
+ proxy_port: Proxy port
91
+ proxy_username: Proxy user name
92
+ realm: Realm
93
+ sharepoint_url: SharePoint URL
109
94
  status:
110
- crawlStarted: Last crawl started
111
- crawlStopped: Last crawl stopped
112
- crawlState: State
95
+ crawl_started: Last crawl started
96
+ crawl_state: State
97
+ crawl_stopped: Last crawl stopped
113
98
  doc_count: Documents indexed
114
- jobId: Job ID
115
- numNew: New docs
116
- numUpdated: Updated docs
117
- numDeleted: Deleted docs
118
- numUnchanged: Unchanged docs
119
- numFailed: Failed docs
120
- numTotal: Total docs
121
- sharepointUrl: SharePoint URL
122
- connectorType: Connector Type
123
- authorization: Authorization
99
+ job_id: Job ID
100
+ num_deleted: Deleted docs
101
+ num_failed: Failed docs
102
+ num_new: New docs
103
+ num_total: Total docs
104
+ num_unchanged: Unchanged docs
105
+ num_updated: Updated docs
106
+ type: Type
107
+ url: URL
108
+ use_sp_search_visibility: Use SP Search Visibility
124
109
  username: Username
125
- password: Password
126
- domain: Domain
127
- mySiteBaseURL: MySite URL
128
- includedURls: Included URLs
129
- excludedURls: Excluded URLs
130
- kdcserver: Kerberos KDC server
131
- useSPSearchVisibility: Use SP Search Visibility
132
- aliases: Site Aliases Mappings
133
- # errors:
134
- # models:
135
- # lucid_works:
136
- # collection:
137
- # exclusion: is reserved
110
+ warn_unknown_mime_types: Log warnings for unknown mime types
111
+ windowsdomain: Windows domain
112
+ field:
113
+ copy_fields: Copy this field to fields
114
+ default_boost: Default boost
115
+ default_value: Default value
116
+ dynamic_base: Dynamically generated from
117
+ editable: Editable
118
+ facet: Facet
119
+ field_type: Field type
120
+ highlight: Highlight
121
+ include_in_results: Include in results
122
+ index_for_autocomplete: Index for autocomplete
123
+ index_for_spellcheck: Index for spell checking
124
+ index_term_freq_and_pos: Index term frequencies and positions
125
+ indexed: Indexed
126
+ multi_valued: Multi-valued
127
+ name: Name
128
+ omit_positions: Omit positions
129
+ omit_tf: Omit term frequencies and positions
130
+ query_time_stopword_handling: Enable stopword handling
131
+ search_by_default: Search by default
132
+ short_field_boost: Short field boost
133
+ stored: Stored
134
+ synonym_expasion: Enable synonym expansion
135
+ term_vectors: Term vectors
136
+ use_for_deduplication: Use for de-duplication
137
+ use_in_find_similar: Use in 'find similar'
138
+ fieldtype:
139
+ name: Name
140
+ _class: Class
141
+ #
142
+ # This section containts two things:
143
+ # Model names wich support ActiveModel <model>.model_name.human
144
+ # Translations for attribute values. This is our own invention,
145
+ # accessed with LucidWorks::Base#human_attribute_value(attribute)
146
+ # or from class LucidWorks::Base.human_attribute_value(attribute, value)
147
+ #
148
+ models:
149
+ lucid_works:
150
+ activity:
151
+ one: Activity
152
+ other: Activities
153
+ type:
154
+ autocomplete: Generate autocomplete index
155
+ click: Process click logs
156
+ optimize: Optimize index
157
+ spelling: Generate spellcheck index
158
+ collection:
159
+ one: Collection
160
+ other: Collections
161
+ settings:
162
+ de_duplication:
163
+ 'off': 'Off'
164
+ overwrite: Overwrite
165
+ tag: Tag
166
+ one: Settings
167
+ other: Settings
168
+ datasource:
169
+ one: Data source
170
+ other: Data sources
171
+ status:
172
+ crawl_state:
173
+ ABORTED: Aborted
174
+ ABORTING: Aborting
175
+ EXCEPTION: Exception
176
+ FINISHED: Finished
177
+ IDLE: Idle
178
+ RUNNING: Running
179
+ STOPPED: Stopped
180
+ STOPPING: Stopping
181
+ type:
182
+ external: External
183
+ file: File system
184
+ ftp: FTP
185
+ hdfs: Hadoop file system
186
+ jdbc: Database
187
+ kfs: Kosmos file system
188
+ lucidworkslogs: LucidWorks Solr Logs
189
+ s3: Hadoop S3 Block FS
190
+ s3n: Hadoop S3 Native FS
191
+ sharepoint: SharePoint
192
+ smb: Windows Share
193
+ solrxml: Solr XML
194
+ web: Web site
195
+ field:
196
+ one: Field
197
+ other: Fields
198
+ index_term_freq_and_pos:
199
+ document_only: none
200
+ document_termfreq: term frequencies
201
+ document_termfreq_termpos: term frequencies and positions
202
+ fieldtype:
203
+ one: Field type
204
+ other: Field types
205
+ jdbcdriver:
206
+ one: JDBC driver
207
+ other: JDBC drivers
208
+ #
209
+ # These hints appear next to fields in SimpleForm forms
210
+ #
211
+ simple_form:
212
+ hints:
213
+ collection:
214
+ name: ! 'Collection names may use the characters: A-Z, a-z, 0-9, dash and
215
+ underscore'
216
+ datasource:
217
+ crawl_depth: Set to -1 to crawl with no depth limit.
218
+ exclude_paths: A list of regular expressions, one per line, e.g. .*\.pdf will
219
+ ignore filenames ending in .pdf.
220
+ include_paths: A list of regular expressions, one per line, e.g. http://example\.com/.*
221
+ will match everything within the site only.
222
+ max_bytes: Default = 10 MiB. Set to -1 to indicate no file size limit.
223
+ url: e.g. http://cnn.com. Please include protocol (http/https).
224
+ synonym:
225
+ mapping: ! 'Example: car, automobile, auto'
@@ -18,7 +18,7 @@ module LucidWorks
18
18
  if target.save
19
19
  target
20
20
  else
21
- raise target.errors.full_messages
21
+ raise LucidWorks::RecordInvalid.new(target.errors.full_messages)
22
22
  end
23
23
  end
24
24
 
@@ -40,7 +40,7 @@ module LucidWorks
40
40
  #
41
41
  # Interestingly for us the cost difference is marginal between the two forms of
42
42
  # the call. Should we just grab all of them and return the one they want?
43
- # Probably not. Not every elegant and there is some cost to creating models
43
+ # Probably not. Not very elegant and there is some cost to creating models
44
44
  # on our end.
45
45
  #
46
46
  # Okay for now we will just not cache .find()
@@ -17,7 +17,7 @@ module LucidWorks
17
17
  if @target.save
18
18
  @target
19
19
  else
20
- raise @target.errors.full_messages
20
+ raise LucidWorks::RecordInvalid.new(@target.errors.full_messages)
21
21
  end
22
22
  end
23
23
 
@@ -25,9 +25,9 @@ module LucidWorks
25
25
  !!@target
26
26
  end
27
27
 
28
- # Can targets be retrieved for all owners if this type, in one step using owner/all/target
29
- def supports_all?
30
- @options[:supports_all]
28
+ # Can targets be retrieved for all owners of this type, in one step using owner/all/target
29
+ def retrieveable_en_masse?
30
+ @options[:retrieveable_en_masse]
31
31
  end
32
32
 
33
33
  def reload!
@@ -113,7 +113,7 @@ module LucidWorks
113
113
 
114
114
  class_eval <<-EOF, __FILE__, __LINE__ + 1
115
115
  def #{resource}
116
- @#{resource}_association ||= Associations::HasOne.new(self, #{resource_class_name}, #{options.to_s})
116
+ @#{resource}_association ||= Associations::HasOne.new(self, #{resource_class_name}, #{options.inspect})
117
117
  end
118
118
 
119
119
  def #{resource}!
@@ -137,7 +137,7 @@ module LucidWorks
137
137
 
138
138
  class_eval <<-EOF, __FILE__, __LINE__ + 1
139
139
  def #{resources}(options={})
140
- @#{resources}_association ||= Associations::HasMany.new(self, #{resource_class_name}, #{options.to_s})
140
+ @#{resources}_association ||= Associations::HasMany.new(self, #{resource_class_name}, #{options.inspect})
141
141
  @#{resources}_association.remember_find_options(options) unless options.empty?
142
142
  @#{resources}_association
143
143
  end
@@ -45,8 +45,6 @@ module LucidWorks
45
45
  define_model_callbacks :save, :only => [:before, :after]
46
46
 
47
47
  class << self
48
- include ActionView::Helpers::NumberHelper rescue nil
49
-
50
48
  attr_accessor :collection_name # :nodoc:
51
49
  attr_accessor_with_default :singleton, false
52
50
 
@@ -66,7 +64,7 @@ module LucidWorks
66
64
  # end
67
65
 
68
66
  def schema(&block)
69
- @schema ||= LucidWorks::Schema.new
67
+ @schema ||= LucidWorks::Schema.new(self)
70
68
  if block_given?
71
69
  @schema.instance_eval(&block)
72
70
  @schema.create_accessors_for_attributes(self)
@@ -177,7 +175,7 @@ module LucidWorks
177
175
  target_class = class_eval(association_info[:class_name]) # get scoping right
178
176
  target_name = association_info[:class_name].underscore
179
177
 
180
- if kind_of_find == :all && association_info[:supports_all]
178
+ if kind_of_find == :all && association_info[:retrieveable_en_masse]
181
179
  all_targets_path = "#{collection_url(parent)}/all/#{target_name}"
182
180
  raw_response = ActiveSupport::Notifications.instrument("lucid_works.request") do |payload|
183
181
  begin
@@ -205,9 +203,7 @@ module LucidWorks
205
203
  # [{"history":[...history_models...],"id":372},{"history":[...history_models...],"id":371}]
206
204
  JSON.parse(raw_response).each do |group_of_targets|
207
205
  owner_id = group_of_targets['id']
208
- # Note: to_i in the next line is because most REST API interfaces return ids a integers
209
- # but one returns them as strings. There is no plan to fix this brokeness (FOCUS-2359).
210
- owner = results_array.detect { |result| result.id == owner_id.to_i }
206
+ owner = results_array.detect { |result| result.id == owner_id }
211
207
  targets = group_of_targets[target_name].collect do |target_attrs|
212
208
  target_class.new(target_attrs.merge(:parent => owner, :persisted => true))
213
209
  end
@@ -215,7 +211,7 @@ module LucidWorks
215
211
  association_proxy.target = targets
216
212
  end
217
213
  end
218
- else # kind_of_find != :all || !supports_all
214
+ else # kind_of_find != :all || !retrieveable_en_masse
219
215
  results_array.each do |result|
220
216
  result.send("#{association_name}!")
221
217
  end
@@ -250,31 +246,14 @@ module LucidWorks
250
246
  # If the attributes is listed in the schema as having :values =>, it will be translated.
251
247
 
252
248
  def human_attribute_value(attribute, value)
253
- if schema[attribute][:values]
254
- l10n_scope = %w{activemodel models} + self.name.underscore.split('/') + [attribute]
255
- return I18n.t(value, :scope => l10n_scope, :default => value)
256
- end
257
-
258
- case schema[attribute][:type]
259
- when :boolean
260
- value.to_yesno
261
- when :integer
262
- number_with_delimiter(value)
263
- else
264
- value.to_s
265
- end
266
- rescue
267
- value.to_s
249
+ schema[attribute].human_value(value)
268
250
  end
269
251
 
270
252
  # For attributes listed in the schema as having :values, this will create an array-of-arrays
271
253
  # suitable for use as options_for_select.
272
254
 
273
255
  def to_select(attribute)
274
- raise "Can't to_select for #{attribute} as it has no values" unless schema[attribute][:values]
275
- schema[attribute][:values].map do |value|
276
- [human_attribute_value(attribute, value), value]
277
- end
256
+ schema[attribute].to_select
278
257
  end
279
258
 
280
259
  def collection_name # :nodoc:
@@ -332,7 +311,7 @@ module LucidWorks
332
311
  rescue RestClient::Conflict, # 409
333
312
  RestClient::UnprocessableEntity, # 422
334
313
  RestClient::InternalServerError => e # 500
335
- payload[:exceptionion] = e
314
+ payload[:exception] = e
336
315
  attach_errors_to_model(e.response)
337
316
  false
338
317
  rescue RestClient::Exception => exception
@@ -358,6 +337,10 @@ module LucidWorks
358
337
  payload[:uri] = member_url
359
338
  payload[:options] = options
360
339
  payload[:repsonse] = RestClient.delete(member_url, options)
340
+ rescue RestClient::Conflict => e
341
+ payload[:exception] = e
342
+ attach_errors_to_model(e.response)
343
+ false
361
344
  rescue RestClient::Exception => exception
362
345
  # Tack on what we were doing when we got the exception, then send it on up
363
346
  exception.message = "#{exception.message} while performing #{payload[:method]} #{payload[:uri]}"
@@ -409,6 +392,10 @@ module LucidWorks
409
392
 
410
393
  private
411
394
 
395
+ def schema
396
+ self.class.schema
397
+ end
398
+
412
399
  def singleton? # :nodoc:
413
400
  self.class.singleton
414
401
  end
@@ -418,20 +405,12 @@ module LucidWorks
418
405
  end
419
406
 
420
407
  def encode # :nodoc:
421
- omit_attrs = [ 'id' ]
422
- omit_attrs += self.class.schema.attrs_to_omit_during_update if persisted?
423
- attrs_as_json = @attributes.inject({}) do |memo, kv|
408
+ attrs_as_json = @attributes.inject({}) do |encoded_attrs, kv|
424
409
  attr, value = kv
425
- unless (value.blank? && self.class.schema[attr][:omit_when_blank]) ||
426
- omit_attrs.include?(attr.to_s)
427
- case self.class.schema[attr][:type]
428
- when :iso8601
429
- memo[attr] = value.iso8601 rescue value
430
- else
431
- memo[attr] = value
432
- end
410
+ unless attr.to_s == 'id'
411
+ schema[attr].encode_and_insert(value, encoded_attrs, persisted?)
433
412
  end
434
- memo
413
+ encoded_attrs
435
414
  end
436
415
  attrs_as_json.to_json
437
416
  end
@@ -445,14 +424,8 @@ module LucidWorks
445
424
  elsif self.class.respond_to?(:belongs_to_association_name) && attr.to_sym == self.class.belongs_to_association_name
446
425
  next # Dont overwrite our connection to our parent
447
426
  end
448
- unless self.class.schema.has_attribute?(attr)
449
- if self.class.schema.dynamic_attributes?
450
- self.class.schema.add_attribute(self.class, attr, :string)
451
- else
452
- raise "unknown attribute: \"#{attr}\""
453
- end
454
- end
455
- send "#{self.class.schema.sanitize_identifier(attr)}=", value
427
+ attribute = schema.find_or_create_attribute(attr)
428
+ send "#{attribute.name}=", value
456
429
  end
457
430
  end
458
431