Implements GET /api/v1/weather/nearby endpoint with comprehensive parameter
validation and error handling. The controller validates required parameters
(lat, lon, radius) and optional parameters (hours, limit) with appropriate
range checking. Integrates with PreparedQueries for efficient database access
and WeatherJSON for response serialization.
Key features:
- Required params: lat (-90 to 90), lon (-180 to 180), radius (0-1000 miles)
- Optional params: hours (1-168, default 6), limit (1-100, default 50)
- Proper error responses via FallbackController (400 for bad requests, 422 for validation)
- Full test coverage (16 tests) including edge cases and error scenarios
Also updates FallbackController to handle {:error, status, message} tuples
and fixes WeatherJSON to support both field name formats (lat/lon and latitude/longitude)
for compatibility with existing tests and actual query results.
135 lines
4.8 KiB
Elixir
135 lines
4.8 KiB
Elixir
defmodule AprsmeWeb.Router do
|
|
use AprsmeWeb, :router
|
|
use ErrorTracker.Web, :router
|
|
|
|
import AprsmeWeb.UserAuth
|
|
import Phoenix.LiveDashboard.Router
|
|
|
|
alias AprsmeWeb.Plugs.IPGeolocation
|
|
alias AprsmeWeb.Plugs.RateLimiter
|
|
|
|
pipeline :browser do
|
|
plug :accepts, ["html"]
|
|
plug :fetch_session
|
|
plug :fetch_live_flash
|
|
plug :put_root_layout, {AprsmeWeb.Layouts, :root}
|
|
plug :protect_from_forgery
|
|
|
|
plug :put_secure_browser_headers, %{
|
|
"content-security-policy" =>
|
|
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.sentry-cdn.com https://unpkg.com https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://unpkg.com; img-src 'self' data: https: http: blob:; font-src 'self' data:; connect-src 'self' wss: https://*.ingest.sentry.io https://*.sentry.io https://nominatim.openstreetmap.org https://tile.openstreetmap.org https://*.tile.openstreetmap.org https://*.tile.openstreetmap.de https://*.basemaps.cartocdn.com; media-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; frame-src 'self'; manifest-src 'self'; worker-src 'self' blob:"
|
|
}
|
|
|
|
plug :fetch_current_user
|
|
plug AprsmeWeb.Plugs.SetLocale
|
|
plug IPGeolocation
|
|
plug RateLimiter, scale: 60_000, limit: 200
|
|
end
|
|
|
|
pipeline :public_api do
|
|
plug :accepts, ["json"]
|
|
plug RateLimiter, scale: 60_000, limit: 100
|
|
end
|
|
|
|
pipeline :accepts_json do
|
|
plug :accepts, ["json"]
|
|
end
|
|
|
|
pipeline :api do
|
|
plug :accepts, ["json"]
|
|
plug RateLimiter, scale: 60_000, limit: 100
|
|
plug AprsmeWeb.Plugs.ApiCSRF
|
|
end
|
|
|
|
scope "/", AprsmeWeb do
|
|
pipe_through [:browser, :require_authenticated_user]
|
|
live_dashboard "/dashboard", metrics: AprsmeWeb.Telemetry
|
|
error_tracker_dashboard("/errors")
|
|
end
|
|
|
|
scope "/", AprsmeWeb do
|
|
pipe_through [:browser]
|
|
|
|
delete "/users/log_out", UserSessionController, :delete
|
|
|
|
live_session :current_user,
|
|
on_mount: [{AprsmeWeb.UserAuth, :mount_current_user}, {AprsmeWeb.LocaleHook, :set_locale}] do
|
|
live "/users/confirm/:token", UserConfirmationLive, :edit
|
|
live "/users/confirm", UserConfirmationInstructionsLive, :new
|
|
end
|
|
end
|
|
|
|
# Health/readiness routes — no rate limiting to avoid false K8s probe failures
|
|
scope "/", AprsmeWeb do
|
|
pipe_through :accepts_json
|
|
get "/ready", PageController, :ready
|
|
get "/status.json", PageController, :status_json
|
|
end
|
|
|
|
## Authentication routes
|
|
|
|
scope "/", AprsmeWeb do
|
|
pipe_through [:browser, :redirect_if_user_is_authenticated]
|
|
|
|
live_session :redirect_if_user_is_authenticated,
|
|
on_mount: [{AprsmeWeb.UserAuth, :redirect_if_user_is_authenticated}, {AprsmeWeb.LocaleHook, :set_locale}] do
|
|
live "/users/register", UserRegistrationLive, :new
|
|
live "/users/log_in", UserLoginLive, :new
|
|
live "/users/reset_password", UserForgotPasswordLive, :new
|
|
live "/users/reset_password/:token", UserResetPasswordLive, :edit
|
|
end
|
|
|
|
post "/users/log_in", UserSessionController, :create
|
|
end
|
|
|
|
scope "/", AprsmeWeb do
|
|
pipe_through [:browser, :require_authenticated_user]
|
|
|
|
live_session :require_authenticated_user,
|
|
on_mount: [{AprsmeWeb.UserAuth, :ensure_authenticated}, {AprsmeWeb.LocaleHook, :set_locale}] do
|
|
live "/users/settings", UserSettingsLive, :edit
|
|
live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
|
|
end
|
|
end
|
|
|
|
scope "/", AprsmeWeb do
|
|
pipe_through :browser
|
|
|
|
live_session :regular_pages,
|
|
on_mount: [{AprsmeWeb.UserAuth, :mount_current_user}, {AprsmeWeb.LocaleHook, :set_locale}] do
|
|
live "/status", StatusLive.Index, :index
|
|
live "/packets", PacketsLive.Index, :index
|
|
live "/packets/:callsign", PacketsLive.CallsignView, :index
|
|
live "/badpackets", BadPacketsLive.Index, :index
|
|
live "/weather/:callsign", WeatherLive.CallsignView, :index
|
|
live "/about", AboutLive, :index
|
|
live "/api", ApiDocsLive, :index
|
|
live "/info/:callsign", InfoLive.Show, :show
|
|
live "/", MapLive.Index, :index
|
|
live "/:callsign", MapLive.Index, :index
|
|
end
|
|
end
|
|
|
|
# API v1 routes
|
|
scope "/api/v1", AprsmeWeb.Api.V1, as: :api_v1 do
|
|
pipe_through :api
|
|
|
|
get "/callsign/:callsign", CallsignController, :show
|
|
get "/weather/nearby", WeatherController, :nearby
|
|
end
|
|
|
|
# Enable LiveDashboard and Swoosh mailbox preview in development
|
|
if Application.compile_env(:aprsme, :dev_routes) do
|
|
# If you want to use the LiveDashboard in production, you should put
|
|
# it behind authentication and allow only admins to access it.
|
|
# If your application does not have an admins-only section yet,
|
|
# you can use Plug.BasicAuth to set up some basic authentication
|
|
# as long as you are also using SSL (which you should anyway).
|
|
|
|
scope "/dev" do
|
|
pipe_through :browser
|
|
|
|
forward "/mailbox", Plug.Swoosh.MailboxPreview
|
|
end
|
|
end
|
|
end
|