spatial_features 2.13.0 → 2.14.0
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/spatial_features.rb +0 -9
- data/lib/spatial_features/importers/kml.rb +16 -3
- data/lib/spatial_features/version.rb +1 -1
- metadata +2 -34
- data/lib/spatial_features/has_fusion_table_features.rb +0 -95
- data/lib/spatial_features/has_fusion_table_features/api.rb +0 -111
- data/lib/spatial_features/has_fusion_table_features/configuration.rb +0 -15
- data/lib/spatial_features/has_fusion_table_features/service.rb +0 -104
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0aa9e8be0d78cabc65695247e3000bcc2d69ce75aeffe1333b0dd5ce423eb562
|
4
|
+
data.tar.gz: 587dc7a4be41c38acd66de43864ed3b8b51f22186996fcdd2c906c01ee97102e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75293b351a8bfa078b1eac5c02a7d5dcce3e6eaa15a1779e660d0ca1c8a1cf93be2ad30190946e8934f51301c8535cfda4a75d0af2d86d051ffdd79646f170eb
|
7
|
+
data.tar.gz: a725a65315d15a5885bd475dc6575969823cac93bc865f4dca3f583e602342a7b40a1afef2478264e74f29a79d44be8fb3528648144b10fe9d4c0a3d8f5858ab
|
data/lib/spatial_features.rb
CHANGED
@@ -3,9 +3,6 @@ require 'delayed_job_active_record'
|
|
3
3
|
require 'rgeo/shapefile'
|
4
4
|
require 'nokogiri'
|
5
5
|
require 'zip'
|
6
|
-
require 'googleauth'
|
7
|
-
require 'google/apis/fusiontables_v2'
|
8
|
-
require 'google/apis/drive_v3'
|
9
6
|
|
10
7
|
# LIB
|
11
8
|
require 'spatial_features/caching'
|
@@ -20,11 +17,6 @@ require 'spatial_features/has_spatial_features'
|
|
20
17
|
require 'spatial_features/has_spatial_features/queued_spatial_processing'
|
21
18
|
require 'spatial_features/has_spatial_features/feature_import'
|
22
19
|
|
23
|
-
require 'spatial_features/has_fusion_table_features'
|
24
|
-
require 'spatial_features/has_fusion_table_features/api'
|
25
|
-
require 'spatial_features/has_fusion_table_features/configuration'
|
26
|
-
require 'spatial_features/has_fusion_table_features/service'
|
27
|
-
|
28
20
|
require 'spatial_features/importers/base'
|
29
21
|
require 'spatial_features/importers/file'
|
30
22
|
require 'spatial_features/importers/kml'
|
@@ -38,7 +30,6 @@ require 'spatial_features/engine'
|
|
38
30
|
|
39
31
|
# Load the act method
|
40
32
|
ActiveRecord::Base.send :extend, SpatialFeatures::ActMethod
|
41
|
-
ActiveRecord::Base.send :extend, SpatialFeatures::FusionTables::ActMethod
|
42
33
|
|
43
34
|
# Suppress date warnings when unzipping KMZ saved by Google Earth, see https://github.com/rubyzip/rubyzip/issues/112
|
44
35
|
Zip.warn_invalid_date = false
|
@@ -14,10 +14,14 @@ module SpatialFeatures
|
|
14
14
|
else
|
15
15
|
metadata = {}
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
next if blank_feature?(feature)
|
19
19
|
|
20
|
-
|
20
|
+
geog = geom_from_kml(feature)
|
21
|
+
|
22
|
+
next if geog.blank?
|
23
|
+
|
24
|
+
yield OpenStruct.new(:feature_type => sql_type, :geog => geog, :name => name, :metadata => metadata)
|
21
25
|
end
|
22
26
|
end
|
23
27
|
end
|
@@ -27,7 +31,16 @@ module SpatialFeatures
|
|
27
31
|
end
|
28
32
|
|
29
33
|
def geom_from_kml(kml)
|
30
|
-
|
34
|
+
geom = nil
|
35
|
+
|
36
|
+
# Do query in a new thread so we use a new connection (if the query fails it will poison the transaction of the current connection)
|
37
|
+
Thread.new do
|
38
|
+
geom = ActiveRecord::Base.connection.select_value("SELECT ST_GeomFromKML(#{ActiveRecord::Base.connection.quote(kml.to_s)})")
|
39
|
+
rescue ActiveRecord::StatementInvalid => e # Discard Invalid KML features
|
40
|
+
geom = nil
|
41
|
+
end.join
|
42
|
+
|
43
|
+
return geom
|
31
44
|
end
|
32
45
|
|
33
46
|
def extract_metadata(placemark)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spatial_features
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Wallace
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-02-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -87,34 +87,6 @@ dependencies:
|
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '1.6'
|
90
|
-
- !ruby/object:Gem::Dependency
|
91
|
-
name: googleauth
|
92
|
-
requirement: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: 0.5.1
|
97
|
-
type: :runtime
|
98
|
-
prerelease: false
|
99
|
-
version_requirements: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: 0.5.1
|
104
|
-
- !ruby/object:Gem::Dependency
|
105
|
-
name: google-api-client
|
106
|
-
requirement: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0.9'
|
111
|
-
type: :runtime
|
112
|
-
prerelease: false
|
113
|
-
version_requirements: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - "~>"
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0.9'
|
118
90
|
- !ruby/object:Gem::Dependency
|
119
91
|
name: chroma
|
120
92
|
requirement: !ruby/object:Gem::Requirement
|
@@ -180,10 +152,6 @@ files:
|
|
180
152
|
- lib/spatial_features/controller_helpers/spatial_extensions.rb
|
181
153
|
- lib/spatial_features/download.rb
|
182
154
|
- lib/spatial_features/engine.rb
|
183
|
-
- lib/spatial_features/has_fusion_table_features.rb
|
184
|
-
- lib/spatial_features/has_fusion_table_features/api.rb
|
185
|
-
- lib/spatial_features/has_fusion_table_features/configuration.rb
|
186
|
-
- lib/spatial_features/has_fusion_table_features/service.rb
|
187
155
|
- lib/spatial_features/has_spatial_features.rb
|
188
156
|
- lib/spatial_features/has_spatial_features/feature_import.rb
|
189
157
|
- lib/spatial_features/has_spatial_features/queued_spatial_processing.rb
|
@@ -1,95 +0,0 @@
|
|
1
|
-
module SpatialFeatures
|
2
|
-
module FusionTables
|
3
|
-
module ActMethod
|
4
|
-
def has_fusion_table_features(options = {})
|
5
|
-
class_attribute :fusion_table_features_options
|
6
|
-
self.fusion_table_features_options = options
|
7
|
-
|
8
|
-
after_update_features :expire_fusion_table
|
9
|
-
|
10
|
-
include InstanceMethods
|
11
|
-
extend ClassMethods
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
module ClassMethods
|
16
|
-
def to_fusion_condition
|
17
|
-
sanitize_sql(["spatial_model_id IN (?)", pluck(:id)])
|
18
|
-
end
|
19
|
-
|
20
|
-
def update_fusion_tables(group_options = {})
|
21
|
-
fusion_table_groups(group_options) do |fusion_table_id, records, group_features|
|
22
|
-
API.set_features(fusion_table_id, group_features, :colour => fusion_table_features_options[:colour])
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def delete_fusion_tables(group_options = {})
|
27
|
-
fusion_table_groups(group_options) do |fusion_table_id, records, group_features|
|
28
|
-
API.delete_table(fusion_table_id)
|
29
|
-
end
|
30
|
-
@fusion_table_id_cache = nil
|
31
|
-
end
|
32
|
-
|
33
|
-
def acts_like_fusion_table_features?
|
34
|
-
true
|
35
|
-
end
|
36
|
-
|
37
|
-
def fusion_table_id_cache
|
38
|
-
@fusion_table_id_cache ||= Hash.new {|hash, table_name| hash[table_name] = API.find_or_create_table(table_name) }
|
39
|
-
.merge(API.tables.collect {|table| [table.name, table.table_id] }.to_h) # Warm the cache
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def fusion_table_groups(only: [], except: [])
|
45
|
-
groups = all.group_by(&:fusion_table_id)
|
46
|
-
groups.select! {|fusion_table_id, _| Array.wrap(only).include?(fusion_table_id) } if only.present?
|
47
|
-
groups.select! {|fusion_table_id, _| !Array.wrap(except).include?(fusion_table_id) } if except.present?
|
48
|
-
groups.each do |fusion_table_id, records|
|
49
|
-
yield fusion_table_id, records, features.where(:spatial_model_id => records)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
module InstanceMethods
|
55
|
-
def acts_like_fusion_table_features?
|
56
|
-
true
|
57
|
-
end
|
58
|
-
|
59
|
-
def stale_fusion_table?
|
60
|
-
@stale_fusion_table
|
61
|
-
end
|
62
|
-
|
63
|
-
def expire_fusion_table
|
64
|
-
@stale_fusion_table = true
|
65
|
-
end
|
66
|
-
|
67
|
-
def update_fusion_table
|
68
|
-
self.class.update_fusion_tables(only: fusion_table_id)
|
69
|
-
end
|
70
|
-
|
71
|
-
def delete_fusion_table
|
72
|
-
self.class.delete_fusion_tables(only: fusion_table_id)
|
73
|
-
end
|
74
|
-
|
75
|
-
def fusion_table_id
|
76
|
-
self.class.fusion_table_id_cache[fusion_table_name]
|
77
|
-
end
|
78
|
-
|
79
|
-
def fusion_table_name
|
80
|
-
case fusion_table_features_options[:table_name]
|
81
|
-
when Symbol
|
82
|
-
send(fusion_table_features_options[:table_name])
|
83
|
-
when String
|
84
|
-
fusion_table_features_options[:table_name]
|
85
|
-
else
|
86
|
-
self.class.table_name
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def to_fusion_condition
|
91
|
-
self.class.where(:id => self).to_fusion_condition
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
@@ -1,111 +0,0 @@
|
|
1
|
-
module SpatialFeatures
|
2
|
-
module FusionTables
|
3
|
-
module API
|
4
|
-
extend self
|
5
|
-
|
6
|
-
FEATURE_COLUMNS = {
|
7
|
-
:name => 'STRING',
|
8
|
-
:spatial_model_type => 'STRING',
|
9
|
-
:spatial_model_id => 'NUMBER',
|
10
|
-
:kml_lowres => 'LOCATION',
|
11
|
-
:colour => 'STRING',
|
12
|
-
:metadata => 'STRING'
|
13
|
-
}
|
14
|
-
TABLE_STYLE = {
|
15
|
-
:polygon_options => { :fill_color_styler => { :kind => 'fusiontables#fromColumn', :column_name => 'colour' },
|
16
|
-
:stroke_color_styler => { :kind => 'fusiontables#fromColumn', :column_name => 'colour' },
|
17
|
-
:stroke_weight => 1
|
18
|
-
},
|
19
|
-
:polyline_options => { :stroke_color_styler => { :kind => 'fusiontables#fromColumn', :column_name => 'colour'} }
|
20
|
-
}
|
21
|
-
|
22
|
-
TABLE_TEMPLATE = {
|
23
|
-
:body => "<h3>{name}</h3>{metadata}"
|
24
|
-
}
|
25
|
-
|
26
|
-
def find_or_create_table(name)
|
27
|
-
find_table(name) || create_table(name)
|
28
|
-
end
|
29
|
-
|
30
|
-
def create_table(name)
|
31
|
-
table_id = service.create_table(name, FEATURE_COLUMNS.collect {|name, type| {:name => name, :type => type} })
|
32
|
-
service.share_table(table_id)
|
33
|
-
service.insert_style(table_id, TABLE_STYLE)
|
34
|
-
service.insert_template(table_id, TABLE_TEMPLATE)
|
35
|
-
return table_id
|
36
|
-
end
|
37
|
-
|
38
|
-
def find_table(name)
|
39
|
-
service.tables.find {|table| table.name == name }.try(:table_id)
|
40
|
-
end
|
41
|
-
|
42
|
-
def delete_table(table_id)
|
43
|
-
service.delete_table(table_id)
|
44
|
-
end
|
45
|
-
|
46
|
-
def tables
|
47
|
-
service.tables
|
48
|
-
end
|
49
|
-
|
50
|
-
def set_features(table_id, features, colour: nil)
|
51
|
-
service.replace_rows(table_id, features_to_csv(features, colour))
|
52
|
-
end
|
53
|
-
|
54
|
-
def set_style(table_id, style)
|
55
|
-
service.style_ids(table_id).each do |style_id|
|
56
|
-
service.delete_style(table_id, style_id)
|
57
|
-
end
|
58
|
-
service.insert_style(table_id, style)
|
59
|
-
end
|
60
|
-
|
61
|
-
def service
|
62
|
-
@service ||= Service.new(Configuration.service_account_credentials)
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def features_to_csv(features, colour)
|
68
|
-
ActiveRecord::Associations::Preloader.new.preload(features, :spatial_model) if colour.is_a?(Symbol)
|
69
|
-
|
70
|
-
csv = CSV.generate do |csv|
|
71
|
-
features.each do |feature|
|
72
|
-
csv << FEATURE_COLUMNS.keys.collect do |attribute|
|
73
|
-
case attribute
|
74
|
-
when :colour
|
75
|
-
render_feature_colour(feature, colour)
|
76
|
-
when :metadata
|
77
|
-
render_feature_metadata(feature)
|
78
|
-
else
|
79
|
-
feature.send(attribute)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
file = Tempfile.new('features')
|
86
|
-
file.write(csv)
|
87
|
-
return file
|
88
|
-
end
|
89
|
-
|
90
|
-
def render_feature_metadata(feature)
|
91
|
-
feature.metadata.collect do |name, val|
|
92
|
-
"<b>#{name}:</b> #{val}"
|
93
|
-
end.join('<br/>')
|
94
|
-
end
|
95
|
-
|
96
|
-
def render_feature_colour(feature, colour)
|
97
|
-
case colour
|
98
|
-
when Symbol
|
99
|
-
feature.spatial_model.send(colour)
|
100
|
-
when Proc
|
101
|
-
colour.call(feature)
|
102
|
-
else
|
103
|
-
colour
|
104
|
-
end.paint.to_ft_hex
|
105
|
-
|
106
|
-
rescue Chroma::Errors::UnrecognizedColor
|
107
|
-
nil
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
@@ -1,104 +0,0 @@
|
|
1
|
-
module SpatialFeatures
|
2
|
-
module FusionTables
|
3
|
-
class Service
|
4
|
-
APPLICATION_NAME = 'Fusion Tables + Spatial Features'
|
5
|
-
GOOGLE_AUTH_SCOPES = %w(https://www.googleapis.com/auth/fusiontables https://www.googleapis.com/auth/drive)
|
6
|
-
|
7
|
-
def initialize(service_account_credentials_path)
|
8
|
-
@authorization = get_authorization(service_account_credentials_path, GOOGLE_AUTH_SCOPES)
|
9
|
-
end
|
10
|
-
|
11
|
-
def table_ids
|
12
|
-
tables.collect(&:table_id)
|
13
|
-
end
|
14
|
-
|
15
|
-
def tables
|
16
|
-
fusion_tables_service.list_tables(max_results: 10000).items || []
|
17
|
-
end
|
18
|
-
|
19
|
-
def create_table(name, columns = [], table_options = {})
|
20
|
-
table_object = {:name => name, :columns => columns, :is_exportable => true}.merge(table_options)
|
21
|
-
fusion_tables_service.insert_table(table_object, :fields => 'table_id').table_id
|
22
|
-
end
|
23
|
-
|
24
|
-
def delete_table(table_id)
|
25
|
-
fusion_tables_service.delete_table(table_id)
|
26
|
-
end
|
27
|
-
|
28
|
-
def style_ids(table_id)
|
29
|
-
styles(table_id).collect(&:style_id)
|
30
|
-
end
|
31
|
-
|
32
|
-
def styles(table_id)
|
33
|
-
fusion_tables_service.list_styles(table_id).items
|
34
|
-
end
|
35
|
-
|
36
|
-
def delete_style(table_id, style_id)
|
37
|
-
fusion_tables_service.delete_style(table_id, style_id, :fields => nil)
|
38
|
-
end
|
39
|
-
|
40
|
-
def insert_style(table_id, style)
|
41
|
-
style.reverse_merge! 'name' => 'default_table_style', 'isDefaultForTable' => true
|
42
|
-
fusion_tables_service.insert_style(table_id, style, :fields => 'styleId')
|
43
|
-
end
|
44
|
-
|
45
|
-
def delete_template(table_id, template_id)
|
46
|
-
fusion_tables_service.delete_template(table_id, template_id, :fields => nil)
|
47
|
-
end
|
48
|
-
|
49
|
-
def insert_template(table_id, template)
|
50
|
-
template.reverse_merge! 'name' => 'default_table_template'
|
51
|
-
fusion_tables_service.insert_template(table_id, template, :fields => 'templateId')
|
52
|
-
end
|
53
|
-
|
54
|
-
def delete_row(table_id, row_id)
|
55
|
-
fusion_tables_service.sql_query("DELETE FROM #{table_id} WHERE ROWID = #{row_id}")
|
56
|
-
end
|
57
|
-
|
58
|
-
def row_ids(table_id, conditions = {})
|
59
|
-
clause = conditions.collect {|column, value| ActiveRecord::Base.send(:sanitize_sql_array, ["? IN (?)", column, value]) }.join(' AND ')
|
60
|
-
where = "WHERE #{clause}" if clause.present?
|
61
|
-
return fusion_tables_service.sql_query_get("SELECT rowid FROM #{table_id} #{where}}").rows.flatten
|
62
|
-
end
|
63
|
-
|
64
|
-
# Process mutliple commands in a single HTTP request
|
65
|
-
def bulk(&block)
|
66
|
-
fusion_tables_service.batch do
|
67
|
-
block.call(self)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def replace_rows(table_id, csv)
|
72
|
-
fusion_tables_service.replace_table_rows(table_id, :upload_source => csv, :options => {:open_timeout_sec => 1.hour})
|
73
|
-
end
|
74
|
-
|
75
|
-
def upload_rows(table_id, csv)
|
76
|
-
fusion_tables_service.import_rows(table_id, :upload_source => csv, :options => {:open_timeout_sec => 1.hour})
|
77
|
-
end
|
78
|
-
|
79
|
-
def share_table(table_id)
|
80
|
-
permission = {:type => 'anyone', :role => 'reader', :withLink => true}
|
81
|
-
drive_service.create_permission(table_id, permission, :fields => 'id')
|
82
|
-
end
|
83
|
-
|
84
|
-
def fusion_tables_service
|
85
|
-
@fusion_tables_service ||= Google::Apis::FusiontablesV2::FusiontablesService.new.tap do |service|
|
86
|
-
service.client_options.application_name = APPLICATION_NAME
|
87
|
-
service.authorization = @authorization
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def drive_service
|
92
|
-
@drive_service ||= Google::Apis::DriveV3::DriveService.new.tap do |drive|
|
93
|
-
drive.client_options.application_name = APPLICATION_NAME
|
94
|
-
drive.authorization = @authorization
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def get_authorization(service_account_credentials_path, scopes)
|
99
|
-
ENV['GOOGLE_APPLICATION_CREDENTIALS'] = service_account_credentials_path
|
100
|
-
return Google::Auth.get_application_default(scopes)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|