spatial_features 2.19.1 → 2.20.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36eed2c1325bed9be0605ee197dfe74770fd86e2a0e0c032e73937db73519ebc
4
- data.tar.gz: dc7959b2ed3f6ca983c0dc22c50842bdbf78b73ab47ec8279a8101f0f850f99b
3
+ metadata.gz: 639dee46fedd2cf507642b41119ff99e93506b54d891ab42d21a1f24fcf5a679
4
+ data.tar.gz: 956175227c6a59acc867810a51796303218eac70c9bc49fe0d0f8222ea8558e6
5
5
  SHA512:
6
- metadata.gz: cf5986e2b8473f571c7faef6044a34b14171779ad46724b3d38916570ca47dff17e57e0ea5ee6d8ae599032ae197ef7177b7113d77911495dc87413570ba630a
7
- data.tar.gz: 95dbc3d2c8c8dc2535930304823f91746ef293091b70ff9c530fcebdeff65ca8dabca66db78ce6bf68919f4cb5d1afb0b3db8e3ee414130e600b956a285a6a1e
6
+ metadata.gz: 6a1ac7a0dca15400e0e03f0f1c2192e22a4c1e818edde2a832f925e6ee803a9284c5236684228e25dbeabf2d147aacef4f4c05170216b0857941c87ed9b9a395
7
+ data.tar.gz: da6fc8be7449202dfe46de18f0829e49664626ba17b90b6e3c1eae7a059f38a10d8310046e4f2bf44fb80bf78f2cdeea26624f429fc0d7b5873775b332086712
data/README.md CHANGED
@@ -109,8 +109,17 @@ Person.new(:features => [Feature.new(:geog => 'some binary PostGIS Geography str
109
109
  You can specify multiple import sources for geometry. Each key is a method that returns the data for the Importer, and
110
110
  each value is the Importer to use to parse the data. See each Importer for more details.
111
111
  ```ruby
112
+ def ImageImporter
113
+ def self.call(feature, image_paths)
114
+ image_paths.each do |pathname|
115
+ # ...
116
+ end
117
+ end
118
+ end
119
+
112
120
  class Location < ActiveRecord::Base
113
- has_spatial_features :import => { :remote_kml_url => 'KMLFile', :file => 'File', :geojson => 'GeoJSON' }
121
+ has_spatial_features :import => { :remote_kml_url => 'KMLFile', :file => 'File', :geojson => 'GeoJSON' },
122
+ :image_handlers => ['ImageImporter']
114
123
 
115
124
  def remote_kml_url
116
125
  "www.test.com/kml/#{id}.kml"
@@ -15,6 +15,8 @@ class Feature < AbstractFeature
15
15
 
16
16
  after_save :refresh_aggregate, if: :automatically_refresh_aggregate?
17
17
 
18
+ attr_accessor :importable_image_paths # :nodoc:
19
+
18
20
  # Features are used for display so we also cache their KML representation
19
21
  def self.cache_derivatives(options = {})
20
22
  super
@@ -8,7 +8,7 @@ module SpatialFeatures
8
8
  included do
9
9
  extend ActiveModel::Callbacks
10
10
  define_model_callbacks :update_features
11
- spatial_features_options.reverse_merge!(:import => {}, spatial_cache: [])
11
+ spatial_features_options.reverse_merge!(:import => {}, :spatial_cache => [], :image_handlers => [])
12
12
  end
13
13
 
14
14
  module ClassMethods
@@ -78,13 +78,30 @@ module SpatialFeatures
78
78
  "SpatialFeatures::Importers::#{importer_name}".constantize
79
79
  end
80
80
 
81
+ def handle_images(feature)
82
+ return if feature.importable_image_paths.nil? || feature.importable_image_paths.empty?
83
+
84
+ Array(spatial_features_options[:image_handlers]).each do |image_handler|
85
+ image_handler_from_name(image_handler).call(feature, feature.importable_image_paths)
86
+ end
87
+ end
88
+
89
+ def image_handler_from_name(handler_name)
90
+ handler_name.to_s.constantize
91
+ end
92
+
81
93
  def import_features(imports, skip_invalid)
82
94
  features.delete_all
83
95
  valid, invalid = Feature.defer_aggregate_refresh do
84
96
  Feature.without_caching_derivatives do
85
97
  imports.flat_map(&:features).partition do |feature|
86
98
  feature.spatial_model = self
87
- feature.save
99
+ if feature.save
100
+ handle_images(feature)
101
+ true
102
+ else
103
+ false
104
+ end
88
105
  end
89
106
  end
90
107
  end
@@ -46,7 +46,8 @@ module SpatialFeatures
46
46
  end
47
47
 
48
48
  def build_feature(record)
49
- Feature.new(:name => record.name, :metadata => record.metadata, :feature_type => record.feature_type, :geog => record.geog, :make_valid => @make_valid)
49
+ importable_image_paths = record.importable_image_paths if record.respond_to?(:importable_image_paths)
50
+ Feature.new(:name => record.name, :metadata => record.metadata, :feature_type => record.feature_type, :geog => record.geog, :importable_image_paths => importable_image_paths, :make_valid => @make_valid)
50
51
  end
51
52
  end
52
53
  end
@@ -3,6 +3,14 @@ require 'ostruct'
3
3
  module SpatialFeatures
4
4
  module Importers
5
5
  class KML < Base
6
+ # <SimpleData name> keys that may contain <img> tags
7
+ IMAGE_METADATA_KEYS = %w[pdfmaps_photos].freeze
8
+
9
+ def initialize(data, base_dir: nil, **args)
10
+ @base_dir = base_dir
11
+ super data, **args
12
+ end
13
+
6
14
  private
7
15
 
8
16
  def each_record(&block)
@@ -18,10 +26,11 @@ module SpatialFeatures
18
26
  next if blank_feature?(feature)
19
27
 
20
28
  geog = geom_from_kml(feature)
21
-
22
29
  next if geog.blank?
23
30
 
24
- yield OpenStruct.new(:feature_type => sql_type, :geog => geog, :name => name, :metadata => metadata)
31
+ importable_image_paths = images_from_metadata(metadata)
32
+
33
+ yield OpenStruct.new(:feature_type => sql_type, :geog => geog, :name => name, :metadata => metadata, :importable_image_paths => importable_image_paths)
25
34
  end
26
35
  end
27
36
  end
@@ -32,17 +41,35 @@ module SpatialFeatures
32
41
 
33
42
  def geom_from_kml(kml)
34
43
  geom = nil
44
+ conn = nil
35
45
 
36
46
  # 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)
47
+ #
48
+ # We manually checkout a new connection since Rails re-uses DB connections across threads.
37
49
  Thread.new do
38
- geom = SpatialFeatures::Utils.select_db_value("SELECT ST_GeomFromKML(#{ActiveRecord::Base.connection.quote(kml.to_s)})")
50
+ conn = ActiveRecord::Base.connection_pool.checkout
51
+ geom = conn.select_value("SELECT ST_GeomFromKML(#{conn.quote(kml.to_s)})")
39
52
  rescue ActiveRecord::StatementInvalid => e # Discard Invalid KML features
40
53
  geom = nil
54
+ ensure
55
+ ActiveRecord::Base.connection_pool.checkin(conn) if conn
41
56
  end.join
42
57
 
43
58
  return geom
44
59
  end
45
60
 
61
+ def images_from_metadata(metadata)
62
+ IMAGE_METADATA_KEYS.flat_map do |key|
63
+ images = metadata.delete(key)
64
+ next unless images
65
+
66
+ Nokogiri::HTML.fragment(images).css("img").map do |img|
67
+ next unless (src = img["src"])
68
+ @base_dir.join(src.downcase)
69
+ end
70
+ end.compact
71
+ end
72
+
46
73
  def extract_metadata(placemark)
47
74
  metadata = {}
48
75
  metadata.merge! extract_table(placemark)
@@ -1,13 +1,17 @@
1
1
  module SpatialFeatures
2
2
  module Importers
3
3
  class KMLFile < KML
4
- def initialize(path_or_url, *args)
5
- super Download.read(path_or_url, unzip: '.kml'), *args
6
-
4
+ def initialize(path_or_url, **options)
5
+ path = Download.open_each(path_or_url, unzip: [/\.kml$/], downcase: true).first
6
+ super ::File.read(path), base_dir: Pathname.new(path).dirname, **options
7
7
  rescue SocketError, Errno::ECONNREFUSED, OpenURI::HTTPError
8
8
  url = URI(path_or_url)
9
9
  raise ImportError, "KML server is not responding. Ensure server is running and accessible at #{[url.scheme, "//#{url.host}", url.port].select(&:present?).join(':')}."
10
10
  end
11
+
12
+ def cache_key
13
+ @cache_key ||= Digest::MD5.hexdigest(@data)
14
+ end
11
15
  end
12
16
  end
13
17
  end
@@ -1,3 +1,3 @@
1
1
  module SpatialFeatures
2
- VERSION = "2.19.1"
2
+ VERSION = "2.20.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.19.1
4
+ version: 2.20.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: 2021-12-12 00:00:00.000000000 Z
12
+ date: 2021-12-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -175,8 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
175
  - !ruby/object:Gem::Version
176
176
  version: '0'
177
177
  requirements: []
178
- rubyforge_project:
179
- rubygems_version: 2.7.6.3
178
+ rubygems_version: 3.0.3
180
179
  signing_key:
181
180
  specification_version: 4
182
181
  summary: Adds spatial methods to a model.