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 +5 -5
- data/bin/mls +22 -1
- data/lib/mls/cli.rb +13 -1
- data/lib/mls/cli/documents.rb +4 -3
- data/lib/mls/cli/storage.rb +2 -1
- data/lib/mls/cli/storage/b2.rb +87 -0
- data/lib/mls/models/account.rb +1 -0
- data/lib/mls/models/broadcast.rb +11 -0
- data/lib/mls/models/document.rb +2 -1
- data/lib/mls/models/listing.rb +1 -1
- data/lib/mls/models/property.rb +2 -2
- data/lib/mls/models/region.rb +1 -0
- data/lib/mls/models/review.rb +18 -0
- data/lib/mls/models/task.rb +2 -0
- data/mls.gemspec +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 61267aa211891a0f0f6d22339b6997745fa532cdb4d50390b5b8645cfb887ffe
|
4
|
+
data.tar.gz: 1df8ded07de72295b7ea2852323cb51838398c77a2a782dffa0c6b4ff03c2c0b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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)
|
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
|
data/lib/mls/cli.rb
CHANGED
@@ -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
|
data/lib/mls/cli/documents.rb
CHANGED
@@ -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.
|
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
|
-
|
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))
|
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))
|
data/lib/mls/cli/storage.rb
CHANGED
@@ -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
|
data/lib/mls/models/account.rb
CHANGED
data/lib/mls/models/document.rb
CHANGED
@@ -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)
|
data/lib/mls/models/listing.rb
CHANGED
data/lib/mls/models/property.rb
CHANGED
@@ -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 =>
|
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.
|
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
|
|
data/lib/mls/models/region.rb
CHANGED
@@ -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'
|
data/lib/mls/models/task.rb
CHANGED
@@ -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
|
data/mls.gemspec
CHANGED
@@ -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
|
+
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.
|
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-
|
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.
|
337
|
+
rubygems_version: 2.7.4
|
335
338
|
signing_key:
|
336
339
|
specification_version: 4
|
337
340
|
summary: 42Floors MLS Client
|