diff --git a/app/controllers/api/v1/maps/hexagons_controller.rb b/app/controllers/api/v1/maps/hexagons_controller.rb index 0e0d19a5..95c6e06a 100644 --- a/app/controllers/api/v1/maps/hexagons_controller.rb +++ b/app/controllers/api/v1/maps/hexagons_controller.rb @@ -4,21 +4,21 @@ class Api::V1::Maps::HexagonsController < ApiController skip_before_action :authenticate_api_key, if: :public_sharing_request? def index - return unless public_sharing_request? || validate_required_parameters - - result = Maps::HexagonRequestHandler.call( + result = Maps::HexagonRequestHandler.new( params: params, current_api_user: current_api_user - ) + ).call render json: result + rescue ActionController::ParameterMissing => e + render json: { error: "Missing required parameter: #{e.param}" }, status: :bad_request + rescue ActionController::BadRequest => e + render json: { error: e.message }, status: :bad_request rescue Maps::HexagonContextResolver::SharedStatsNotFoundError => e render json: { error: e.message }, status: :not_found rescue Maps::DateParameterCoercer::InvalidDateFormatError => e render json: { error: e.message }, status: :bad_request - rescue Maps::H3HexagonCenters::TooManyHexagonsError, - Maps::H3HexagonCenters::InvalidCoordinatesError, - Maps::H3HexagonCenters::PostGISError => e + rescue Maps::H3HexagonCenters::PostGISError => e render json: { error: e.message }, status: :bad_request rescue StandardError => _e handle_service_error @@ -56,10 +56,6 @@ class Api::V1::Maps::HexagonsController < ApiController private - def hexagon_params - params.permit(:uuid, :start_date, :end_date) - end - def handle_service_error render json: { error: 'Failed to generate hexagon grid' }, status: :internal_server_error end @@ -67,39 +63,4 @@ class Api::V1::Maps::HexagonsController < ApiController def public_sharing_request? params[:uuid].present? end - - def validate_required_parameters - required_params = %i[min_lon max_lon min_lat max_lat start_date end_date] - missing_params = required_params.select { |param| params[param].blank? } - - unless missing_params.empty? - error_message = "Missing required parameters: #{missing_params.join(', ')}" - render json: { error: error_message }, status: :bad_request - return false - end - - # Validate coordinate ranges - unless valid_coordinate_ranges? - render json: { error: 'Invalid coordinate ranges' }, status: :bad_request - return false - end - - true - end - - def valid_coordinate_ranges? - min_lon = params[:min_lon].to_f - max_lon = params[:max_lon].to_f - min_lat = params[:min_lat].to_f - max_lat = params[:max_lat].to_f - - # Check longitude range (-180 to 180) - return false unless (-180..180).cover?(min_lon) && (-180..180).cover?(max_lon) - # Check latitude range (-90 to 90) - return false unless (-90..90).cover?(min_lat) && (-90..90).cover?(max_lat) - # Check that min values are less than max values - return false unless min_lon < max_lon && min_lat < max_lat - - true - end end diff --git a/app/services/maps/bounds_calculator.rb b/app/services/maps/bounds_calculator.rb index aba1e251..694fc51c 100644 --- a/app/services/maps/bounds_calculator.rb +++ b/app/services/maps/bounds_calculator.rb @@ -4,10 +4,9 @@ module Maps class BoundsCalculator class NoUserFoundError < StandardError; end class NoDateRangeError < StandardError; end - class NoDataFoundError < StandardError; end - def initialize(target_user:, start_date:, end_date:) - @target_user = target_user + def initialize(user:, start_date:, end_date:) + @user = user @start_date = start_date @end_date = end_date end @@ -18,7 +17,7 @@ module Maps start_timestamp = Maps::DateParameterCoercer.new(@start_date).call end_timestamp = Maps::DateParameterCoercer.new(@end_date).call - points_relation = @target_user.points.where(timestamp: start_timestamp..end_timestamp) + points_relation = @user.points.where(timestamp: start_timestamp..end_timestamp) point_count = points_relation.count return build_no_data_response if point_count.zero? @@ -30,7 +29,7 @@ module Maps private def validate_inputs! - raise NoUserFoundError, 'No user found' unless @target_user + raise NoUserFoundError, 'No user found' unless @user raise NoDateRangeError, 'No date range specified' unless @start_date && @end_date end @@ -42,7 +41,7 @@ module Maps WHERE user_id = $1 AND timestamp BETWEEN $2 AND $3", 'bounds_query', - [@target_user.id, start_timestamp, end_timestamp] + [@user.id, start_timestamp, end_timestamp] ).first end diff --git a/app/services/maps/h3_hexagon_centers.rb b/app/services/maps/h3_hexagon_centers.rb index a6a526ac..c9167da5 100644 --- a/app/services/maps/h3_hexagon_centers.rb +++ b/app/services/maps/h3_hexagon_centers.rb @@ -7,15 +7,10 @@ class Maps::H3HexagonCenters DEFAULT_H3_RESOLUTION = 8 # Small hexagons for good detail MAX_HEXAGONS = 10_000 # Maximum number of hexagons to prevent memory issues - # Validation error classes - class TooManyHexagonsError < StandardError; end - class InvalidCoordinatesError < StandardError; end class PostGISError < StandardError; end attr_reader :user_id, :start_date, :end_date, :h3_resolution - validates :user_id, presence: true - def initialize(user_id:, start_date:, end_date:, h3_resolution: DEFAULT_H3_RESOLUTION) @user_id = user_id @start_date = start_date @@ -24,8 +19,6 @@ class Maps::H3HexagonCenters end def call - validate! - points = fetch_user_points return [] if points.empty? @@ -104,10 +97,4 @@ class Maps::H3HexagonCenters service.call end - - def validate! - return if valid? - - raise InvalidCoordinatesError, errors.full_messages.join(', ') - end end diff --git a/app/services/maps/hexagon_center_manager.rb b/app/services/maps/hexagon_center_manager.rb index d786137a..f23ced63 100644 --- a/app/services/maps/hexagon_center_manager.rb +++ b/app/services/maps/hexagon_center_manager.rb @@ -96,7 +96,6 @@ module Maps def build_hexagon_properties(index, earliest, latest) { 'hex_id' => index + 1, - 'hex_size' => 1000, 'earliest_point' => earliest ? Time.zone.at(earliest).iso8601 : nil, 'latest_point' => latest ? Time.zone.at(latest).iso8601 : nil } @@ -107,7 +106,6 @@ module Maps 'type' => 'FeatureCollection', 'features' => hexagon_features, 'metadata' => { - 'hex_size_m' => 1000, 'count' => hexagon_features.count, 'user_id' => target_user.id, 'pre_calculated' => true diff --git a/app/services/maps/hexagon_request_handler.rb b/app/services/maps/hexagon_request_handler.rb index d6f27999..e71f8d01 100644 --- a/app/services/maps/hexagon_request_handler.rb +++ b/app/services/maps/hexagon_request_handler.rb @@ -2,13 +2,9 @@ module Maps class HexagonRequestHandler - def self.call(params:, current_api_user: nil) - new(params: params, current_api_user: current_api_user).call - end - - def initialize(params:, current_api_user: nil) + def initialize(params:, user: nil) @params = params - @current_api_user = current_api_user + @user = user end def call @@ -34,16 +30,15 @@ module Maps private - attr_reader :params, :current_api_user + attr_reader :params, :user def resolve_context Maps::HexagonContextResolver.call( params: params, - current_api_user: current_api_user + user: user ) end - def find_matching_stat(context) return unless context[:target_user] && context[:start_date] diff --git a/app/services/stats/calculate_month.rb b/app/services/stats/calculate_month.rb index effddff2..9db28917 100644 --- a/app/services/stats/calculate_month.rb +++ b/app/services/stats/calculate_month.rb @@ -103,9 +103,7 @@ class Stats::CalculateMonth Rails.logger.info "Pre-calculated #{result.size} H3 hexagon centers for user #{user.id}, #{year}-#{month}" result - rescue Maps::H3HexagonCenters::TooManyHexagonsError, - Maps::H3HexagonCenters::InvalidCoordinatesError, - Maps::H3HexagonCenters::PostGISError => e + rescue Maps::H3HexagonCenters::PostGISError => e Rails.logger.warn "H3 hexagon centers calculation failed for user #{user.id}, #{year}-#{month}: #{e.message}" nil end diff --git a/spec/requests/api/v1/maps/hexagons_spec.rb b/spec/requests/api/v1/maps/hexagons_spec.rb index e377b27a..a755a9cb 100644 --- a/spec/requests/api/v1/maps/hexagons_spec.rb +++ b/spec/requests/api/v1/maps/hexagons_spec.rb @@ -17,7 +17,6 @@ RSpec.describe 'Api::V1::Maps::Hexagons', type: :request do min_lat: 40.6, max_lon: -73.9, max_lat: 40.8, - hex_size: 1000, start_date: '2024-06-01T00:00:00Z', end_date: '2024-06-30T23:59:59Z' } @@ -57,7 +56,7 @@ RSpec.describe 'Api::V1::Maps::Hexagons', type: :request do expect(response).to have_http_status(:bad_request) json_response = JSON.parse(response.body) - expect(json_response['error']).to include('Missing required parameters') + expect(json_response['error']).to include('Missing required parameter') expect(json_response['error']).to include('min_lon') end @@ -69,15 +68,6 @@ RSpec.describe 'Api::V1::Maps::Hexagons', type: :request do expect(response).to have_http_status(:bad_request) end - it 'uses custom hex_size when provided' do - custom_params = valid_params.merge(hex_size: 500) - - get '/api/v1/maps/hexagons', params: custom_params, headers: headers - - expect(response).to have_http_status(:success) - end - - context 'with no data points' do let(:empty_user) { create(:user) } let(:empty_headers) { { 'Authorization' => "Bearer #{empty_user.api_key}" } } @@ -233,7 +223,6 @@ RSpec.describe 'Api::V1::Maps::Hexagons', type: :request do # Verify properties include timestamp data expect(feature['properties']['earliest_point']).to be_present expect(feature['properties']['latest_point']).to be_present - expect(feature['properties']['hex_size']).to eq(1000) end it 'generates proper hexagon polygons from centers' do diff --git a/spec/services/maps/hexagon_center_manager_spec.rb b/spec/services/maps/hexagon_center_manager_spec.rb index cb6733d2..8ddee03c 100644 --- a/spec/services/maps/hexagon_center_manager_spec.rb +++ b/spec/services/maps/hexagon_center_manager_spec.rb @@ -48,7 +48,6 @@ RSpec.describe Maps::HexagonCenterManager do properties = feature['properties'] expect(properties['hex_id']).to eq(index + 1) - expect(properties['hex_size']).to eq(1000) expect(properties['earliest_point']).to be_present expect(properties['latest_point']).to be_present end @@ -126,4 +125,4 @@ RSpec.describe Maps::HexagonCenterManager do end end end -end \ No newline at end of file +end diff --git a/spec/services/maps/hexagon_request_handler_spec.rb b/spec/services/maps/hexagon_request_handler_spec.rb index 7cef2727..1bc0cb70 100644 --- a/spec/services/maps/hexagon_request_handler_spec.rb +++ b/spec/services/maps/hexagon_request_handler_spec.rb @@ -5,10 +5,10 @@ require 'rails_helper' RSpec.describe Maps::HexagonRequestHandler do describe '.call' do subject(:handle_request) do - described_class.call( + described_class.new( params: params, current_api_user: current_api_user - ) + ).call end let(:user) { create(:user) } @@ -32,7 +32,6 @@ RSpec.describe Maps::HexagonRequestHandler do min_lat: 40.6, max_lon: -73.9, max_lat: 40.8, - hex_size: 1000, start_date: '2024-06-01T00:00:00Z', end_date: '2024-06-30T23:59:59Z' } @@ -68,8 +67,7 @@ RSpec.describe Maps::HexagonRequestHandler do min_lon: -74.1, min_lat: 40.6, max_lon: -73.9, - max_lat: 40.8, - hex_size: 1000 + max_lat: 40.8 } ) end @@ -94,8 +92,7 @@ RSpec.describe Maps::HexagonRequestHandler do min_lon: -74.1, min_lat: 40.6, max_lon: -73.9, - max_lat: 40.8, - hex_size: 1000 + max_lat: 40.8 } ) end @@ -123,8 +120,7 @@ RSpec.describe Maps::HexagonRequestHandler do min_lon: -74.1, min_lat: 40.6, max_lon: -73.9, - max_lat: 40.8, - hex_size: 1000 + max_lat: 40.8 } ) end @@ -148,7 +144,6 @@ RSpec.describe Maps::HexagonRequestHandler do end end - context 'error handling' do let(:params) do ActionController::Parameters.new(