mls 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: '05855a1a8a8ff7514aa0d09798c336972c6443cc'
4
- data.tar.gz: 689bc19414f3f6516d74bb8f8721d6019fb86060
2
+ SHA256:
3
+ metadata.gz: 61267aa211891a0f0f6d22339b6997745fa532cdb4d50390b5b8645cfb887ffe
4
+ data.tar.gz: 1df8ded07de72295b7ea2852323cb51838398c77a2a782dffa0c6b4ff03c2c0b
5
5
  SHA512:
6
- metadata.gz: e675d1684d26d1fc2a5c64fe995bce74f185090a161844091bc24b5bfc7d6f36d723d2a6f57700ee41589dedb58d77044ab29a752ed75c3783f714fa2bdc827b
7
- data.tar.gz: a94d1a6219a065cbc0c436e167f06a333c90662aec2160d5cf62e3a4dd1bed96100d2296e364d1ce71c9fd1b9cb6488aaaced1e66cdd0f9e60bf683534fad5ae
6
+ metadata.gz: 169618f8b6f8aec727b99d2a4a893cdcd292ae925095f57df1431d28f72d1fde6a6a3891b65505abd935de9268a5c8b639b1f5c72393c7bff72ee4391c790593
7
+ data.tar.gz: 983cc885eb785faa6dc33e4dce9246b368b9519ab4d451aca20708e0fc47f282401d9238ed5fbc8b33ef253b8715df88200247768b1b72882d17c819a8b143d7
data/bin/mls CHANGED
@@ -3,7 +3,7 @@ require File.expand_path('../../lib/mls/cli', __FILE__)
3
3
 
4
4
  case ARGV.shift.downcase.strip
5
5
  when "documents:backup"
6
- MLS::CLI.parse_args(ARGV).inspect
6
+ MLS::CLI.parse_args(ARGV)
7
7
  directory = ARGV.shift
8
8
 
9
9
  if directory.nil? || !File.directory?(directory)
@@ -12,6 +12,27 @@ when "documents:backup"
12
12
  end
13
13
 
14
14
  MLS::CLI::Documents.backup(directory)
15
+ when "documents:migrate"
16
+ MLS::CLI.parse_args(ARGV)
17
+ directory = ARGV.shift
18
+
19
+ if directory.nil? || !File.directory?(directory)
20
+ puts "Usage: mls documents:backup dir [options...]"
21
+ exit 1
22
+ end
23
+
24
+ b2 = MLS::CLI::Storage::B2.new(MLS::CLI.options[:b2])
25
+ Document.where(excludes: 'b2/sha256').find_each do |document|
26
+ if document.sha256 && File.exists?(File.join(directory, MLS::CLI::Documents.partition(document.sha256)))
27
+ b2.upload_file(documents.sha256, File.open(File.join(directory, MLS::CLI::Documents.partition(document.sha256))), {
28
+ filename: document.filename,
29
+ sha1: document.sha1,
30
+ content_type: document.content_type,
31
+ size: document.size
32
+ })
33
+ end
34
+ end
35
+ when "documents:check"
15
36
  else
16
37
  puts "Usage: mls documents:backup dir [options...]"
17
38
  end
@@ -32,7 +32,19 @@ module MLS::CLI
32
32
  end
33
33
  end
34
34
  when 'b2'
35
-
35
+ MLS::CLI.options[:b2] = {
36
+ account_id: URI.unescape(url.user),
37
+ application_key: URI.unescape(url.password),
38
+ bucket: URI.unescape(url.host)
39
+ prefix: url.path&.empty? ? url.path : nil
40
+ }
41
+ url.query.split('&').each do |qp|
42
+ key, value = qp.split('=').map { |d| URI.unescape(d) }
43
+ case key
44
+ when 'partition'
45
+ MLS::CLI.options[:b2][:partition] = value.to_i
46
+ end
47
+ end
36
48
  when 'mls'
37
49
  arg = arg.sub('mls://', 'https://')
38
50
  MLS::CLI.options[:mls] = arg
@@ -33,7 +33,7 @@ module MLS::CLI::Documents
33
33
 
34
34
  query = if File.exist?(last_sync_file)
35
35
  from_timestamp = Time.iso8601(File.read(last_sync_file))
36
- Document.filter(created_at: {gte: from_timestamp})
36
+ Document.where(Document.arel_table['created_at'].gteq(from_timestamp))
37
37
  else
38
38
  Document.all
39
39
  end
@@ -51,15 +51,16 @@ module MLS::CLI::Documents
51
51
  raise 'unkown storage engine'
52
52
  end
53
53
 
54
- puts "Downloading #{document.id}"
54
+ print "Downloading #{document.id.to_s.ljust(7)} "
55
55
  storage_engine.copy_to_tempfile(document.send(key)) do |file|
56
56
  digests = calculate_digest(file)
57
+ puts partition(document.sha256)
57
58
 
58
59
  raise 'MD5 does not match' if digests[:md5] != document.md5
59
60
  document.update!(digests.merge({provider: ['s3/hash_key']}))
60
61
 
61
62
  FileUtils.mkdir_p(File.dirname(File.join(dir, partition(document.sha256))))
62
- FileUtils.mv(file.path, File.join(dir, partition(document.sha256)), verbose: true)
63
+ FileUtils.mv(file.path, File.join(dir, partition(document.sha256)))
63
64
  end
64
65
 
65
66
  File.write(last_sync_file, document.created_at.iso8601(6))
@@ -1 +1,2 @@
1
- require File.expand_path('../storage/s3', __FILE__)
1
+ require File.expand_path('../storage/s3', __FILE__)
2
+ require File.expand_path('../storage/b2', __FILE__)
@@ -0,0 +1,87 @@
1
+ require 'b2'
2
+
3
+ module MLS::CLI::Storage
4
+ class B2
5
+
6
+ def initialize(configs = {})
7
+ @configs = configs
8
+ @configs[:prefix] ||= ""
9
+
10
+ @client = B2::Bucket.new({
11
+ 'bucketId' => configs[:bucket_id]
12
+ }, B2.new({
13
+ account_id: configs[:account_id],
14
+ application_key: configs[:application_key]
15
+ }))
16
+ end
17
+
18
+ def local?
19
+ false
20
+ end
21
+
22
+ # def url(key)
23
+ # [host, destination(key)].join('/')
24
+ # end
25
+
26
+ # def host
27
+ # h = @configs[:bucket_host_alias] || "https://s3.amazonaws.com/#{@configs[:bucket]}"
28
+ # h.delete_suffix('/')
29
+ # end
30
+
31
+ def destination(key)
32
+ "#{@configs[:prefix]}#{partition(key)}".gsub(/^\//, '')
33
+ end
34
+
35
+ def exists?(key)
36
+ @client.has_key?(destination(key))
37
+ end
38
+
39
+ def write(key, file, meta_info)
40
+ file = file.tempfile if file.is_a?(ActionDispatch::Http::UploadedFile)
41
+ file = File.open(file) if file.is_a?(String)
42
+
43
+ @client.upload_file(key, file, mime_type: meta_info[:content_type], sha1: meta_info[:sha1], content_disposition: "inline; filename=\"#{meta_info[:filename]}\"")
44
+ end
45
+
46
+ def download(key, to=nil, &block)
47
+ @client.download(destination(key), to, &block)
48
+ end
49
+
50
+ def delete(key)
51
+ @client.delete!(key)
52
+ end
53
+
54
+ def copy_to_tempfile(key)
55
+ tmpfile = Tempfile.new([File.basename(key), File.extname(key)], binmode: true)
56
+ download(key, tmpfile.path)
57
+ if block_given?
58
+ begin
59
+ yield(tmpfile)
60
+ ensure
61
+ tmpfile.close!
62
+ end
63
+ else
64
+ tmpfile
65
+ end
66
+ end
67
+
68
+ def partition(value)
69
+ return value unless @configs[:partition]
70
+ split = value.scan(/.{1,4}/)
71
+ split.shift(@configs[:partition_depth] || 3).join("/") + split.join("")
72
+ end
73
+
74
+ def sha1(key)
75
+ @client.file(destination(key)).sha1
76
+ end
77
+
78
+ def last_modified(key)
79
+ @client.file(destination(key)).uploaded_at
80
+ end
81
+
82
+ def mime_type(key)
83
+ @client.file(destination(key)).mime_type
84
+ end
85
+
86
+ end
87
+ end
@@ -21,6 +21,7 @@ class Account < MLS::Model
21
21
 
22
22
  has_many :searches
23
23
  has_many :suggestions, foreign_key: "suggested_by_id"
24
+ has_many :broadcasts, foreign_key: :sender_id
24
25
 
25
26
  has_many :credit_cards
26
27
 
@@ -0,0 +1,11 @@
1
+ class Broadcast < MLS::Model
2
+
3
+ belongs_to :sender, class_name: 'Account'
4
+
5
+ has_many :emails
6
+
7
+ has_and_belongs_to_many :regions
8
+ has_and_belongs_to_many :listings
9
+ has_and_belongs_to_many :attachments, class_name: 'Document'
10
+
11
+ end
@@ -1,6 +1,7 @@
1
1
  class Document < MLS::Model
2
2
 
3
3
  has_many :image_orderings, foreign_key: :image_id
4
+ has_many :reviews
4
5
 
5
6
  def self.create(file)
6
7
  if doc = find_matching(file)
@@ -18,7 +19,7 @@ class Document < MLS::Model
18
19
  end
19
20
 
20
21
  def url(style=:original)
21
- MLS.config['document_host'] + '/' + path(style)
22
+ MLS.config['document_host'].gsub(/\/$/, '') + '/' + path(style)
22
23
  end
23
24
 
24
25
  def path(style=:original)
@@ -168,7 +168,7 @@ class Listing < MLS::Model
168
168
  "Leased"
169
169
  elsif self.archived
170
170
  "Deleted"
171
- elsif self.touched_at < 90.days.ago
171
+ elsif self.touched_at < 180.days.ago
172
172
  "Expired"
173
173
  else
174
174
  "Active"
@@ -33,7 +33,7 @@ class Property < MLS::Model
33
33
  accepts_nested_attributes_for :image_orderings, :addresses
34
34
 
35
35
  def contacts
36
- @contact ||= listings.eager_load(:accounts => [:email_addresses, :phones, :organization]).filter(leased_at: nil, authorized: true, type: ['Lease', 'Sublease'], :touched_at => {:gte => 90.days.ago})
36
+ @contact ||= listings.eager_load(:accounts => [:email_addresses, :phones, :organization]).filter(leased_at: nil, authorized: true, type: ['Lease', 'Sublease'], :touched_at => {:gte => 180.days.ago})
37
37
  .order(size: :desc).first.try(:contacts)
38
38
  end
39
39
 
@@ -128,7 +128,7 @@ class Property < MLS::Model
128
128
  region = neighborhood_region
129
129
  region ||= city_region
130
130
  region ||= market
131
- region ||= regions.where(depth: true).sort_by(&:depth).reverse.first
131
+ region ||= regions.filter(depth: true).select{ |r| r.type != "Zip Code Tabulation Area" }.sort_by(&:depth).reverse.first
132
132
  region
133
133
  end
134
134
 
@@ -15,6 +15,7 @@ class Region < MLS::Model
15
15
  has_one :geometry, as: :subject
16
16
  has_many :stats, as: :subject
17
17
 
18
+ has_and_belongs_to_many :tasks
18
19
  has_and_belongs_to_many :organizations
19
20
  has_and_belongs_to_many :parents, :join_table => 'regions_regions', :class_name => 'Region', :foreign_key => 'child_id', :association_foreign_key => 'parent_id'
20
21
  has_and_belongs_to_many :children, :join_table => 'regions_regions', :class_name => 'Region', :foreign_key => 'parent_id', :association_foreign_key => 'child_id'
@@ -0,0 +1,18 @@
1
+ class Review < MLS::Model
2
+
3
+ belongs_to :document
4
+ belongs_to :account
5
+
6
+ def approved?
7
+ approval == true
8
+ end
9
+
10
+ def rejected?
11
+ approval == false
12
+ end
13
+
14
+ def pending?
15
+ approval == nil
16
+ end
17
+
18
+ end
@@ -11,6 +11,8 @@ class Task < MLS::Model
11
11
  has_many :reviews, -> { where(:type => "review") }, :class_name => "Task", :as => :subject, :inverse_of => :subject
12
12
  has_many :fixes, -> { where(:type => "fix") }, :class_name => "Task", :as => :subject, :inverse_of => :subject
13
13
 
14
+ has_and_belongs_to_many :regions
15
+
14
16
  def for_source?
15
17
  subject_type == "Source"
16
18
  end
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "mls"
6
- s.version = '1.6.0'
6
+ s.version = '1.7.0'
7
7
  s.authors = ["Jon Bracy", "James R. Bracy"]
8
8
  s.email = ["jon@42floors.com", "james@42floors.com"]
9
9
  s.homepage = "http://mls.42floors.com"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mls
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Bracy
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-01-07 00:00:00.000000000 Z
12
+ date: 2018-07-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -253,6 +253,7 @@ files:
253
253
  - lib/mls/cli.rb
254
254
  - lib/mls/cli/documents.rb
255
255
  - lib/mls/cli/storage.rb
256
+ - lib/mls/cli/storage/b2.rb
256
257
  - lib/mls/cli/storage/s3.rb
257
258
  - lib/mls/comment.rb
258
259
  - lib/mls/models/account.rb
@@ -260,6 +261,7 @@ files:
260
261
  - lib/mls/models/action.rb
261
262
  - lib/mls/models/address.rb
262
263
  - lib/mls/models/api_key.rb
264
+ - lib/mls/models/broadcast.rb
263
265
  - lib/mls/models/coworking_space.rb
264
266
  - lib/mls/models/credit_card.rb
265
267
  - lib/mls/models/datum.rb
@@ -286,6 +288,7 @@ files:
286
288
  - lib/mls/models/recommendation.rb
287
289
  - lib/mls/models/reference.rb
288
290
  - lib/mls/models/region.rb
291
+ - lib/mls/models/review.rb
289
292
  - lib/mls/models/search.rb
290
293
  - lib/mls/models/service.rb
291
294
  - lib/mls/models/session.rb
@@ -331,7 +334,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
331
334
  version: '0'
332
335
  requirements: []
333
336
  rubyforge_project: mls
334
- rubygems_version: 2.6.11
337
+ rubygems_version: 2.7.4
335
338
  signing_key:
336
339
  specification_version: 4
337
340
  summary: 42Floors MLS Client