mls 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/mls.rb +9 -27
- data/lib/mls/account.rb +120 -16
- data/lib/mls/accounts_region.rb +6 -0
- data/lib/mls/action.rb +18 -0
- data/lib/mls/api_key.rb +5 -0
- data/lib/mls/coworking_space.rb +16 -2
- data/lib/mls/credit_card.rb +11 -0
- data/lib/mls/datum.rb +5 -0
- data/lib/mls/document.rb +8 -26
- data/lib/mls/email.rb +2 -1
- data/lib/mls/email_address.rb +5 -0
- data/lib/mls/email_digest.rb +10 -0
- data/lib/mls/event.rb +30 -5
- data/lib/mls/flyer.rb +11 -0
- data/lib/mls/image_ordering.rb +1 -1
- data/lib/mls/impression_count.rb +21 -0
- data/lib/mls/inquiry.rb +49 -1
- data/lib/mls/invoice.rb +16 -0
- data/lib/mls/lead.rb +1 -5
- data/lib/mls/listing.rb +57 -22
- data/lib/mls/membership.rb +27 -0
- data/lib/mls/metadatum.rb +3 -0
- data/lib/mls/mistake.rb +1 -1
- data/lib/mls/organization.rb +3 -1
- data/lib/mls/ownership.rb +8 -0
- data/lib/mls/phone.rb +7 -1
- data/lib/mls/property.rb +95 -71
- data/lib/mls/region.rb +6 -0
- data/lib/mls/session.rb +2 -2
- data/lib/mls/source.rb +3 -2
- data/lib/mls/subscription.rb +24 -0
- data/lib/mls/task.rb +14 -8
- data/lib/mls/team.rb +6 -0
- data/lib/mls/view.rb +24 -0
- data/lib/mls/webpage.rb +1 -1
- data/mls.gemspec +4 -1
- metadata +59 -8
- data/lib/mls/agency.rb +0 -6
- data/lib/mls/change.rb +0 -40
- data/lib/mls/event_action.rb +0 -6
- data/lib/mls/green_sheet.rb +0 -5
- data/lib/mls/unit.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d679db7d9456ed2f5924a612fd51157607a5c360
|
4
|
+
data.tar.gz: 869b5a1f4d647eb414827322bc9904cb68220488
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec8233dc1a01a4341d793e112bb67540796eb3d5ec90752704213fff4075755e8ad81e7c497bce35a23c47ca81fe0f4cb496f30a0a6150249bd08fc87a088608
|
7
|
+
data.tar.gz: ba2ae50b4822afac5febe29d8bcca90a6af7cd17e5a0d283f29f2ed8d717cbd8571674ae1e06554f0baca2a8b17ffa6304a613f1d6409666e1c65f0e8b18a3f3
|
data/lib/mls.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
require 'phony'
|
1
2
|
require 'sunstone'
|
3
|
+
require 'arel/extensions'
|
4
|
+
require 'bcrypt'
|
2
5
|
|
3
6
|
module MLS
|
4
7
|
|
@@ -98,8 +101,12 @@ module MLS::Slugger
|
|
98
101
|
def find(*ids)
|
99
102
|
friendly = -> (id) { id.respond_to?(:to_i) && id.to_i.to_s != id.to_s }
|
100
103
|
return super if ids.size > 1 || !ids.all? { |x| friendly.call(x) }
|
101
|
-
|
102
|
-
|
104
|
+
|
105
|
+
if ids.first.include?("@")
|
106
|
+
self.filter(email_addresses: {address: ids.first}).first
|
107
|
+
else
|
108
|
+
find_by_slug!(ids.first)
|
109
|
+
end
|
103
110
|
end
|
104
111
|
|
105
112
|
end
|
@@ -149,31 +156,6 @@ module MLS::Avatar
|
|
149
156
|
belongs_to :avatar, :class_name => 'Image'
|
150
157
|
end
|
151
158
|
|
152
|
-
def avatar_url(options={})
|
153
|
-
return nil unless avatar_hash_key
|
154
|
-
|
155
|
-
options.reverse_merge!({
|
156
|
-
:style => nil,
|
157
|
-
:bg => nil,
|
158
|
-
:protocol => 'https',
|
159
|
-
:format => "jpg",
|
160
|
-
:host => MLS.image_host
|
161
|
-
});
|
162
|
-
|
163
|
-
url_params = { s: options[:style], bg: options[:bg] }.select{ |k, v| v }
|
164
|
-
|
165
|
-
if options[:protocol] == :relative # Protocol Relative
|
166
|
-
result = '//'
|
167
|
-
else options[:protocol]
|
168
|
-
result = "#{options[:protocol]}://"
|
169
|
-
end
|
170
|
-
|
171
|
-
result += "#{options[:host]}/#{avatar_hash_key}.#{options[:format]}"
|
172
|
-
result += "?#{url_params.to_param}" if url_params.size > 0
|
173
|
-
|
174
|
-
result
|
175
|
-
end
|
176
|
-
|
177
159
|
end
|
178
160
|
|
179
161
|
Dir.glob(File.join(File.dirname(__FILE__), 'mls', '*.rb'), &method(:require))
|
data/lib/mls/account.rb
CHANGED
@@ -3,21 +3,29 @@ class Account < MLS::Model
|
|
3
3
|
include MLS::Slugger
|
4
4
|
include MLS::Avatar
|
5
5
|
|
6
|
-
has_one :lead, foreign_key: :account_id
|
7
|
-
|
8
6
|
belongs_to :organization
|
9
|
-
belongs_to :
|
7
|
+
belongs_to :membership
|
10
8
|
|
11
9
|
has_many :tasks
|
12
10
|
has_many :sources
|
13
|
-
has_many :
|
11
|
+
has_many :ownerships, :inverse_of => :account, :dependent => :delete_all
|
12
|
+
has_many :assets, through: :ownerships
|
13
|
+
has_many :coworking_spaces, through: :ownerships, source: :asset, source_type: 'CoworkingSpace'
|
14
|
+
has_many :listings, through: :ownerships, source: :asset, source_type: 'Listing', inverse_of: :accounts
|
15
|
+
has_many :email_digests
|
16
|
+
has_many :subscriptions, as: :subject
|
17
|
+
has_many :leads
|
14
18
|
|
15
|
-
|
19
|
+
has_many :credit_cards
|
16
20
|
|
17
21
|
has_many :email_addresses do
|
18
22
|
def primary
|
19
23
|
# For cases where the number is not primary we order
|
20
|
-
|
24
|
+
if loaded?
|
25
|
+
select{|x| x.primary}.first
|
26
|
+
else
|
27
|
+
order(:primary => :desc).first
|
28
|
+
end
|
21
29
|
end
|
22
30
|
end
|
23
31
|
|
@@ -25,30 +33,126 @@ class Account < MLS::Model
|
|
25
33
|
|
26
34
|
def primary
|
27
35
|
# For cases where the number is not primary we order
|
28
|
-
|
36
|
+
if loaded?
|
37
|
+
select{|x| x.primary}.first
|
38
|
+
else
|
39
|
+
order(:primary => :desc).first
|
40
|
+
end
|
29
41
|
end
|
30
42
|
|
31
43
|
end
|
32
44
|
|
45
|
+
has_and_belongs_to_many :advertised_regions, join_table: 'accounts_regions_advertised', class_name: 'Region'
|
46
|
+
has_and_belongs_to_many :inquiries
|
47
|
+
has_and_belongs_to_many :teams
|
48
|
+
|
49
|
+
attr_accessor :password, :password_required
|
50
|
+
accepts_nested_attributes_for :phones, :email_addresses
|
51
|
+
|
52
|
+
validates :password, confirmation: true, if: Proc.new {|a| (!a.persisted? && a.password_required?) || !a.password.nil? }
|
53
|
+
validates :password, length: { minimum: 6 }, if: :password
|
54
|
+
validates :password_confirmation, presence: true, if: :password
|
55
|
+
|
56
|
+
def regions
|
57
|
+
Region.filter(id: {in: self.advertised_region_ids})
|
58
|
+
end
|
59
|
+
|
60
|
+
def city_regions
|
61
|
+
advertised_regions.filter(type: Region::CITY_TYPES).order(listings_count: :desc)
|
62
|
+
end
|
63
|
+
|
64
|
+
def properties
|
65
|
+
Property.where(listings: {ownerships: {account_id: self.id}})
|
66
|
+
end
|
67
|
+
|
68
|
+
def tim_alerts?
|
69
|
+
self.membership&.subscriptions&.filter(started_at: true, status: {not: "closed"}, type: "tim_alerts", subject_id: self.id, subject_type: "Account")&.count.try(:>, 0)
|
70
|
+
end
|
71
|
+
|
72
|
+
def unlimited?
|
73
|
+
self.membership&.subscriptions&.filter(started_at: true, status: {not: "closed"}, type: "unlimited", subject_id: self.id, subject_type: "Account")&.count.try(:>, 0)
|
74
|
+
end
|
75
|
+
|
76
|
+
def paying?
|
77
|
+
self.membership&.subscriptions&.filter(started_at: true, status: {not: "closed"})&.count.try(:>, 0)
|
78
|
+
end
|
79
|
+
|
80
|
+
def password_required?
|
81
|
+
@password_required != false
|
82
|
+
end
|
83
|
+
|
84
|
+
def password=(pass)
|
85
|
+
@password = pass
|
86
|
+
self.password_digest = BCrypt::Password.create(pass)
|
87
|
+
end
|
88
|
+
|
33
89
|
def email_address
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
90
|
+
email_addresses.to_a.find{|p| p.primary }.try(:address)
|
91
|
+
end
|
92
|
+
|
93
|
+
def regions_attributes=(regions_attrs)
|
94
|
+
# regions.clear was trying to destroy all regions going to "/accounts_regions/" method = Destroy
|
95
|
+
AccountsRegion.where(:agent_id => self.id).destroy_all
|
96
|
+
return if regions_attrs.nil?
|
97
|
+
regions_attrs.each do |attrs|
|
98
|
+
region = Region.find(attrs["id"])
|
99
|
+
regions.push(region)
|
38
100
|
end
|
39
101
|
end
|
40
102
|
|
41
103
|
def phone
|
42
|
-
|
43
|
-
phones.to_a.find{|p| p.primary }.try(:number)
|
44
|
-
else
|
45
|
-
phones.primary.try(:number)
|
46
|
-
end
|
104
|
+
(phones.to_a.find{|p| p.primary } || phones.first).try(:number)
|
47
105
|
end
|
48
106
|
|
107
|
+
def role?(*compare_roles)
|
108
|
+
(roles & compare_roles).any?
|
109
|
+
end
|
110
|
+
alias_method :roles?, :role?
|
111
|
+
|
49
112
|
def company_name
|
50
113
|
return organization.name if organization
|
51
114
|
return company
|
52
115
|
end
|
116
|
+
|
117
|
+
def merge_in(account_id)
|
118
|
+
req = Net::HTTP::Put.new("/accounts/#{self.id}/merge")
|
119
|
+
req.body = { account_id: account_id }.to_json
|
120
|
+
Account.connection.instance_variable_get(:@connection).send_request(req)
|
121
|
+
return true
|
122
|
+
rescue Sunstone::Exception::NotFound
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.send_reset_password_email(url, email_address)
|
127
|
+
req = Net::HTTP::Post.new("/accounts/password")
|
128
|
+
req.body = { email_address: email_address, url: url }.to_json
|
129
|
+
Account.connection.instance_variable_get(:@connection).send_request(req)
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.update_password(token, password, password_confirmation)
|
133
|
+
req = Net::HTTP::Put.new("/accounts/password")
|
134
|
+
req.body = {
|
135
|
+
token: token,
|
136
|
+
password: password,
|
137
|
+
password_confirmation: password_confirmation
|
138
|
+
}.to_json
|
139
|
+
Account.connection.instance_variable_get(:@connection).send_request(req)
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.confirm(token)
|
143
|
+
req = Net::HTTP::Post.new("/accounts/confirm")
|
144
|
+
req.body = { token: token }.to_json
|
145
|
+
Account.connection.instance_variable_get(:@connection).send_request(req)
|
146
|
+
return true
|
147
|
+
rescue Sunstone::Exception::NotFound
|
148
|
+
return false
|
149
|
+
end
|
150
|
+
|
151
|
+
def send_confirmation_email(url)
|
152
|
+
req = Net::HTTP::Post.new("/accounts/#{self.id}/confirm")
|
153
|
+
req.body = {url: url}.to_json
|
154
|
+
Account.connection.instance_variable_get(:@connection).send_request(req)
|
155
|
+
end
|
156
|
+
|
53
157
|
|
54
158
|
end
|
data/lib/mls/action.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Action < MLS::Model
|
2
|
+
self.inheritance_column = nil
|
3
|
+
|
4
|
+
belongs_to :event
|
5
|
+
belongs_to :subject, :polymorphic => true
|
6
|
+
|
7
|
+
has_many :mistakes
|
8
|
+
has_many :metadata, foreign_key: :event_id, primary_key: :event_id
|
9
|
+
|
10
|
+
def self.by_performer(filter)
|
11
|
+
req = Net::HTTP::Get.new("/actions/by_performer")
|
12
|
+
req.body = {
|
13
|
+
where: filter
|
14
|
+
}.to_json
|
15
|
+
JSON.parse(connection.instance_variable_get(:@connection).send_request(req).body)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/lib/mls/api_key.rb
ADDED
data/lib/mls/coworking_space.rb
CHANGED
@@ -4,15 +4,29 @@ class CoworkingSpace < MLS::Model
|
|
4
4
|
|
5
5
|
belongs_to :organization
|
6
6
|
belongs_to :property
|
7
|
+
belongs_to :membership
|
7
8
|
has_many :image_orderings, as: :subject
|
8
9
|
has_many :photos, through: :image_orderings, source: :image
|
9
10
|
has_many :spaces
|
10
11
|
has_many :addresses, :through => :property
|
11
12
|
|
12
|
-
|
13
|
+
has_many :ownerships, as: :asset
|
14
|
+
has_many :accounts, through: :ownerships
|
15
|
+
|
16
|
+
accepts_nested_attributes_for :spaces, :ownerships, :accounts
|
17
|
+
|
18
|
+
def display_name
|
13
19
|
output = organization.name
|
14
20
|
output += " - " + read_attribute(:name) if read_attribute(:name)
|
15
21
|
output
|
16
22
|
end
|
23
|
+
|
24
|
+
def longitude
|
25
|
+
location.x
|
26
|
+
end
|
27
|
+
|
28
|
+
def latitude
|
29
|
+
location.y
|
30
|
+
end
|
17
31
|
|
18
|
-
end
|
32
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class CreditCard < MLS::Model
|
2
|
+
|
3
|
+
belongs_to :account
|
4
|
+
|
5
|
+
def name
|
6
|
+
string = "•••• ••••• •" if self.brand == "American Express"
|
7
|
+
string ||= "•••• •••• •••• "
|
8
|
+
string += self.last4
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
data/lib/mls/datum.rb
ADDED
data/lib/mls/document.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
class Document < MLS::Model
|
2
2
|
|
3
|
+
has_many :image_orderings, foreign_key: :image_id
|
4
|
+
|
3
5
|
def self.create(file)
|
4
6
|
if doc = find_matching(file)
|
5
7
|
doc
|
@@ -16,13 +18,17 @@ class Document < MLS::Model
|
|
16
18
|
end
|
17
19
|
|
18
20
|
def url(style=:original)
|
19
|
-
MLS.config['document_host'] + path(style)
|
21
|
+
MLS.config['document_host'] + '/' + path(style)
|
20
22
|
end
|
21
23
|
|
22
24
|
def path(style=:original)
|
23
|
-
"
|
25
|
+
"#{partition(style == :original ? hash_key : "#{hash_key}-#{style}")}"
|
24
26
|
end
|
25
27
|
|
28
|
+
def partition(value)
|
29
|
+
split = value.scan(/.{1,4}/)
|
30
|
+
split.shift(4).join("/") + split.join("")
|
31
|
+
end
|
26
32
|
|
27
33
|
def width
|
28
34
|
return nil if !dimensions
|
@@ -59,30 +65,6 @@ class Document < MLS::Model
|
|
59
65
|
end
|
60
66
|
|
61
67
|
class Image < Document
|
62
|
-
|
63
|
-
def url(options={})
|
64
|
-
options.reverse_merge!({
|
65
|
-
:style => nil,
|
66
|
-
:bg => nil,
|
67
|
-
:protocol => 'https',
|
68
|
-
:format => "jpg",
|
69
|
-
:host => MLS.image_host
|
70
|
-
});
|
71
|
-
|
72
|
-
url_params = {s: options[:style], bg: options[:bg]}.select{ |k, v| v }
|
73
|
-
|
74
|
-
if options[:protocol] == :relative # Protocol Relative
|
75
|
-
result = '//'
|
76
|
-
else options[:protocol]
|
77
|
-
result = "#{options[:protocol]}://"
|
78
|
-
end
|
79
|
-
|
80
|
-
result += "#{options[:host]}/#{hash_key}.#{options[:format]}"
|
81
|
-
result += "?#{url_params.to_param}" if url_params.size > 0
|
82
|
-
|
83
|
-
result
|
84
|
-
end
|
85
|
-
|
86
68
|
end
|
87
69
|
|
88
70
|
class PDF < Document
|
data/lib/mls/email.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
class Email < MLS::Model
|
2
2
|
|
3
3
|
belongs_to :source
|
4
|
+
has_many :tasks, :as => :subject, :inverse_of => :subject
|
4
5
|
has_and_belongs_to_many :attachments, :class_name => 'Document'
|
5
6
|
|
6
7
|
def from
|
@@ -12,7 +13,7 @@ class Email < MLS::Model
|
|
12
13
|
end
|
13
14
|
|
14
15
|
def name
|
15
|
-
from
|
16
|
+
from_address || from
|
16
17
|
end
|
17
18
|
|
18
19
|
def to
|
data/lib/mls/email_address.rb
CHANGED
data/lib/mls/event.rb
CHANGED
@@ -4,17 +4,42 @@ class Event < MLS::Model
|
|
4
4
|
|
5
5
|
belongs_to :account
|
6
6
|
belongs_to :task
|
7
|
+
belongs_to :api_key
|
7
8
|
|
8
|
-
has_many :
|
9
|
+
has_many :actions
|
9
10
|
|
10
11
|
has_many :regards
|
11
12
|
|
12
|
-
|
13
|
-
event_actions.map(&:action)
|
14
|
-
end
|
13
|
+
enum type: { create: 0, update: 1, delete: 2 }, _suffix: true
|
15
14
|
|
16
15
|
def regarding
|
17
16
|
regards.map(&:thing)
|
18
17
|
end
|
19
18
|
|
20
|
-
|
19
|
+
def encapsulate(&block)
|
20
|
+
Thread.current[:sunstone_headers] ||= {}
|
21
|
+
Thread.current[:sunstone_headers]['Event-Id'] = self.id
|
22
|
+
yield
|
23
|
+
self
|
24
|
+
ensure
|
25
|
+
Thread.current[:sunstone_headers].delete('Event-Id')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Allow you to encapsulate all modification to be attached to a single event
|
29
|
+
#
|
30
|
+
# Event.encapsulate(source: '...', source_type: 'API') do
|
31
|
+
# ...
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# Returns the event is needed in the future
|
35
|
+
def self.encapsulate(options={}, &block)
|
36
|
+
event = Event.create!(options)
|
37
|
+
Thread.current[:sunstone_headers] ||= {}
|
38
|
+
Thread.current[:sunstone_headers]['Event-Id'] = event.id
|
39
|
+
yield
|
40
|
+
event
|
41
|
+
ensure
|
42
|
+
Thread.current[:sunstone_headers].try(:delete, 'Event-Id')
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|