sl_map_web/routes/
notecard.rs1use axum::Json;
5use axum::extract::{Multipart, State};
6use serde::Serialize;
7use sl_map_apis::region::usb_notecard_to_grid_rectangle;
8use sl_types::map::{GridRectangleLike as _, USBNotecard};
9
10use crate::auth::CurrentUser;
11use crate::error::Error;
12use crate::library;
13use crate::state::AppState;
14use crate::usb_notecard::parse_notecard_form;
15
16#[derive(Debug, Clone, Serialize)]
18pub struct ResolvedWaypoint {
19 pub region_name: String,
21 pub region_x: u32,
23 pub region_y: u32,
25 pub x: f32,
27 pub y: f32,
29 pub z: f32,
31}
32
33#[derive(Debug, Clone, Serialize)]
35pub struct DeriveResponse {
36 pub lower_left_x: u32,
38 pub lower_left_y: u32,
40 pub upper_right_x: u32,
42 pub upper_right_y: u32,
44 pub waypoints: Vec<ResolvedWaypoint>,
46}
47
48pub async fn derive_rectangle(
57 user: CurrentUser,
58 State(state): State<AppState>,
59 multipart: Multipart,
60) -> Result<Json<DeriveResponse>, Error> {
61 let form = parse_notecard_form(multipart).await?;
62 let (border_north, border_south, border_east, border_west) = form.borders();
63 let notecard = match (form.notecard, form.notecard_id) {
64 (Some(nc), _) => nc,
65 (None, Some(id)) => {
66 let row = library::assert_can_read_notecard(&state.db, user.user_id, id).await?;
70 row.body.parse()?
71 }
72 (None, None) => return Err(Error::BadRequest("missing notecard".to_owned())),
73 };
74 let mut region_cache = state.region_cache.lock().await;
75 let rect = usb_notecard_to_grid_rectangle(&mut region_cache, ¬ecard)
76 .await?
77 .expanded_west(border_west)
78 .expanded_east(border_east)
79 .expanded_south(border_south)
80 .expanded_north(border_north);
81 let waypoints = resolve_waypoints(&mut region_cache, ¬ecard).await?;
82 drop(region_cache);
83 let lower_left = rect.lower_left_corner();
84 let upper_right = rect.upper_right_corner();
85 Ok(Json(DeriveResponse {
86 lower_left_x: lower_left.x(),
87 lower_left_y: lower_left.y(),
88 upper_right_x: upper_right.x(),
89 upper_right_y: upper_right.y(),
90 waypoints,
91 }))
92}
93
94async fn resolve_waypoints(
97 region_cache: &mut sl_map_apis::region::RegionNameToGridCoordinatesCache,
98 notecard: &USBNotecard,
99) -> Result<Vec<ResolvedWaypoint>, Error> {
100 let mut out = Vec::with_capacity(notecard.waypoints().len());
101 for waypoint in notecard.waypoints() {
102 let region = waypoint.location().region_name();
103 let grid = region_cache
104 .get_grid_coordinates(region)
105 .await?
106 .ok_or_else(|| {
107 Error::BadRequest(format!(
108 "could not resolve region `{}` to grid coordinates",
109 region.to_owned().into_inner()
110 ))
111 })?;
112 let rc = waypoint.region_coordinates();
113 out.push(ResolvedWaypoint {
114 region_name: region.to_owned().into_inner(),
115 region_x: grid.x(),
116 region_y: grid.y(),
117 x: rc.x(),
118 y: rc.y(),
119 z: rc.z(),
120 });
121 }
122 Ok(out)
123}