g5_updatable 0.10.3 → 0.20.3.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|