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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88c320989e3fc2fa794540eceda94ca135c83992bdb8d95beae96cb23547253b
4
- data.tar.gz: '08acd270a048acc72c637876d36f7d4d39b4270f47f02f8cd51d80a834348c07'
3
+ metadata.gz: 0aa9e8be0d78cabc65695247e3000bcc2d69ce75aeffe1333b0dd5ce423eb562
4
+ data.tar.gz: 587dc7a4be41c38acd66de43864ed3b8b51f22186996fcdd2c906c01ee97102e
5
5
  SHA512:
6
- metadata.gz: 4597a17999f3503d80ae00d40072c9335a9a0141fc277f952328a868b3d339cdcc236929b2bdc914f42eafe1229cde317202eb7064cab956d467257747d44152
7
- data.tar.gz: e859fc1b6fb70a1f2ad453d5e8017799f2d7b6c9212fd04f8abaf3c4c7958e7383ebd71b23fd51accb9f5ed168955afcfa49ae20b5d0486b44f0580a907a2586
6
+ metadata.gz: 75293b351a8bfa078b1eac5c02a7d5dcce3e6eaa15a1779e660d0ca1c8a1cf93be2ad30190946e8934f51301c8535cfda4a75d0af2d86d051ffdd79646f170eb
7
+ data.tar.gz: a725a65315d15a5885bd475dc6575969823cac93bc865f4dca3f583e602342a7b40a1afef2478264e74f29a79d44be8fb3528648144b10fe9d4c0a3d8f5858ab
@@ -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
- yield OpenStruct.new(:feature_type => sql_type, :geog => geom_from_kml(feature), :name => name, :metadata => metadata)
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
- ActiveRecord::Base.connection.select_value("SELECT ST_GeomFromKML(#{ActiveRecord::Base.connection.quote(kml.to_s)})")
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)
@@ -1,3 +1,3 @@
1
1
  module SpatialFeatures
2
- VERSION = "2.13.0"
2
+ VERSION = "2.14.0"
3
3
  end
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.13.0
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: 2020-09-08 00:00:00.000000000 Z
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,15 +0,0 @@
1
- module SpatialFeatures
2
- module FusionTables
3
- def self.config
4
- if block_given?
5
- yield Configuration
6
- else
7
- Configuration
8
- end
9
- end
10
-
11
- module Configuration
12
- mattr_accessor :service_account_credentials
13
- end
14
- end
15
- 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