lgtm
This commit is contained in:
parent
f7e0814a38
commit
fd2860070a
55 changed files with 4084 additions and 186 deletions
70
server-rs/src/routes/developments.rs
Normal file
70
server-rs/src/routes/developments.rs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use axum::extract::{Query, State};
|
||||
use axum::response::{IntoResponse, Json, Response};
|
||||
use axum::Extension;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::info;
|
||||
|
||||
use crate::auth::OptionalUser;
|
||||
use crate::data::DevelopmentSite;
|
||||
use crate::licensing::{check_license_bounds, resolve_share_code};
|
||||
use crate::parsing::require_bounds;
|
||||
use crate::state::SharedState;
|
||||
|
||||
/// Hard cap on sites returned per viewport. Biggest schemes (by dwelling count)
|
||||
/// are kept when a dense viewport exceeds this; `truncated` flags the clamp.
|
||||
const DEVELOPMENTS_LIMIT: usize = 4000;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DevelopmentsParams {
|
||||
bounds: Option<String>,
|
||||
/// Share-link code; grants bbox-scoped access for unlicensed users.
|
||||
share: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct DevelopmentsResponse {
|
||||
pub developments: Vec<DevelopmentSite>,
|
||||
pub total: usize,
|
||||
pub truncated: bool,
|
||||
}
|
||||
|
||||
/// Forward-looking "where new homes are coming" layer: planned/pipeline
|
||||
/// development sites (MHCLG Brownfield Land register + Homes England Land Hub),
|
||||
/// served as points within a viewport. Public OGL data, but still gated by the
|
||||
/// normal demo/licence bounds check so unlicensed users only see their free zone.
|
||||
pub async fn get_developments(
|
||||
State(shared): State<Arc<SharedState>>,
|
||||
Extension(user): Extension<OptionalUser>,
|
||||
Extension(geo): Extension<crate::demo_zone::DemoZone>,
|
||||
Query(params): Query<DevelopmentsParams>,
|
||||
) -> Result<Json<DevelopmentsResponse>, Response> {
|
||||
let state = shared.load_state();
|
||||
|
||||
let (south, west, north, east) =
|
||||
require_bounds(params.bounds).map_err(IntoResponse::into_response)?;
|
||||
|
||||
let share_bounds = resolve_share_code(&state, params.share.as_deref()).await;
|
||||
check_license_bounds(
|
||||
&user.0,
|
||||
(south, west, north, east),
|
||||
geo.free_zone,
|
||||
share_bounds,
|
||||
)?;
|
||||
|
||||
let developments = state.developments.clone();
|
||||
let (sites, total, truncated) =
|
||||
developments.query_bounds(south, west, north, east, DEVELOPMENTS_LIMIT);
|
||||
|
||||
info!(
|
||||
results = sites.len(),
|
||||
total, truncated, "GET /api/developments"
|
||||
);
|
||||
|
||||
Ok(Json(DevelopmentsResponse {
|
||||
developments: sites,
|
||||
total,
|
||||
truncated,
|
||||
}))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue