This commit is contained in:
Mateusz Gruszczyński
2026-09-01 10:20:19 +02:00
parent 1a5c1305dc
commit 3479ed750d
34 changed files with 575 additions and 113 deletions
+18 -5
View File
@@ -49,7 +49,14 @@ fn validate_schedule_conflicts(state: &AppState, item: &Schedule, exclude_id: Op
Ok(())
}
fn refresh_zone_override_boundary(state: &AppState, zone_id: &str) -> Result<(), AppError> {
async fn refresh_zone_override_boundary(state: &AppState, zone_id: &str) -> Result<(), AppError> {
let _zone_guard = state.lock_zone_operation(zone_id).await;
let device_id = state.db.get_zone(zone_id)?.map(|zone| zone.device_id);
let _device_guard = if let Some(device_id) = device_id.as_deref() {
Some(state.lock_device_operation(device_id).await)
} else {
None
};
let Some(mut zone) = state.db.get_zone(zone_id)? else { return Ok(()); };
let has_temporary_schedule_boundary = zone.temporary_quick_thermostat.as_ref()
.map(|session| session.finish_kind == "schedule_boundary")
@@ -87,17 +94,21 @@ async fn get_schedule(State(state): State<AppState>, Path(id): Path<String>) ->
state.db.get_schedule(&id)?.map(Json).ok_or_else(|| AppError::NotFound(format!("schedule {id}")))
}
async fn create_schedule(State(state): State<AppState>, Json(input): Json<ScheduleInput>) -> Result<(StatusCode, Json<Schedule>), AppError> {
let _configuration_guard = state.lock_configuration_operation().await;
let _schedule_guard = state.lock_schedule_operation().await;
input.validate()?;
if state.db.get_zone(&input.zone_id)?.is_none() { return Err(AppError::BadRequest("schedule zone does not exist".into())); }
let item = input.into_schedule(Uuid::new_v4().to_string(), Utc::now());
validate_schedule_conflicts(&state, &item, None)?;
state.db.save_schedule(&item)?;
refresh_zone_override_boundary(&state, &item.zone_id)?;
refresh_zone_override_boundary(&state, &item.zone_id).await?;
state.broadcast("schedule.created", serde_json::to_value(&item)?);
state.wake_zone_control();
Ok((StatusCode::CREATED, Json(item)))
}
async fn update_schedule(State(state): State<AppState>, Path(id): Path<String>, Json(input): Json<ScheduleInput>) -> Result<Json<Schedule>, AppError> {
let _configuration_guard = state.lock_configuration_operation().await;
let _schedule_guard = state.lock_schedule_operation().await;
input.validate()?;
let existing = state.db.get_schedule(&id)?.ok_or_else(|| AppError::NotFound(format!("schedule {id}")))?;
if state.db.get_zone(&input.zone_id)?.is_none() { return Err(AppError::BadRequest("schedule zone does not exist".into())); }
@@ -105,16 +116,18 @@ async fn update_schedule(State(state): State<AppState>, Path(id): Path<String>,
let item = input.into_schedule(id.clone(), existing.created_at);
validate_schedule_conflicts(&state, &item, Some(&id))?;
state.db.save_schedule(&item)?;
refresh_zone_override_boundary(&state, &old_zone_id)?;
if item.zone_id != old_zone_id { refresh_zone_override_boundary(&state, &item.zone_id)?; }
refresh_zone_override_boundary(&state, &old_zone_id).await?;
if item.zone_id != old_zone_id { refresh_zone_override_boundary(&state, &item.zone_id).await?; }
state.broadcast("schedule.updated", serde_json::to_value(&item)?);
state.wake_zone_control();
Ok(Json(item))
}
async fn delete_schedule(State(state): State<AppState>, Path(id): Path<String>) -> Result<StatusCode, AppError> {
let _configuration_guard = state.lock_configuration_operation().await;
let _schedule_guard = state.lock_schedule_operation().await;
let existing = state.db.get_schedule(&id)?.ok_or_else(|| AppError::NotFound(format!("schedule {id}")))?;
if !state.db.delete_schedule(&id)? { return Err(AppError::NotFound(format!("schedule {id}"))); }
refresh_zone_override_boundary(&state, &existing.zone_id)?;
refresh_zone_override_boundary(&state, &existing.zone_id).await?;
state.broadcast("schedule.deleted", json!({"id": id}));
state.wake_zone_control();
Ok(StatusCode::NO_CONTENT)