caboose-rets 0.0.58 → 0.0.60

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YzA2ZjFiZWNjODQ0YTQ1NWI3ZmMwZTY4MGUzOWEwZGE5YTU0NzQ0Nw==
4
+ ZmM5YTVkYTE5MzFiNzNkYTdhZDVkNjVmZTVjMTkyMWYzNWY5OTgxOA==
5
5
  data.tar.gz: !binary |-
6
- YzNjZmJhMWM2NjI4YjI5MjZjYTI3MGFkNGZiNzliYTQwYjk3Yjg4NQ==
6
+ Yzk0MGI4OWNiMzNlZmE0ZmY4ZGYxOGU2NGJkZmE4MjMwOTI4YzBmOQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZDM2YTE0OGM1ZjdkNjMzMTk1N2Q2NzAwYWQwZWQ2Nzg4NmI0MGRjNjJmZDZh
10
- MjNlNjBmOTY5NGI5Yjg2NWM3YjI5ZDBhMTBmMTRmNWZhYTgwODJjZGFlN2U4
11
- NjJkNmFhYjJmZGNmMDRlOWMyYjYyOWU5YjRjZjYzYjQ3MjVhYWQ=
9
+ MTYyOGY2OTAzOGE1NDVkY2IyMWE3MWUwODg5ZmY2ODI4MGZmMmZlZTFkMTEw
10
+ MjI4NGE2ZTM5ODMyMjMwNTcwMWE3MjBlOGZhZDg3ZDM3NDE1N2E4ZmY3ZWRm
11
+ MjU2Mzk4NGM2OTMyMjVkODM4MzlmZjUwZWY2ZTJkMDJlZTNmZWQ=
12
12
  data.tar.gz: !binary |-
13
- YWNiZWNkZTExYTA3ZTI2Y2FkZDBiNTUyOWM0ZjUzMDhjYmI0MjY4Y2ZjOGQy
14
- MmVhMjIxNmI5OGJhMzg0OThlMTg0YjVlZGFlNGZhNWZmOWVmOGEwNTBkZWMx
15
- YmYyZmFjYmY4NzM2MzI2NDM4YzQ5MGY4YTIzMjA2YzI1MWY3OTA=
13
+ MWU2NzRiYWVlODVjNTczOGE3MjY2NjA1YTBmMjIyZmU2NTUyNzI3M2NiYTI4
14
+ OGNjYWIzNDgwZDhkNjI0NGU3YzlhZGVmYmM3NzE4ODE5Mjk3NGEyNGJjODg1
15
+ NzMzZGNhNmFkMmYxNDMxNjE3NDcxMDUxYzY4ZDgwMTFhZTEzNmQ=
@@ -1,3 +1,3 @@
1
1
  module CabooseRets
2
- VERSION = '0.0.58'
2
+ VERSION = '0.0.60'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caboose-rets
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.58
4
+ version: 0.0.60
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Barry
@@ -58,7 +58,6 @@ files:
58
58
  - app/models/caboose_rets/open_house.rb
59
59
  - app/models/caboose_rets/residential_property.rb
60
60
  - app/models/caboose_rets/rets_importer.rb
61
- - app/models/caboose_rets/rets_importer_bak.rb
62
61
  - app/models/caboose_rets/rets_plugin.rb
63
62
  - app/models/caboose_rets/saved_property.rb
64
63
  - app/models/caboose_rets/saved_search.rb
@@ -1,512 +0,0 @@
1
- require 'ruby-rets'
2
- require 'httparty'
3
- require 'json'
4
-
5
- # http://rets.solidearth.com/ClientHome.aspx
6
-
7
- class CabooseRets::RetsImporter # < ActiveRecord::Base
8
-
9
- @@rets_client = nil
10
- @@config = nil
11
- @@object_types = {
12
- 'OpenHouse' => ['OPH'],
13
- 'Media' => ['GFX'],
14
- 'Property' => ['COM', 'LND', 'MUL', 'RES'],
15
- 'Agent' => ['AGT'],
16
- 'Office' => ['OFF']
17
- }
18
- @@key_fields = {
19
- 'OpenHouse' => 'ID',
20
- 'Media' => 'MEDIA_ID',
21
- 'Property' => 'MLS_ACCT',
22
- 'Agent' => 'LA_LA_CODE',
23
- 'Office' => 'LO_LO_CODE'
24
- }
25
- @@models = {
26
- 'OPH' => 'CabooseRets::OpenHouse',
27
- 'GFX' => 'CabooseRets::Media',
28
- 'COM' => 'CabooseRets::CommercialProperty',
29
- 'LND' => 'CabooseRets::LandProperty',
30
- 'MUL' => 'CabooseRets::MultiFamilyProperty',
31
- 'RES' => 'CabooseRets::ResidentialProperty',
32
- 'AGT' => 'CabooseRets::Agent',
33
- 'OFF' => 'CabooseRets::Office'
34
- }
35
- @@date_modified_fields = {
36
- 'OPH' => 'DATE_MODIFIED',
37
- 'GFX' => 'DATE_MODIFIED',
38
- 'COM' => 'DATE_MODIFIED',
39
- 'LND' => 'DATE_MODIFIED',
40
- 'MUL' => 'DATE_MODIFIED',
41
- 'RES' => 'DATE_MODIFIED',
42
- 'AGT' => 'LA_DATE_MODIFIED',
43
- 'OFF' => 'LO_DATE_MODIFIED'
44
- }
45
-
46
- def self.config
47
- return @@config
48
- end
49
-
50
- def self.get_config
51
- @@config = {
52
- 'url' => nil, # URL to the RETS login
53
- 'username' => nil,
54
- 'password' => nil,
55
- 'limit' => nil, # How many records to limit per request
56
- 'days_per_batch' => nil, # When performing a large property import, how many days to search on per batch
57
- 'temp_path' => nil,
58
- 'log_file' => nil,
59
- 'media_base_url' => nil
60
- }
61
- config = YAML::load(File.open("#{Rails.root}/config/rets_importer.yml"))
62
- config = config[Rails.env]
63
- config.each { |key,val| @@config[key] = val }
64
- end
65
-
66
- def self.client
67
- self.get_config if @@config.nil? || @@config['url'].nil?
68
-
69
- if (@@rets_client.nil?)
70
- @@rets_client = RETS::Client.login(
71
- :url => @@config['url'],
72
- :username => @@config['username'],
73
- :password => @@config['password']
74
- )
75
- end
76
- return @@rets_client
77
- end
78
-
79
- #=============================================================================
80
- # Main updater
81
- #=============================================================================
82
-
83
- def self.update_after(date_modified)
84
- self.update_data_after(date_modified)
85
- self.update_images_after(date_modified)
86
- end
87
-
88
- def self.update_data_after(date_modified)
89
- self.get_config if @@config.nil? || @@config['url'].nil?
90
- self.import_modified_after(date_modified, 'Agent' , 'AGT')
91
- self.import_modified_after(date_modified, 'Office' , 'OFF')
92
- self.import_modified_after(date_modified, 'OpenHouse' , 'OPH')
93
- #self.import_modified_after(date_modified, 'Property' , 'COM')
94
- self.import_modified_after(date_modified, 'Property' , 'LND')
95
- self.import_modified_after(date_modified, 'Property' , 'MUL')
96
- self.import_modified_after(date_modified, 'Property' , 'RES')
97
- end
98
-
99
- def self.update_images_after(date_modified)
100
- self.get_config if @@config.nil? || @@config['url'].nil?
101
- self.download_agent_images_modified_after(date_modified)
102
- self.download_property_images_modified_after(date_modified)
103
- end
104
-
105
- #=============================================================================
106
- # Data
107
- #=============================================================================
108
-
109
- def self.import_property(mls_acct)
110
-
111
- self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'RES')
112
- p = CabooseRets::ResidentialProperty.where(:id => mls_acct.to_i).first
113
- if p.nil?
114
- self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'COM')
115
- p = CabooseRets::CommercialProperty.where(:id => mls_acct.to_i).first
116
- if p.nil?
117
- self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'LND')
118
- p = CabooseRets::LandProperty.where(:id => mls_acct.to_i).first
119
- if p.nil?
120
- self.import("(MLS_ACCT=*#{mls_acct}*)", 'Property', 'MUL')
121
- p = CabooseRets::MultiFamilyProperty.where(:id => mls_acct.to_i).first
122
- return if p.nil?
123
- end
124
- end
125
- end
126
- self.download_property_images(p)
127
- end
128
-
129
- def self.import_modified_after(date_modified, search_type = nil, class_type = nil)
130
- self.get_config if @@config.nil? || @@config['url'].nil?
131
-
132
- d = date_modified
133
- date_modified_field = @@date_modified_fields[class_type]
134
-
135
- while d.strftime('%FT%T') <= DateTime.now.strftime('%FT%T') do
136
- break if d.nil?
137
-
138
- d2 = d.strftime('%FT%T')
139
- d2 << "-"
140
- d2 << (d+@@config['days_per_batch']).strftime('%FT%T')
141
-
142
- query = "(#{date_modified_field}=#{d2})"
143
- self.import(query, search_type, class_type)
144
-
145
- d = d + @@config['days_per_batch']
146
- end
147
- end
148
-
149
- def self.import(query, search_type, class_type)
150
- # See how many records we have
151
- self.client.search(
152
- :search_type => search_type,
153
- :class => class_type,
154
- :query => query,
155
- :count_mode => :only,
156
- :timeout => -1,
157
- )
158
- # Return if no records found
159
- if (self.client.rets_data[:code] == "20201")
160
- self.log "No #{search_type}:#{class_type} records found for query: #{query}"
161
- return
162
- else
163
- count = self.client.rets_data[:count]
164
- self.log "Importing #{count} #{search_type}:#{class_type} record" + (count == 1 ? "" : "s") + "..."
165
- end
166
-
167
- count = self.client.rets_data[:count]
168
- batch_count = (count.to_f/@@config['limit'].to_f).ceil
169
-
170
- (0...batch_count).each do |i|
171
- params = {
172
- :search_type => search_type,
173
- :class => class_type,
174
- :query => query,
175
- :limit => @@config['limit'],
176
- :offset => @@config['limit'] * i,
177
- :timeout => -1
178
- }
179
- obj = nil
180
- self.client.search(params) do |data|
181
- m = @@models[class_type]
182
- #key_field = @@key_fields[search_type]
183
- #id = data[key_field].to_i
184
- #obj = m.exists?(id) ? m.find(id) : m.new
185
- obj = self.get_instance_with_id(m, data)
186
- if obj.nil?
187
- puts "Error: object is nil"
188
- puts m.inspect
189
- puts data.inspect
190
- next
191
- end
192
- obj.parse(data)
193
- #obj.id = id
194
- obj.save
195
- end
196
-
197
- case obj
198
- when CabooseRets::CommercialProperty, CabooseRets::LandProperty, CabooseRets::MultiFamilyProperty, CabooseRets::ResidentialProperty
199
- self.update_coords(obj)
200
- end
201
- end
202
- end
203
-
204
- def self.get_instance_with_id(model, data)
205
- obj = nil
206
- m = model.constantize
207
- case model
208
- when 'CabooseRets::OpenHouse' then obj = m.where(:id => data['ID'].to_i ).exists? ? m.where(:id => data['ID'].to_i ).first : m.new(:id => data['ID'].to_i )
209
- when 'CabooseRets::Media' then obj = m.where(:media_id => data['MEDIA_ID'] ).exists? ? m.where(:media_id => data['MEDIA_ID'] ).first : m.new(:media_id => data['MEDIA_ID'] )
210
- when 'CabooseRets::CommercialProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
211
- when 'CabooseRets::LandProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
212
- when 'CabooseRets::MultiFamilyProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
213
- when 'CabooseRets::ResidentialProperty' then obj = m.where(:id => data['MLS_ACCT'].to_i ).exists? ? m.where(:id => data['MLS_ACCT'].to_i ).first : m.new(:id => data['MLS_ACCT'].to_i )
214
- when 'CabooseRets::Agent' then obj = m.where(:la_code => data['LA_LA_CODE'] ).exists? ? m.where(:la_code => data['LA_LA_CODE'] ).first : m.new(:la_code => data['LA_LA_CODE'] )
215
- when 'CabooseRets::Office' then obj = m.where(:lo_code => data['LO_LO_CODE'] ).exists? ? m.where(:lo_code => data['LO_LO_CODE'] ).first : m.new(:lo_code => data['LO_LO_CODE'] )
216
- end
217
- return obj
218
- end
219
-
220
- #=============================================================================
221
- # Agent Images
222
- #=============================================================================
223
-
224
- def self.download_agent_images_modified_after(date_modified, agent = nil)
225
- if agent.nil?
226
- CabooseRets::Agent.where('photo_date_modified > ?', date_modified.strftime('%FT%T')).reorder('last_name, first_name').all.each do |a|
227
- self.download_agent_images_modified_after(date_modified, a)
228
- end
229
- return
230
- end
231
- self.download_agent_images(agent)
232
- end
233
-
234
- def self.download_agent_images(agent)
235
- a = agent
236
- self.log "Saving image for #{a.first_name} #{a.last_name}..."
237
- begin
238
- self.client.get_object(:resource => :Agent, :type => :Photo, :location => true, :id => a.la_code) do |headers, content|
239
- a.image = URI.parse(headers['location'])
240
- a.save
241
- end
242
- rescue RETS::APIError => err
243
- self.log "No image for #{a.first_name} #{a.last_name}."
244
- end
245
- end
246
-
247
- #=============================================================================
248
- # Property Images
249
- #=============================================================================
250
-
251
- def self.download_property_images_modified_after(date_modified)
252
- models = [CabooseRets::CommercialProperty, CabooseRets::LandProperty, CabooseRets::MultiFamilyProperty, CabooseRets::ResidentialProperty]
253
- names = ["commercial", "land", "multi-family", "residential"]
254
- i = 0
255
- models.each do |model|
256
- count = model.where("photo_date_modified > ?", date_modified.strftime('%FT%T')).count
257
- j = 1
258
- model.where("photo_date_modified > ?", date_modified.strftime('%FT%T')).reorder(:mls_acct).each do |p|
259
- self.log("Downloading images for #{j} of #{count} #{names[i]} properties...")
260
- self.download_property_images(p)
261
- j = j + 1
262
- end
263
- i = i + 1
264
- end
265
- end
266
-
267
- def self.download_property_images(p)
268
- self.refresh_property_media(p)
269
-
270
- self.log("-- Downloading images and resizing for #{p.mls_acct}")
271
- media = []
272
- self.client.get_object(:resource => :Property, :type => :Photo, :location => true, :id => p.id) do |headers, content|
273
-
274
- # Find the associated media record for the image
275
- filename = File.basename(headers['location'])
276
- m = CabooseRets::Media.where(:mls_acct => p.mls_acct, :file_name => filename).first
277
-
278
- if m.nil?
279
- self.log("Can't find media record for #{p.mls_acct} #{filename}.")
280
- else
281
- m.image = URI.parse(headers['location'])
282
- media << m
283
- #m.save
284
- end
285
- end
286
-
287
- self.log("-- Uploading images to S3 for #{p.mls_acct}")
288
- media.each do |m|
289
- m.save
290
- end
291
- end
292
-
293
- def self.refresh_property_media(p)
294
- self.log("-- Deleting images and metadata for #{p.mls_acct}...")
295
- #CabooseRets::Media.where(:mls_acct => p.mls_acct, :media_type => 'Photo').destroy_all
296
- CabooseRets::Media.where(:mls_acct => p.mls_acct).destroy_all
297
-
298
- self.log("-- Downloading image metadata for #{p.mls_acct}...")
299
- params = {
300
- :search_type => 'Media',
301
- :class => 'GFX',
302
- #:query => "(MLS_ACCT=*#{p.id}*),(MEDIA_TYPE=|I)",
303
- :query => "(MLS_ACCT=*#{p.id}*)",
304
- :timeout => -1
305
- }
306
- self.client.search(params) do |data|
307
- m = CabooseRets::Media.new
308
- m.parse(data)
309
- #m.id = m.media_id
310
- m.save
311
- end
312
- end
313
-
314
- def self.refresh_all_virtual_tours
315
- # See how many records we have
316
- self.client.search(
317
- :search_type => 'Media',
318
- :class => 'GFX',
319
- :query => "(MEDIA_TYPE=|V)",
320
- :count_mode => :only,
321
- :timeout => -1
322
- )
323
- # Return if no records found
324
- if (self.client.rets_data[:code] == "20201")
325
- self.log "No virtual tours found."
326
- return
327
- else
328
- count = self.client.rets_data[:count]
329
- self.log "Importing #{count} virtual tours..."
330
- end
331
-
332
- count = self.client.rets_data[:count]
333
- batch_count = (count.to_f/@@config['limit'].to_f).ceil
334
-
335
- (0...batch_count).each do |i|
336
- params = {
337
- :search_type => 'Media',
338
- :class => 'GFX',
339
- :query => "(MEDIA_TYPE=|V)",
340
- :limit => @@config['limit'],
341
- :offset => @@config['limit'] * i,
342
- :timeout => -1
343
- }
344
- obj = nil
345
- self.client.search(params) do |data|
346
- mls_acct = data['MLS_ACCT'].to_i
347
- m = CabooseRets::Media.exists?("mls_acct = '#{mls_acct}' and media_type = 'Virtual Tour'") ? CabooseRets::Media.where("mls_acct = '#{mls_acct}' and media_type = 'Virtual Tour'").first : CabooseRets::Media.new
348
- m.parse(data)
349
- m.save
350
- end
351
- end
352
- end
353
-
354
- def self.refresh_virtual_tours(p)
355
- self.log("-- Deleting images and metadata for #{p.mls_acct}...")
356
- CabooseRets::Media.where(:mls_acct => p.mls_acct, :media_type => 'Photo').destroy_all
357
-
358
- self.log("-- Downloading image metadata for #{p.mls_acct}...")
359
- params = {
360
- :search_type => 'Media',
361
- :class => 'GFX',
362
- #:query => "(MLS_ACCT=*#{p.id}*),(MEDIA_TYPE=|I)",
363
- :query => "(MLS_ACCT=*#{p.id}*)",
364
- :timeout => -1
365
- }
366
- self.client.search(params) do |data|
367
- m = CabooseRets::Media.new
368
- m.parse(data)
369
- #m.id = m.media_id
370
- m.save
371
- end
372
- end
373
-
374
- #def self.download_property_images(p)
375
- #
376
- # self.log("-- Deleting images and metadata for #{p.mls_acct}...")
377
- # CabooseRets::Media.where(:mls_acct => p.mls_acct, :media_type => 'Photo').destroy_all
378
- #
379
- # self.log("-- Downloading image metadata for #{p.mls_acct}...")
380
- # params = {
381
- # :search_type => 'Media',
382
- # :class => 'GFX',
383
- # :query => "(MLS_ACCT=*#{p.id}*),(MEDIA_TYPE=|I)",
384
- # :timeout => -1
385
- # }
386
- # puts "Before search #{p.id}"
387
- # self.client.search(params) do |data|
388
- # puts "download_property_images self.client.search #{p.id}"
389
- # #m = CabooseRets::Media.new
390
- # #m.parse(data)
391
- # #m.id = m.media_id
392
- # #m.save
393
- # self.download_property_images2(p)
394
- # end
395
- # puts "After search #{p.id}"
396
- #end
397
- #
398
- #def self.download_property_images2(p)
399
- # puts "download_property_images2 #{p.id}"
400
- # sleep(1)
401
- #
402
- # #self.log("-- Downloading images and resizing for #{p.mls_acct}")
403
- # #media = []
404
- # #self.client.get_object(:resource => :Property, :type => :Photo, :location => true, :id => p.id) do |headers, content|
405
- # #
406
- # ## Find the associated media record for the image
407
- # #filename = File.basename(headers['location'])
408
- # #m = CabooseRets::Media.where(:mls_acct => p.mls_acct, :file_name => filename).first
409
- # #
410
- # #if m.nil?
411
- # # self.log("Can't find media record for #{p.mls_acct} #{filename}.")
412
- # #else
413
- # # m.image = URI.parse(headers['location'])
414
- # # media << m
415
- # # #m.save
416
- # #end
417
- # #
418
- # #self.log("-- Uploading images to S3 for #{p.mls_acct}")
419
- # #media.each do |m|
420
- # # m.save
421
- # #end
422
- #end
423
-
424
- #=============================================================================
425
- # GPS
426
- #=============================================================================
427
-
428
- def self.update_coords(p = nil)
429
- if p.nil?
430
- models = [CabooseRets::CommercialProperty, CabooseRets::LandProperty, CabooseRets::MultiFamilyProperty, CabooseRets::ResidentialProperty]
431
- names = ["commercial", "land", "multi-family", "residential"]
432
- i = 0
433
- models.each do |model|
434
- self.log "Updating coords #{names[i]} properties..."
435
- model.where(:latitude => nil).reorder(:mls_acct).each do |p|
436
- self.update_coords(p)
437
- end
438
- i = i + 1
439
- end
440
- return
441
- end
442
-
443
- self.log "Getting coords for mls_acct #{p.mls_acct}..."
444
- coords = self.coords_from_address(CGI::escape "#{p.street_num} #{p.street_name}, #{p.city}, #{p.state} #{p.zip}")
445
- return if coords.nil? || coords == false
446
-
447
- p.latitude = coords['lat']
448
- p.longitude = coords['lng']
449
- p.save
450
- end
451
-
452
- def self.coords_from_address(address)
453
- begin
454
- uri = "https://maps.googleapis.com/maps/api/geocode/json?address=#{address}&sensor=false"
455
- uri.gsub!(" ", "+")
456
- resp = HTTParty.get(uri)
457
- json = JSON.parse(resp.body)
458
- return json['results'][0]['geometry']['location']
459
- rescue
460
- self.log "Error: #{uri}"
461
- sleep(2)
462
- return false
463
- end
464
- end
465
-
466
- #=============================================================================
467
- # Logging
468
- #=============================================================================
469
-
470
- def self.log(msg)
471
- #puts "[rets_importer] #{msg}"
472
- Rails.logger.info("[rets_importer] #{msg}")
473
- end
474
-
475
- #=============================================================================
476
- # Locking update task
477
- #=============================================================================
478
-
479
- def self.last_updated
480
- if !Caboose::Setting.exists?(:name => 'rets_last_updated')
481
- Caboose::Setting.create(:name => 'rets_last_updated', :value => '2013-08-06T00:00:01')
482
- end
483
- s = Caboose::Setting.where(:name => 'rets_last_updated').first
484
- return DateTime.parse(s.value)
485
- end
486
-
487
- def self.save_last_updated(d)
488
- s = Caboose::Setting.where(:name => 'rets_last_updated').first
489
- s.value = d.strftime('%FT%T')
490
- s.save
491
- end
492
-
493
- def self.task_is_locked
494
- return Caboose::Setting.exists?(:name => 'rets_update_running')
495
- end
496
-
497
- def self.lock_task
498
- d = DateTime.now.utc - 5.hours
499
- Caboose::Setting.create(:name => 'rets_update_running', :value => d.strftime('%F %T'))
500
- return d
501
- end
502
-
503
- def self.unlock_task
504
- Caboose::Setting.where(:name => 'rets_update_running').first.destroy
505
- end
506
-
507
- def self.unlock_task_if_last_updated(d)
508
- setting = Caboose::Setting.where(:name => 'rets_update_running').first
509
- self.unlock_task if setting && d.strftime('%F %T') == setting.value
510
- end
511
-
512
- end