diff --git a/app/jobs/export_job.rb b/app/jobs/export_job.rb index 6f65a25b..e2ff3d26 100644 --- a/app/jobs/export_job.rb +++ b/app/jobs/export_job.rb @@ -3,7 +3,7 @@ class ExportJob < ApplicationJob queue_as :exports - def perform(export_id, start_at, end_at, format: :json) + def perform(export_id, start_at, end_at, format: :geojson) export = Export.find(export_id) Exports::Create.new(export:, start_at:, end_at:, format:).call diff --git a/app/serializers/point_serializer.rb b/app/serializers/point_serializer.rb new file mode 100644 index 00000000..4bbd7ad0 --- /dev/null +++ b/app/serializers/point_serializer.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class PointSerializer + EXCLUDED_ATTRIBUTES = %w[created_at updated_at visit_id id import_id user_id].freeze + + def initialize(point) + @point = point + end + + def call + point.attributes.except(*EXCLUDED_ATTRIBUTES) + end + + private + + attr_reader :point +end diff --git a/app/serializers/points/geojson_serializer.rb b/app/serializers/points/geojson_serializer.rb new file mode 100644 index 00000000..40c1048f --- /dev/null +++ b/app/serializers/points/geojson_serializer.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class Points::GeojsonSerializer + def initialize(points) + @points = points + end + + # rubocop:disable Metrics/MethodLength + def call + { + type: 'FeatureCollection', + features: points.map do |point| + { + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [point.longitude, point.latitude] + }, + properties: PointSerializer.new(point).call + } + end + }.to_json + end + # rubocop:enable Metrics/MethodLength + + private + + attr_reader :points +end diff --git a/app/services/exports/create.rb b/app/services/exports/create.rb index b8c1e333..19c6d7a3 100644 --- a/app/services/exports/create.rb +++ b/app/services/exports/create.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Exports::Create - def initialize(export:, start_at:, end_at:, format: :json) + def initialize(export:, start_at:, end_at:, format: :geojson) @export = export @user = export.user @start_at = start_at.to_datetime @@ -18,7 +18,13 @@ class Exports::Create Rails.logger.debug "====Exporting #{points.size} points" - data = ::ExportSerializer.new(points, user.email).call + data = + case format + when :geojson then process_geojson_export(points) + when :gpx then process_gpx_export(points) + else raise ArgumentError, "Unsupported format: #{format}" + end + file_path = Rails.root.join('public', 'exports', "#{export.name}.#{format}") File.open(file_path, 'w') { |file| file.write(data) } @@ -62,7 +68,8 @@ class Exports::Create ).call end - def process_json_export(points) + def process_geojson_export(points) + Points::GeojsonSerializer.new(points).call end def process_gpx_export(points) diff --git a/app/views/points/index.html.erb b/app/views/points/index.html.erb index 8df019f9..06707058 100644 --- a/app/views/points/index.html.erb +++ b/app/views/points/index.html.erb @@ -22,7 +22,7 @@
- <%= link_to 'Export points', exports_path(start_at: @start_at, end_at: @end_at), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure? This will start background process of exporting points withing timeframe, selected between #{@start_at} and #{@end_at}", turbo_method: :post }, class: "px-4 py-2 bg-green-500 text-white rounded-md join-item" %> + <%= link_to 'Export GeoJSON', exports_path(start_at: @start_at, end_at: @end_at, file_format: :geojson), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure? This will start background process of exporting points withing timeframe, selected between #{@start_at} and #{@end_at}", turbo_method: :post }, class: "px-4 py-2 bg-green-500 text-white rounded-md join-item" %>
<%#
%>