g5_updatable 0.10.3 → 0.20.3.pre.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/README.md +33 -2
- data/app/concerns/g5_updatable/belongs_to_client.rb +3 -3
- data/app/controllers/g5_updatable/feed_controller.rb +1 -1
- data/app/controllers/g5_updatable/locations_controller.rb +2 -2
- data/app/controllers/g5_updatable/syncs_controller.rb +3 -3
- data/app/models/g5_updatable/client.rb +4 -4
- data/app/models/g5_updatable/hub_amenities_location.rb +6 -0
- data/app/models/g5_updatable/hub_amenity.rb +21 -0
- data/app/models/g5_updatable/location.rb +75 -2
- data/app/serializers/g5_updatable/location_serializer.rb +8 -0
- data/db/migrate/20151103043916_add_latitude_and_longitude_to_location.rb +6 -0
- data/db/migrate/20151103050229_copy_lat_long_props_to_lat_long_columns.rb +19 -0
- data/db/migrate/20151106070749_add_latitude_longitude_indexes_to_location.rb +6 -0
- data/db/migrate/20161122070749_add_amenities.rb +25 -0
- data/db/migrate/20161209070749_add_client_urn_to_locations.rb +6 -0
- data/lib/g5_updatable.rb +5 -3
- data/lib/g5_updatable/all_client_urns_fetcher.rb +17 -0
- data/lib/g5_updatable/client_feed_processor.rb +26 -14
- data/lib/g5_updatable/client_updater.rb +37 -12
- data/lib/g5_updatable/factories.rb +2 -2
- data/lib/g5_updatable/fetcher.rb +22 -0
- data/lib/g5_updatable/indifferentizer.rb +11 -0
- data/lib/g5_updatable/locations_updater.rb +68 -20
- data/lib/g5_updatable/rspec/factories.rb +53 -2
- data/lib/g5_updatable/version.rb +1 -1
- data/lib/tasks/g5_updatable_tasks.rake +11 -4
- data/spec/concerns/g5_updatable/belongs_to_client_spec.rb +1 -3
- data/spec/controllers/feed_controller_spec.rb +21 -0
- data/spec/controllers/syncs_controller_spec.rb +3 -3
- data/spec/dummy/config/database.yml +2 -2
- data/spec/dummy/db/schema.rb +28 -1
- data/spec/dummy/log/development.log +172 -146
- data/spec/dummy/log/test.log +101011 -13426
- data/spec/dummy/log/tests.log +0 -0
- data/spec/fixtures/client-g5-c-1soj8m6e-g5-multifamily-missing-locations.json +121 -0
- data/spec/fixtures/client-g5-c-1soj8m6e-g5-multifamily-no-locations.json +41 -0
- data/spec/fixtures/client-g5-c-1soj8m6e-g5-multifamily.json +471 -0
- data/spec/fixtures/hub-client.json +187 -0
- data/spec/fixtures/hub-clients.json +19972 -0
- data/spec/fixtures/hub-location.json +166 -0
- data/spec/fixtures/location-g5-cl-1soj9pe2-541-apartments.json +98 -0
- data/spec/fixtures/urns.json +10 -0
- data/spec/lib/g5_updatable/all_client_urns_fetcher_spec.rb +56 -0
- data/spec/lib/g5_updatable/client_feed_processor_spec.rb +86 -33
- data/spec/lib/g5_updatable/client_updater_spec.rb +55 -23
- data/spec/lib/g5_updatable/locations_updater_spec.rb +140 -54
- data/spec/models/g5_updatable/client_spec.rb +2 -0
- data/spec/models/g5_updatable/hub_amenities_location_spec.rb +6 -0
- data/spec/models/g5_updatable/hub_amenity_spec.rb +29 -0
- data/spec/models/g5_updatable/location_spec.rb +240 -10
- data/spec/serializers/g5_updatable/location_serializer_spec.rb +2 -1
- data/spec/spec_helper.rb +2 -1
- data/spec/support/fixture_helper.rb +5 -0
- data/spec/support/shared_examples/belongs_to_client.rb +4 -5
- metadata +84 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fff24c03cbb209168e956147a0266737b9bcfba9
|
4
|
+
data.tar.gz: b459baf96623cb716ed624e606307f1712359d40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fccf2277a17f67d1c7945ef14c90084b60eb11d42e5937352b4cefe52b45fa79d704f857329593df4bddf78a3571d0987b4b731bf0424d1e30c1e7b1ce35e825
|
7
|
+
data.tar.gz: c550dc2f70ec537c76570849bc2f54b637367b5ad5c9c55bf59dae1bae1d1d2acf99adb11b97ef4d97b70993a50ebd74829106e3e7028056be686db8af4aac0c
|
data/README.md
CHANGED
@@ -38,9 +38,12 @@ G5 Updatable makes use of PostgrSQL's `json` field type, and so only supports im
|
|
38
38
|
```
|
39
39
|
3. Optional: load all of G5-Hub's data into your database
|
40
40
|
|
41
|
+
**Important:** The entries.js and entries.json endpoint on the hub are deprecated. So, for all versions of g5_updatable before 0.17.0, this task will only load the newest 10 clients. If you would like to load all clients, please specify "~> 0.17.0" or higher in your Gemfile.
|
42
|
+
|
41
43
|
```console
|
42
44
|
rake g5_updatable:load_all
|
43
|
-
```
|
45
|
+
```
|
46
|
+
|
44
47
|
Note, all of the G5_AUTH env variables need to be set for this to work.
|
45
48
|
|
46
49
|
## Usage
|
@@ -58,14 +61,42 @@ G5 Updatable also exposes two GET endpoints which return JSON:
|
|
58
61
|
|
59
62
|
### Hooks
|
60
63
|
|
64
|
+
Execute code each time a new client is created:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
G5Updatable::ClientUpdater.on_create do |g5_updatable_client|
|
68
|
+
puts "#{g5_updatable_client.name} was just created"
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
61
72
|
To execute code every time a location is updated:
|
62
73
|
|
63
74
|
```ruby
|
64
|
-
G5Updatable::
|
75
|
+
G5Updatable::LocationsUpdater.on_update do |g5_updatable_location|
|
76
|
+
puts "G5Updatable::Location##{g5_updatable_location.id} was just updated"
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
Also optionally expect a secondary block argument, receiving the object previous to be updated
|
81
|
+
... you know.. For diff reasons.
|
82
|
+
```ruby
|
83
|
+
G5Updatable::LocationsUpdater.on_update do |g5_updatable_location, before_update_location|
|
84
|
+
puts "G5Updatable::Location##{before_update_location.properties} changed to "
|
85
|
+
puts "G5Updatable::Location##{g5_updatable_location.properties} "
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
|
90
|
+
or, execute code only when a location is created:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
G5Updatable::LocationsUpdater.on_create do |g5_updatable_location|
|
65
94
|
puts "G5Updatable::Location##{g5_updatable_location.id} was just updated"
|
66
95
|
end
|
67
96
|
```
|
68
97
|
|
98
|
+
The `on_create` callback is called right before the `on_update` callback when a new location is created.
|
99
|
+
|
69
100
|
### Associations
|
70
101
|
|
71
102
|
You will likely have models in your own application that are associated with a Client or Location. A module is available to include in your related models to support this association. Assuming your model has a `client_uid` or `location_uid` string field respectively, you can do the following:
|
@@ -4,9 +4,9 @@ module G5Updatable::BelongsToClient
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
belongs_to(:client, {
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
class_name: 'G5Updatable::Client',
|
8
|
+
foreign_key: :client_urn,
|
9
|
+
primary_key: :urn,
|
10
10
|
})
|
11
11
|
end
|
12
12
|
|
@@ -4,16 +4,16 @@ class G5Updatable::SyncsController < G5Updatable::BaseUpdatableController
|
|
4
4
|
|
5
5
|
def index
|
6
6
|
timestamp = @client.locations.max_updated_at
|
7
|
-
render json: {updated_at: formatted_timestamp(timestamp)}
|
7
|
+
render json: { updated_at: formatted_timestamp(timestamp) }
|
8
8
|
end
|
9
9
|
|
10
10
|
private
|
11
11
|
|
12
12
|
def set_client
|
13
13
|
@client = G5Updatable::Client.find_by_urn!(params[:urn])
|
14
|
-
end
|
14
|
+
end
|
15
15
|
|
16
16
|
def formatted_timestamp(timestamp)
|
17
17
|
timestamp.in_time_zone.strftime("%I:%M%P on %B %e, %Y") if timestamp
|
18
|
-
end
|
18
|
+
end
|
19
19
|
end
|
@@ -4,11 +4,11 @@ module G5Updatable
|
|
4
4
|
include G5Updatable::UrnAsParameter
|
5
5
|
|
6
6
|
has_many(:locations, {
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
class_name: 'G5Updatable::Location',
|
8
|
+
foreign_key: :client_urn,
|
9
|
+
primary_key: :urn,
|
10
10
|
})
|
11
11
|
|
12
|
-
validates :uid, :urn, presence: true
|
12
|
+
validates :uid, :urn, presence: true, uniqueness: true
|
13
13
|
end
|
14
14
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module G5Updatable
|
2
|
+
class HubAmenity < ActiveRecord::Base
|
3
|
+
validates :external_id, presence: true
|
4
|
+
has_many :hub_amenities_locations, foreign_key: :g5_updatable_hub_amenity_id
|
5
|
+
|
6
|
+
scope :by_client_urn, -> (client_urn) {
|
7
|
+
joins(hub_amenities_locations: { location: :client }).
|
8
|
+
where('g5_updatable_clients.urn = :client_urn', client_urn: client_urn).uniq
|
9
|
+
}
|
10
|
+
|
11
|
+
scope :by_client_urns, -> (client_urns) {
|
12
|
+
joins(hub_amenities_locations: { location: :client }).
|
13
|
+
where('g5_updatable_clients.urn IN (:client_urns)', client_urns: client_urns.join(',')).uniq
|
14
|
+
}
|
15
|
+
|
16
|
+
scope :by_client_uid, -> (client_uid) {
|
17
|
+
joins(hub_amenities_locations: :location).
|
18
|
+
where('g5_updatable_locations.client_uid = :client_uid', client_uid: client_uid).uniq
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
@@ -4,18 +4,91 @@ module G5Updatable
|
|
4
4
|
include G5Updatable::UrnAsParameter
|
5
5
|
include BelongsToClient
|
6
6
|
|
7
|
-
|
7
|
+
has_many :hub_amenities_locations, foreign_key: :g5_updatable_location_id, dependent: :destroy
|
8
|
+
has_many :hub_amenities, through: :hub_amenities_locations
|
9
|
+
|
10
|
+
validates :uid, :urn, :client_uid, :client_urn, presence: true
|
11
|
+
validates :urn, uniqueness: true
|
8
12
|
|
9
13
|
scope :by_client_uid, -> (client_uid) { where(client_uid: client_uid) }
|
14
|
+
scope :by_client_urn, -> (client_urn) { where(client_urn: client_urn) }
|
15
|
+
scope :by_postal_code, -> (postal_code) { by_property('postal_code', postal_code) }
|
16
|
+
scope :by_city, -> (city) { by_property('city', city) }
|
17
|
+
scope :by_state, -> (state) { by_property('state', state) }
|
18
|
+
scope :in_status, -> (status) { where("g5_updatable_locations.properties ->> 'status' IN (?)", status) }
|
19
|
+
scope :by_neighborhood, -> (neighborhood) {
|
20
|
+
where("g5_updatable_locations.properties ->> 'neighborhood' = :neighborhood OR g5_updatable_locations.properties ->> 'neighborhood_2' = :neighborhood", neighborhood: neighborhood)
|
21
|
+
}
|
22
|
+
scope :by_property, -> (property_name, value) { where("g5_updatable_locations.properties ->> '#{property_name}' = :#{property_name}", property_name.to_sym => value) }
|
10
23
|
scope :by_urn, -> (urn) { where(urn: urn) }
|
11
24
|
scope :max_updated_at, -> { maximum(:updated_at) }
|
25
|
+
scope :by_amenity_names, -> (*amenity_names) { # there must be a match for every amenity name (AND not OR)
|
26
|
+
results = all
|
27
|
+
[amenity_names].flatten.each do |amenity_name|
|
28
|
+
results = results.where('g5_updatable_locations.flat_amenity_names LIKE :amenity_names',
|
29
|
+
amenity_names: "%#{amenity_names_to_tokenized_string(amenity_name)}%")
|
30
|
+
end
|
31
|
+
results
|
32
|
+
}
|
33
|
+
before_validation :set_client_urn, :set_client_uid
|
34
|
+
|
35
|
+
def refresh_flat_amenity_names!
|
36
|
+
update_attributes(flat_amenity_names: self.class.amenity_names_to_tokenized_string(hub_amenities.collect(&:name)))
|
37
|
+
end
|
12
38
|
|
13
|
-
|
39
|
+
def amenity_names_array=(names_array)
|
40
|
+
self.flat_amenity_names = self.class.amenity_names_to_tokenized_string names_array
|
41
|
+
end
|
42
|
+
|
43
|
+
FLAT_DELIM = '|'
|
44
|
+
|
45
|
+
def self.amenity_names_to_tokenized_string(names_array)
|
46
|
+
return if names_array.blank?
|
47
|
+
"#{FLAT_DELIM}#{[names_array].flatten.compact.sort.join(FLAT_DELIM)}#{FLAT_DELIM}"
|
48
|
+
end
|
14
49
|
|
15
50
|
def display_name
|
16
51
|
return nil unless properties
|
17
52
|
return properties['internal_branded_name'] if properties['internal_branded_name'].present?
|
18
53
|
name
|
19
54
|
end
|
55
|
+
|
56
|
+
def neighborhoods
|
57
|
+
[properties['neighborhood'], properties['neighborhood_2']].select(&:present?)
|
58
|
+
end
|
59
|
+
|
60
|
+
def live?
|
61
|
+
status?("Live")
|
62
|
+
end
|
63
|
+
|
64
|
+
def no_deploy?
|
65
|
+
status?("No Deploy")
|
66
|
+
end
|
67
|
+
|
68
|
+
def pending?
|
69
|
+
status?("Pending")
|
70
|
+
end
|
71
|
+
|
72
|
+
def deleted?
|
73
|
+
status?("Deleted")
|
74
|
+
end
|
75
|
+
|
76
|
+
def suspended?
|
77
|
+
status?("Suspended")
|
78
|
+
end
|
79
|
+
|
80
|
+
def status?(status)
|
81
|
+
return false unless properties
|
82
|
+
match = properties['status'].to_s.strip =~ /#{status.to_s.strip}/i
|
83
|
+
!!match
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_client_urn
|
87
|
+
self.client_urn ||= self.client_uid.split('/').last if self.client_uid
|
88
|
+
end
|
89
|
+
|
90
|
+
def set_client_uid
|
91
|
+
self.client_uid||= self.client.try(:uid)
|
92
|
+
end
|
20
93
|
end
|
21
94
|
end
|
@@ -9,4 +9,12 @@ class G5Updatable::LocationSerializer < ActiveModel::Serializer
|
|
9
9
|
|
10
10
|
keys
|
11
11
|
end
|
12
|
+
|
13
|
+
def attributes(requested_attrs = nil, reload = false)
|
14
|
+
data = super requested_attrs, reload
|
15
|
+
object.properties.each do |name, value|
|
16
|
+
data[name.to_sym] = value
|
17
|
+
end
|
18
|
+
data
|
19
|
+
end
|
12
20
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CopyLatLongPropsToLatLongColumns < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
G5Updatable::Location.all.each do |location|
|
4
|
+
location.latitude = location.properties['latitude']
|
5
|
+
location.longitude = location.properties['longitude']
|
6
|
+
location.save
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def down
|
11
|
+
G5Updatable::Location.all.each do |location|
|
12
|
+
location.properties['latitude'] = location.latitude
|
13
|
+
location.proper['longitude'] = location.longitude
|
14
|
+
location.latitude = nil
|
15
|
+
location.longitude = nil
|
16
|
+
location.save
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class AddAmenities < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :g5_updatable_hub_amenities do |t|
|
4
|
+
t.integer :external_id
|
5
|
+
t.string :name
|
6
|
+
t.string :icon
|
7
|
+
t.timestamp :external_updated_at
|
8
|
+
t.timestamp :external_created_at
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
|
12
|
+
add_index :g5_updatable_hub_amenities, :external_id, unique: true
|
13
|
+
|
14
|
+
create_table :g5_updatable_hub_amenities_locations do |t|
|
15
|
+
t.belongs_to :g5_updatable_hub_amenity
|
16
|
+
t.belongs_to :g5_updatable_location
|
17
|
+
end
|
18
|
+
|
19
|
+
add_index :g5_updatable_hub_amenities_locations, :g5_updatable_hub_amenity_id, name: 'updatable_amenities_loc_amen_id'
|
20
|
+
add_index :g5_updatable_hub_amenities_locations, :g5_updatable_location_id, name: 'updatable_amenities_loc_loc_id'
|
21
|
+
|
22
|
+
# we need this for queries that require a location to have ALL amenities in a list
|
23
|
+
add_column :g5_updatable_locations, :flat_amenity_names, :string
|
24
|
+
end
|
25
|
+
end
|
data/lib/g5_updatable.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'active_model_serializers'
|
2
|
+
require 'g5_authentication_client'
|
3
|
+
require 'g5_updatable/engine'
|
4
|
+
require 'httparty'
|
4
5
|
|
5
6
|
module G5Updatable
|
7
|
+
HUB_URL = ENV.fetch('HUB_URL', 'https://g5-hub.herokuapp.com').freeze
|
6
8
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module G5Updatable
|
2
|
+
class AllClientUrnsFetcher
|
3
|
+
def self.fetch_uids
|
4
|
+
G5Updatable::Fetcher.get_with_token(url)['clients'].collect do |urn|
|
5
|
+
"#{hub_url}/clients/#{urn['urn']}.json"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.url
|
10
|
+
"#{hub_url}/urns.json"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.hub_url
|
14
|
+
G5Updatable::HUB_URL
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,37 +1,49 @@
|
|
1
1
|
class G5Updatable::ClientFeedProcessor
|
2
2
|
attr_reader :client_uid
|
3
3
|
|
4
|
-
def initialize(
|
5
|
-
@client_uid = client_uid || ENV["CLIENT_UID"]
|
4
|
+
def initialize(params)
|
5
|
+
@client_uid = params[:client_uid] || ENV["CLIENT_UID"]
|
6
6
|
raise "A client_uid must be either passed in or configured!" if @client_uid.blank?
|
7
|
+
@location_uid = params[:location_uid]
|
7
8
|
end
|
8
9
|
|
9
10
|
class << self
|
10
|
-
def load_all_clients
|
11
|
-
|
12
|
-
|
11
|
+
def load_all_clients
|
12
|
+
G5Updatable::AllClientUrnsFetcher.fetch_uids.each do |uid|
|
13
|
+
puts "Loading: #{uid}"
|
14
|
+
load_client(uid)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def load_client(client_uid)
|
19
|
+
begin
|
20
|
+
new(client_uid: client_uid).work
|
21
|
+
rescue => e
|
22
|
+
Rails.logger.error e
|
23
|
+
nil
|
24
|
+
end
|
13
25
|
end
|
14
26
|
end
|
15
27
|
|
16
28
|
def work
|
17
|
-
|
18
|
-
update_locations
|
19
|
-
|
20
|
-
client
|
29
|
+
@location_uid ? update_location : update_client
|
21
30
|
end
|
22
31
|
|
23
32
|
private
|
24
33
|
|
25
|
-
def
|
26
|
-
G5Updatable::LocationsUpdater.new(
|
34
|
+
def update_location
|
35
|
+
G5Updatable::LocationsUpdater.new(location_hash).update
|
27
36
|
end
|
28
37
|
|
29
38
|
def update_client
|
30
|
-
G5Updatable::ClientUpdater.new(
|
39
|
+
G5Updatable::ClientUpdater.new(client_hash).update
|
31
40
|
end
|
32
41
|
|
33
|
-
def
|
34
|
-
|
42
|
+
def client_hash
|
43
|
+
G5Updatable::Fetcher.get_with_token(@client_uid)['client']
|
35
44
|
end
|
36
45
|
|
46
|
+
def location_hash
|
47
|
+
G5Updatable::Fetcher.get_with_token(@location_uid)['location']
|
48
|
+
end
|
37
49
|
end
|