We're reworking the format validation to correctly interpret feature collection, feature, and geometry, according to RFC 7946 [1]. Since Leaflet interprets GeoJSON format, we're rendering the GeoJSON as a layer instead of as a set of points. For that, we're normalizing the GeoJSON to make sure it contains either a Feature or a FeatureCollection. We're also adding the Leaflet images to the assets path so the markers used for point geometries are rendered correctly. Note we no longer allow a GeoJSON containing a geometry but not a defined type. Since there might be invalid GeoJSON in existing Consul Democracy databases, we're normalizing these existing geometry objects to be part of a feature object. We're also wrapping the outline points in a FeatureCollection object because most of the large GIS systems eg ArcGIS, QGIS export geojson as a complete FeatureCollection. [1] https://datatracker.ietf.org/doc/html/rfc7946 Co-authored-by: Javi Martín <javim@elretirao.net>
61 lines
1.4 KiB
Ruby
61 lines
1.4 KiB
Ruby
class Geozone < ApplicationRecord
|
|
include Graphqlable
|
|
|
|
has_many :proposals
|
|
has_many :debates
|
|
has_many :users
|
|
has_many :headings, class_name: "Budget::Heading", dependent: :nullify
|
|
validates :name, presence: true
|
|
validates :geojson, geojson_format: true
|
|
|
|
scope :public_for_api, -> { all }
|
|
|
|
def self.names
|
|
Geozone.pluck(:name)
|
|
end
|
|
|
|
def safe_to_destroy?
|
|
Geozone.reflect_on_all_associations(:has_many).all? do |association|
|
|
association.klass.where(geozone: self).empty?
|
|
end
|
|
end
|
|
|
|
def outline_points
|
|
normalized_geojson&.to_json
|
|
end
|
|
|
|
private
|
|
|
|
def normalized_geojson
|
|
if geojson.present?
|
|
parsed_geojson = JSON.parse(geojson)
|
|
|
|
if parsed_geojson["type"] == "FeatureCollection"
|
|
parsed_geojson
|
|
elsif parsed_geojson["type"] == "Feature"
|
|
wrap_in_feature_collection(parsed_geojson)
|
|
elsif parsed_geojson["geometry"]
|
|
wrap_in_feature_collection(wrap_in_feature(parsed_geojson["geometry"]))
|
|
elsif parsed_geojson["type"] && parsed_geojson["coordinates"]
|
|
wrap_in_feature_collection(wrap_in_feature(parsed_geojson))
|
|
else
|
|
raise ArgumentError, "Invalid GeoJSON fragment"
|
|
end
|
|
end
|
|
end
|
|
|
|
def wrap_in_feature(geometry)
|
|
{
|
|
type: "Feature",
|
|
geometry: geometry
|
|
}
|
|
end
|
|
|
|
def wrap_in_feature_collection(feature)
|
|
{
|
|
type: "FeatureCollection",
|
|
features: [feature]
|
|
}
|
|
end
|
|
end
|