added http endpoint to update alarms. For now it will not update the schedules automatically
This commit is contained in:
BIN
snooze-pal.db
BIN
snooze-pal.db
Binary file not shown.
@@ -1,3 +1,5 @@
|
||||
use std::i32;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use sea_orm::{
|
||||
ActiveModelTrait, ActiveValue::Set, ColumnTrait, ConnectionTrait, DbErr, EntityTrait, QueryFilter
|
||||
@@ -34,3 +36,10 @@ pub async fn get_alarms<C: ConnectionTrait>(db: &C, enabled: Option<bool>) -> Re
|
||||
|
||||
query.all(db).await
|
||||
}
|
||||
|
||||
pub async fn get_alarm<C: ConnectionTrait>(db: &C, id: i32) -> Result<Option<model::alarm::Model>, DbErr> {
|
||||
let result = model::alarm::Entity::find_by_id(id)
|
||||
.one(db).await;
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
mod get;
|
||||
mod patch;
|
||||
mod post;
|
||||
|
||||
use utoipa_axum::{router::OpenApiRouter, routes};
|
||||
@@ -6,5 +7,9 @@ use utoipa_axum::{router::OpenApiRouter, routes};
|
||||
use crate::AppState;
|
||||
|
||||
pub fn router() -> OpenApiRouter<AppState> {
|
||||
OpenApiRouter::new().routes(routes!(post::post_handler, get::get_handler))
|
||||
OpenApiRouter::new().routes(routes!(
|
||||
post::post_handler,
|
||||
get::get_handler,
|
||||
patch::patch_handler
|
||||
))
|
||||
}
|
||||
|
||||
73
src/resources/alarm/patch.rs
Normal file
73
src/resources/alarm/patch.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use axum::Json;
|
||||
use axum::http::StatusCode;
|
||||
use axum::{debug_handler, response::IntoResponse};
|
||||
use axum::extract::{Path, State};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::{IntoResponses, ToSchema};
|
||||
|
||||
use crate::AppState;
|
||||
|
||||
#[derive(ToSchema, Serialize, Deserialize)]
|
||||
pub struct OkResponse {
|
||||
id: i32,
|
||||
title: String,
|
||||
enabled: bool,
|
||||
time: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(ToSchema, Deserialize)]
|
||||
pub struct PatchRequestBody {
|
||||
title: Option<String>,
|
||||
enabled: Option<bool>,
|
||||
time: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(IntoResponses)]
|
||||
pub enum Responses {
|
||||
#[response(status = 200)]
|
||||
Ok(#[to_schema] OkResponse),
|
||||
#[response(status = 500, description = "Something failed in the Database when trying to update the alarm")]
|
||||
DbError(String),
|
||||
#[response(status = 404, description = "The alarm you want to update was not found")]
|
||||
NotFound,
|
||||
}
|
||||
|
||||
impl IntoResponse for Responses {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
match self {
|
||||
Responses::Ok(body) => (StatusCode::OK, Json(body)).into_response(),
|
||||
Responses::DbError(message) => (StatusCode::INTERNAL_SERVER_ERROR, Json(message)).into_response(),
|
||||
Responses::NotFound => (StatusCode::NOT_FOUND).into_response(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::types::Alarm> for OkResponse {
|
||||
fn from(value: crate::types::Alarm) -> Self {
|
||||
OkResponse {
|
||||
id: value.id,
|
||||
title: value.title,
|
||||
enabled: value.enabled,
|
||||
time: value.time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(patch, path = "/{id}", responses(Responses))]
|
||||
#[debug_handler]
|
||||
pub async fn patch_handler(State(AppState { scheduler }): State<AppState>, Path(id): Path<i32>, Json(body): Json<PatchRequestBody>) -> Responses {
|
||||
let result = scheduler.update_alarm(id, body.title, body.enabled, body.time).await;
|
||||
|
||||
match result {
|
||||
Ok(Some(alarm)) => {
|
||||
Responses::Ok(alarm.into())
|
||||
},
|
||||
Ok(None) => {
|
||||
Responses::NotFound
|
||||
},
|
||||
Err(error) => {
|
||||
Responses::DbError(error.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ pub struct RequestBody {
|
||||
|
||||
#[derive(ToSchema, Serialize)]
|
||||
pub struct OkResponseBody {
|
||||
id: i32,
|
||||
time: DateTime<Utc>,
|
||||
title: String,
|
||||
enabled: bool,
|
||||
@@ -43,7 +44,12 @@ impl IntoResponse for Responses {
|
||||
|
||||
impl From<Alarm> for OkResponseBody {
|
||||
fn from(value: Alarm) -> Self {
|
||||
OkResponseBody { time: value.time, enabled: value.enabled, title: value.title }
|
||||
OkResponseBody {
|
||||
time: value.time,
|
||||
enabled: value.enabled,
|
||||
title: value.title,
|
||||
id: value.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use std::i32;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use chrono::{DateTime, Local, Timelike, Utc};
|
||||
use cron_tab::Cron;
|
||||
use sea_orm::{DatabaseConnection, DbErr};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use sea_orm::{ActiveModelTrait, DatabaseConnection, DbErr};
|
||||
|
||||
use crate::dao::alarm::{create_alarm, get_alarms};
|
||||
use crate::dao::alarm::{create_alarm, get_alarm, get_alarms};
|
||||
use crate::model;
|
||||
use crate::ringer::Ringer;
|
||||
use crate::types::Alarm;
|
||||
|
||||
@@ -50,16 +53,15 @@ impl Scheduler {
|
||||
|
||||
pub async fn add_alarm(&self, time: DateTime<Utc>, title: String) -> Result<Alarm, String> {
|
||||
let cron_schedule = self.construct_cron_schedule(time);
|
||||
let alarm = Alarm::new(true, time, title.clone());
|
||||
|
||||
create_alarm(&*self.db, title, time)
|
||||
let created_alarm = create_alarm(&*self.db, title, time)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
self.schedule(&cron_schedule).map_err(|e| e.to_string())?;
|
||||
println!("Added alarm {}", cron_schedule);
|
||||
|
||||
Ok(alarm)
|
||||
Ok(created_alarm.into())
|
||||
}
|
||||
|
||||
pub async fn get_alarms(&self, enabled: Option<bool>) -> Result<Vec<Alarm>, DbErr> {
|
||||
@@ -71,6 +73,32 @@ impl Scheduler {
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn update_alarm(&self, id: i32, title: Option<String>, enabled: Option<bool>, time: Option<DateTime<Utc>>) -> Result<Option<Alarm>, DbErr> {
|
||||
let alarm = get_alarm(&*self.db, id).await?;
|
||||
|
||||
let Some(alarm) = alarm else {
|
||||
return Ok(None)
|
||||
};
|
||||
|
||||
let mut active_alarm: model::alarm::ActiveModel = alarm.into();
|
||||
|
||||
if let Some(title) = title {
|
||||
active_alarm.title = Set(title.to_owned());
|
||||
}
|
||||
|
||||
if let Some(enabled) = enabled {
|
||||
active_alarm.enabled = Set(enabled);
|
||||
}
|
||||
|
||||
if let Some(time) = time {
|
||||
active_alarm.time = Set(time.naive_utc());
|
||||
}
|
||||
|
||||
let updated_alarm = active_alarm.update(&*self.db).await?;
|
||||
|
||||
return Ok(Some(updated_alarm.into()));
|
||||
}
|
||||
|
||||
pub async fn start(&self) {
|
||||
self.cron.lock().expect("Failed to lock cron").start();
|
||||
self.register_existing_alarms().await;
|
||||
|
||||
@@ -5,14 +5,16 @@ use crate::model;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Alarm {
|
||||
pub id: i32,
|
||||
pub enabled: bool,
|
||||
pub time: DateTime<Utc>,
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
impl Alarm {
|
||||
pub fn new(enabled: bool, time: DateTime<Utc>, title: String) -> Self {
|
||||
pub fn new(id: i32, enabled: bool, time: DateTime<Utc>, title: String) -> Self {
|
||||
Self {
|
||||
id,
|
||||
enabled,
|
||||
time,
|
||||
title,
|
||||
@@ -23,6 +25,7 @@ impl Alarm {
|
||||
impl From<model::alarm::Model> for Alarm {
|
||||
fn from(value: model::alarm::Model) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
enabled: value.enabled,
|
||||
time: DateTime::from_utc(value.time, Utc),
|
||||
title: value.title,
|
||||
|
||||
Reference in New Issue
Block a user