spatial_features 2.19.1 → 2.20.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: 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.