mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 09:41:40 -05:00
Simplify some services by removing unused parameters and validations
This commit is contained in:
parent
0905ef65a5
commit
3fd7634657
9 changed files with 24 additions and 103 deletions
|
|
@ -4,21 +4,21 @@ class Api::V1::Maps::HexagonsController < ApiController
|
||||||
skip_before_action :authenticate_api_key, if: :public_sharing_request?
|
skip_before_action :authenticate_api_key, if: :public_sharing_request?
|
||||||
|
|
||||||
def index
|
def index
|
||||||
return unless public_sharing_request? || validate_required_parameters
|
result = Maps::HexagonRequestHandler.new(
|
||||||
|
|
||||||
result = Maps::HexagonRequestHandler.call(
|
|
||||||
params: params,
|
params: params,
|
||||||
current_api_user: current_api_user
|
current_api_user: current_api_user
|
||||||
)
|
).call
|
||||||
|
|
||||||
render json: result
|
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
|
rescue Maps::HexagonContextResolver::SharedStatsNotFoundError => e
|
||||||
render json: { error: e.message }, status: :not_found
|
render json: { error: e.message }, status: :not_found
|
||||||
rescue Maps::DateParameterCoercer::InvalidDateFormatError => e
|
rescue Maps::DateParameterCoercer::InvalidDateFormatError => e
|
||||||
render json: { error: e.message }, status: :bad_request
|
render json: { error: e.message }, status: :bad_request
|
||||||
rescue Maps::H3HexagonCenters::TooManyHexagonsError,
|
rescue Maps::H3HexagonCenters::PostGISError => e
|
||||||
Maps::H3HexagonCenters::InvalidCoordinatesError,
|
|
||||||
Maps::H3HexagonCenters::PostGISError => e
|
|
||||||
render json: { error: e.message }, status: :bad_request
|
render json: { error: e.message }, status: :bad_request
|
||||||
rescue StandardError => _e
|
rescue StandardError => _e
|
||||||
handle_service_error
|
handle_service_error
|
||||||
|
|
@ -56,10 +56,6 @@ class Api::V1::Maps::HexagonsController < ApiController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def hexagon_params
|
|
||||||
params.permit(:uuid, :start_date, :end_date)
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_service_error
|
def handle_service_error
|
||||||
render json: { error: 'Failed to generate hexagon grid' }, status: :internal_server_error
|
render json: { error: 'Failed to generate hexagon grid' }, status: :internal_server_error
|
||||||
end
|
end
|
||||||
|
|
@ -67,39 +63,4 @@ class Api::V1::Maps::HexagonsController < ApiController
|
||||||
def public_sharing_request?
|
def public_sharing_request?
|
||||||
params[:uuid].present?
|
params[:uuid].present?
|
||||||
end
|
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
|
end
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,9 @@ module Maps
|
||||||
class BoundsCalculator
|
class BoundsCalculator
|
||||||
class NoUserFoundError < StandardError; end
|
class NoUserFoundError < StandardError; end
|
||||||
class NoDateRangeError < StandardError; end
|
class NoDateRangeError < StandardError; end
|
||||||
class NoDataFoundError < StandardError; end
|
|
||||||
|
|
||||||
def initialize(target_user:, start_date:, end_date:)
|
def initialize(user:, start_date:, end_date:)
|
||||||
@target_user = target_user
|
@user = user
|
||||||
@start_date = start_date
|
@start_date = start_date
|
||||||
@end_date = end_date
|
@end_date = end_date
|
||||||
end
|
end
|
||||||
|
|
@ -18,7 +17,7 @@ module Maps
|
||||||
start_timestamp = Maps::DateParameterCoercer.new(@start_date).call
|
start_timestamp = Maps::DateParameterCoercer.new(@start_date).call
|
||||||
end_timestamp = Maps::DateParameterCoercer.new(@end_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
|
point_count = points_relation.count
|
||||||
|
|
||||||
return build_no_data_response if point_count.zero?
|
return build_no_data_response if point_count.zero?
|
||||||
|
|
@ -30,7 +29,7 @@ module Maps
|
||||||
private
|
private
|
||||||
|
|
||||||
def validate_inputs!
|
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
|
raise NoDateRangeError, 'No date range specified' unless @start_date && @end_date
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -42,7 +41,7 @@ module Maps
|
||||||
WHERE user_id = $1
|
WHERE user_id = $1
|
||||||
AND timestamp BETWEEN $2 AND $3",
|
AND timestamp BETWEEN $2 AND $3",
|
||||||
'bounds_query',
|
'bounds_query',
|
||||||
[@target_user.id, start_timestamp, end_timestamp]
|
[@user.id, start_timestamp, end_timestamp]
|
||||||
).first
|
).first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,10 @@ class Maps::H3HexagonCenters
|
||||||
DEFAULT_H3_RESOLUTION = 8 # Small hexagons for good detail
|
DEFAULT_H3_RESOLUTION = 8 # Small hexagons for good detail
|
||||||
MAX_HEXAGONS = 10_000 # Maximum number of hexagons to prevent memory issues
|
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
|
class PostGISError < StandardError; end
|
||||||
|
|
||||||
attr_reader :user_id, :start_date, :end_date, :h3_resolution
|
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)
|
def initialize(user_id:, start_date:, end_date:, h3_resolution: DEFAULT_H3_RESOLUTION)
|
||||||
@user_id = user_id
|
@user_id = user_id
|
||||||
@start_date = start_date
|
@start_date = start_date
|
||||||
|
|
@ -24,8 +19,6 @@ class Maps::H3HexagonCenters
|
||||||
end
|
end
|
||||||
|
|
||||||
def call
|
def call
|
||||||
validate!
|
|
||||||
|
|
||||||
points = fetch_user_points
|
points = fetch_user_points
|
||||||
return [] if points.empty?
|
return [] if points.empty?
|
||||||
|
|
||||||
|
|
@ -104,10 +97,4 @@ class Maps::H3HexagonCenters
|
||||||
|
|
||||||
service.call
|
service.call
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate!
|
|
||||||
return if valid?
|
|
||||||
|
|
||||||
raise InvalidCoordinatesError, errors.full_messages.join(', ')
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,6 @@ module Maps
|
||||||
def build_hexagon_properties(index, earliest, latest)
|
def build_hexagon_properties(index, earliest, latest)
|
||||||
{
|
{
|
||||||
'hex_id' => index + 1,
|
'hex_id' => index + 1,
|
||||||
'hex_size' => 1000,
|
|
||||||
'earliest_point' => earliest ? Time.zone.at(earliest).iso8601 : nil,
|
'earliest_point' => earliest ? Time.zone.at(earliest).iso8601 : nil,
|
||||||
'latest_point' => latest ? Time.zone.at(latest).iso8601 : nil
|
'latest_point' => latest ? Time.zone.at(latest).iso8601 : nil
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +106,6 @@ module Maps
|
||||||
'type' => 'FeatureCollection',
|
'type' => 'FeatureCollection',
|
||||||
'features' => hexagon_features,
|
'features' => hexagon_features,
|
||||||
'metadata' => {
|
'metadata' => {
|
||||||
'hex_size_m' => 1000,
|
|
||||||
'count' => hexagon_features.count,
|
'count' => hexagon_features.count,
|
||||||
'user_id' => target_user.id,
|
'user_id' => target_user.id,
|
||||||
'pre_calculated' => true
|
'pre_calculated' => true
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,9 @@
|
||||||
|
|
||||||
module Maps
|
module Maps
|
||||||
class HexagonRequestHandler
|
class HexagonRequestHandler
|
||||||
def self.call(params:, current_api_user: nil)
|
def initialize(params:, user: nil)
|
||||||
new(params: params, current_api_user: current_api_user).call
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(params:, current_api_user: nil)
|
|
||||||
@params = params
|
@params = params
|
||||||
@current_api_user = current_api_user
|
@user = user
|
||||||
end
|
end
|
||||||
|
|
||||||
def call
|
def call
|
||||||
|
|
@ -34,16 +30,15 @@ module Maps
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :params, :current_api_user
|
attr_reader :params, :user
|
||||||
|
|
||||||
def resolve_context
|
def resolve_context
|
||||||
Maps::HexagonContextResolver.call(
|
Maps::HexagonContextResolver.call(
|
||||||
params: params,
|
params: params,
|
||||||
current_api_user: current_api_user
|
user: user
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def find_matching_stat(context)
|
def find_matching_stat(context)
|
||||||
return unless context[:target_user] && context[:start_date]
|
return unless context[:target_user] && context[:start_date]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,9 +103,7 @@ class Stats::CalculateMonth
|
||||||
|
|
||||||
Rails.logger.info "Pre-calculated #{result.size} H3 hexagon centers for user #{user.id}, #{year}-#{month}"
|
Rails.logger.info "Pre-calculated #{result.size} H3 hexagon centers for user #{user.id}, #{year}-#{month}"
|
||||||
result
|
result
|
||||||
rescue Maps::H3HexagonCenters::TooManyHexagonsError,
|
rescue Maps::H3HexagonCenters::PostGISError => e
|
||||||
Maps::H3HexagonCenters::InvalidCoordinatesError,
|
|
||||||
Maps::H3HexagonCenters::PostGISError => e
|
|
||||||
Rails.logger.warn "H3 hexagon centers calculation failed for user #{user.id}, #{year}-#{month}: #{e.message}"
|
Rails.logger.warn "H3 hexagon centers calculation failed for user #{user.id}, #{year}-#{month}: #{e.message}"
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ RSpec.describe 'Api::V1::Maps::Hexagons', type: :request do
|
||||||
min_lat: 40.6,
|
min_lat: 40.6,
|
||||||
max_lon: -73.9,
|
max_lon: -73.9,
|
||||||
max_lat: 40.8,
|
max_lat: 40.8,
|
||||||
hex_size: 1000,
|
|
||||||
start_date: '2024-06-01T00:00:00Z',
|
start_date: '2024-06-01T00:00:00Z',
|
||||||
end_date: '2024-06-30T23:59:59Z'
|
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)
|
expect(response).to have_http_status(:bad_request)
|
||||||
|
|
||||||
json_response = JSON.parse(response.body)
|
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')
|
expect(json_response['error']).to include('min_lon')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -69,15 +68,6 @@ RSpec.describe 'Api::V1::Maps::Hexagons', type: :request do
|
||||||
expect(response).to have_http_status(:bad_request)
|
expect(response).to have_http_status(:bad_request)
|
||||||
end
|
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
|
context 'with no data points' do
|
||||||
let(:empty_user) { create(:user) }
|
let(:empty_user) { create(:user) }
|
||||||
let(:empty_headers) { { 'Authorization' => "Bearer #{empty_user.api_key}" } }
|
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
|
# Verify properties include timestamp data
|
||||||
expect(feature['properties']['earliest_point']).to be_present
|
expect(feature['properties']['earliest_point']).to be_present
|
||||||
expect(feature['properties']['latest_point']).to be_present
|
expect(feature['properties']['latest_point']).to be_present
|
||||||
expect(feature['properties']['hex_size']).to eq(1000)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'generates proper hexagon polygons from centers' do
|
it 'generates proper hexagon polygons from centers' do
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ RSpec.describe Maps::HexagonCenterManager do
|
||||||
|
|
||||||
properties = feature['properties']
|
properties = feature['properties']
|
||||||
expect(properties['hex_id']).to eq(index + 1)
|
expect(properties['hex_id']).to eq(index + 1)
|
||||||
expect(properties['hex_size']).to eq(1000)
|
|
||||||
expect(properties['earliest_point']).to be_present
|
expect(properties['earliest_point']).to be_present
|
||||||
expect(properties['latest_point']).to be_present
|
expect(properties['latest_point']).to be_present
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ require 'rails_helper'
|
||||||
RSpec.describe Maps::HexagonRequestHandler do
|
RSpec.describe Maps::HexagonRequestHandler do
|
||||||
describe '.call' do
|
describe '.call' do
|
||||||
subject(:handle_request) do
|
subject(:handle_request) do
|
||||||
described_class.call(
|
described_class.new(
|
||||||
params: params,
|
params: params,
|
||||||
current_api_user: current_api_user
|
current_api_user: current_api_user
|
||||||
)
|
).call
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
|
|
@ -32,7 +32,6 @@ RSpec.describe Maps::HexagonRequestHandler do
|
||||||
min_lat: 40.6,
|
min_lat: 40.6,
|
||||||
max_lon: -73.9,
|
max_lon: -73.9,
|
||||||
max_lat: 40.8,
|
max_lat: 40.8,
|
||||||
hex_size: 1000,
|
|
||||||
start_date: '2024-06-01T00:00:00Z',
|
start_date: '2024-06-01T00:00:00Z',
|
||||||
end_date: '2024-06-30T23:59:59Z'
|
end_date: '2024-06-30T23:59:59Z'
|
||||||
}
|
}
|
||||||
|
|
@ -68,8 +67,7 @@ RSpec.describe Maps::HexagonRequestHandler do
|
||||||
min_lon: -74.1,
|
min_lon: -74.1,
|
||||||
min_lat: 40.6,
|
min_lat: 40.6,
|
||||||
max_lon: -73.9,
|
max_lon: -73.9,
|
||||||
max_lat: 40.8,
|
max_lat: 40.8
|
||||||
hex_size: 1000
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
@ -94,8 +92,7 @@ RSpec.describe Maps::HexagonRequestHandler do
|
||||||
min_lon: -74.1,
|
min_lon: -74.1,
|
||||||
min_lat: 40.6,
|
min_lat: 40.6,
|
||||||
max_lon: -73.9,
|
max_lon: -73.9,
|
||||||
max_lat: 40.8,
|
max_lat: 40.8
|
||||||
hex_size: 1000
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
@ -123,8 +120,7 @@ RSpec.describe Maps::HexagonRequestHandler do
|
||||||
min_lon: -74.1,
|
min_lon: -74.1,
|
||||||
min_lat: 40.6,
|
min_lat: 40.6,
|
||||||
max_lon: -73.9,
|
max_lon: -73.9,
|
||||||
max_lat: 40.8,
|
max_lat: 40.8
|
||||||
hex_size: 1000
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
@ -148,7 +144,6 @@ RSpec.describe Maps::HexagonRequestHandler do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
context 'error handling' do
|
context 'error handling' do
|
||||||
let(:params) do
|
let(:params) do
|
||||||
ActionController::Parameters.new(
|
ActionController::Parameters.new(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue