Add controller to database

This commit is contained in:
Tobias Reisinger 2023-11-24 22:45:44 +01:00
parent 9f64075f5a
commit d193000aec
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
34 changed files with 411 additions and 195 deletions

View file

@ -2,10 +2,11 @@
build:
cargo build
sqlx: build
sqlx:
rm ./emgauwa-dev.sqlite
cargo sqlx database create
cargo sqlx migrate run
cargo sqlx prepare
cargo sqlx prepare --workspace
build-rpi:
cross build --target arm-unknown-linux-gnueabihf

View file

@ -2,8 +2,10 @@ use std::str;
use futures::{future, pin_mut, StreamExt};
use futures::channel::mpsc;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::io::AsyncReadExt;
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
use tokio_tungstenite::tungstenite::Error;
use emgauwa_lib::db;
mod settings;
@ -11,6 +13,8 @@ mod settings;
async fn main() {
let settings = settings::init();
let _pool = db::init(&settings.database).await;
let url = format!(
"ws://{}:{}/api/v1/ws/controllers",
settings.core.host,
@ -21,17 +25,11 @@ async fn main() {
tokio::spawn(read_stdin(stdin_tx));
let (ws_stream, _) = connect_async(url).await.expect("Failed to connect");
println!("WebSocket handshake has been successfully completed");
let (write, read) = ws_stream.split();
let stdin_to_ws = stdin_rx.map(Ok).forward(write);
let ws_to_stdout = {
read.for_each(|message| async {
let data = message.unwrap().into_text().unwrap();
println!("{}", data);
})
};
let ws_to_stdout = read.for_each(handle_message);
pin_mut!(stdin_to_ws, ws_to_stdout);
future::select(stdin_to_ws, ws_to_stdout).await;
@ -50,4 +48,11 @@ async fn read_stdin(tx: mpsc::UnboundedSender<Message>) {
buf.truncate(n);
tx.unbounded_send(Message::text(str::from_utf8(&buf).unwrap())).unwrap();
}
}
pub async fn handle_message(message_result: Result<Message, Error>) {
match message_result {
Ok(message) => println!("{}", message.into_text().unwrap()),
Err(err) => println!("Error: {}", err)
}
}

View file

@ -14,13 +14,13 @@ async fn main() -> std::io::Result<()> {
let settings = settings::init();
let log_level: LevelFilter = LevelFilter::from_str(&settings.logging.level)
.unwrap_or_else(|_| panic!("Error parsing log level."));
.expect("Error parsing log level.");
trace!("Log level set to {:?}", log_level);
SimpleLogger::new()
.with_level(log_level)
.init()
.unwrap_or_else(|_| panic!("Error initializing logger."));
.expect("Error initializing logger.");
let pool = emgauwa_lib::db::init(&settings.database).await;

View file

@ -0,0 +1,122 @@
use serde_derive::{Deserialize, Serialize};
use std::ops::DerefMut;
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;
use crate::db::errors::DatabaseError;
use crate::db::model_utils::Period;
use crate::db::tag::Tag;
use crate::db::types::ControllerUid;
#[derive(Debug, Serialize, Clone)]
pub struct Controller {
pub id: i64,
pub uid: ControllerUid,
pub name: String,
pub relay_count: i64,
pub active: bool,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct Periods(pub Vec<Period>);
impl Controller {
pub async fn get_all(
conn: &mut PoolConnection<Sqlite>,
) -> Result<Vec<Controller>, DatabaseError> {
Ok(sqlx::query_as!(Controller, "SELECT * FROM controllers")
.fetch_all(conn.deref_mut())
.await?)
}
pub async fn get(
conn: &mut PoolConnection<Sqlite>,
id: i64,
) -> Result<Controller, DatabaseError> {
sqlx::query_as!(
Controller,
"SELECT * FROM controllers WHERE id = ?",
id
)
.fetch_optional(conn.deref_mut())
.await
.map(|s| s.ok_or(DatabaseError::NotFound))?
}
pub async fn get_by_uid(
conn: &mut PoolConnection<Sqlite>,
filter_uid: &ControllerUid,
) -> Result<Controller, DatabaseError> {
sqlx::query_as!(
Controller,
"SELECT * FROM controllers WHERE uid = ?",
filter_uid
)
.fetch_optional(conn.deref_mut())
.await
.map(|s| s.ok_or(DatabaseError::NotFound))?
}
pub async fn get_by_tag(
conn: &mut PoolConnection<Sqlite>,
tag: &Tag,
) -> Result<Vec<Controller>, DatabaseError> {
Ok(sqlx::query_as!(Controller, "SELECT schedule.* FROM controllers AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id)
.fetch_all(conn.deref_mut())
.await?)
}
pub async fn delete_by_uid(
conn: &mut PoolConnection<Sqlite>,
filter_uid: ControllerUid,
) -> Result<(), DatabaseError> {
sqlx::query!("DELETE FROM controllers WHERE uid = ?", filter_uid)
.execute(conn.deref_mut())
.await
.map(|res| match res.rows_affected() {
0 => Err(DatabaseError::DeleteError),
_ => Ok(()),
})?
}
pub async fn create(
conn: &mut PoolConnection<Sqlite>,
new_uid: &ControllerUid,
new_name: &str,
new_relay_count: i64,
new_active: bool
) -> Result<Controller, DatabaseError> {
sqlx::query_as!(
Controller,
"INSERT INTO controllers (uid, name, relay_count, active) VALUES (?, ?, ?, ?) RETURNING *",
new_uid,
new_name,
new_relay_count,
new_active,
)
.fetch_optional(conn.deref_mut())
.await?
.ok_or(DatabaseError::InsertGetError)
}
pub async fn update(
&self,
conn: &mut PoolConnection<Sqlite>,
new_name: &str,
new_relay_count: i64,
new_active: bool
) -> Result<Controller, DatabaseError> {
sqlx::query!(
"UPDATE controllers SET name = ?, relay_count = ?, active = ? WHERE id = ?",
new_name,
new_relay_count,
new_active,
self.id,
)
.execute(conn.deref_mut())
.await?;
Controller::get_by_uid(conn, &self.uid).await
}
}

View file

@ -6,17 +6,18 @@ use std::str::FromStr;
use crate::db::errors::DatabaseError;
use crate::db::model_utils::Period;
use crate::db::types::EmgauwaUid;
use crate::db::types::ScheduleUid;
// export for easier/flatter access
pub use crate::db::schedules::{Periods, Schedule};
pub(crate) mod errors;
pub mod errors;
mod model_utils;
mod models;
pub(crate) mod schedules;
pub(crate) mod tag;
pub mod schedules;
pub mod tag;
pub mod types;
pub mod controllers;
static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations"
@ -27,7 +28,7 @@ pub async fn run_migrations(pool: &Pool<Sqlite>) {
async fn init_schedule(
pool: &Pool<Sqlite>,
uid: &EmgauwaUid,
uid: &ScheduleUid,
name: &str,
periods: Periods,
) -> Result<(), DatabaseError> {
@ -68,13 +69,13 @@ pub async fn init(db: &str) -> Pool<Sqlite> {
run_migrations(&pool).await;
init_schedule(&pool, &EmgauwaUid::Off, "Off", Periods(vec![]))
init_schedule(&pool, &ScheduleUid::Off, "Off", Periods(vec![]))
.await
.expect("Error initializing schedule Off");
init_schedule(
&pool,
&EmgauwaUid::On,
&ScheduleUid::On,
"On",
Periods(vec![Period::new_on()]),
)

View file

@ -8,14 +8,14 @@ use sqlx::Sqlite;
use crate::db::errors::DatabaseError;
use crate::db::model_utils::Period;
use crate::db::tag::Tag;
use crate::db::types::EmgauwaUid;
use crate::db::types::ScheduleUid;
#[derive(Debug, Serialize, Clone)]
pub struct Schedule {
#[serde(skip)]
pub id: i64,
#[serde(rename(serialize = "id"))]
pub uid: EmgauwaUid,
pub uid: ScheduleUid,
pub name: String,
pub periods: Periods,
}
@ -32,9 +32,23 @@ impl Schedule {
.await?)
}
pub async fn get(
conn: &mut PoolConnection<Sqlite>,
id: &i64,
) -> Result<Schedule, DatabaseError> {
sqlx::query_as!(
Schedule,
"SELECT * FROM schedules WHERE id = ?",
id
)
.fetch_optional(conn.deref_mut())
.await
.map(|s| s.ok_or(DatabaseError::NotFound))?
}
pub async fn get_by_uid(
conn: &mut PoolConnection<Sqlite>,
filter_uid: &EmgauwaUid,
filter_uid: &ScheduleUid,
) -> Result<Schedule, DatabaseError> {
sqlx::query_as!(
Schedule,
@ -57,12 +71,12 @@ impl Schedule {
pub async fn delete_by_uid(
conn: &mut PoolConnection<Sqlite>,
filter_uid: EmgauwaUid,
filter_uid: ScheduleUid,
) -> Result<(), DatabaseError> {
let filter_uid = match filter_uid {
EmgauwaUid::Off => Err(DatabaseError::Protected),
EmgauwaUid::On => Err(DatabaseError::Protected),
EmgauwaUid::Any(_) => Ok(filter_uid),
ScheduleUid::Off => Err(DatabaseError::Protected),
ScheduleUid::On => Err(DatabaseError::Protected),
ScheduleUid::Any(_) => Ok(filter_uid),
}?;
sqlx::query!("DELETE FROM schedules WHERE uid = ?", filter_uid)
@ -79,7 +93,7 @@ impl Schedule {
new_name: &str,
new_periods: &Periods,
) -> Result<Schedule, DatabaseError> {
let uid = EmgauwaUid::default();
let uid = ScheduleUid::default();
sqlx::query_as!(
Schedule,
"INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *",
@ -100,8 +114,8 @@ impl Schedule {
) -> Result<Schedule, DatabaseError> {
// overwrite periods on protected schedules
let new_periods = match self.uid {
EmgauwaUid::Off | EmgauwaUid::On => self.periods.borrow(),
EmgauwaUid::Any(_) => new_periods,
ScheduleUid::Off | ScheduleUid::On => self.periods.borrow(),
ScheduleUid::Any(_) => new_periods,
};
sqlx::query!(

View file

@ -37,6 +37,16 @@ impl Tag {
}
pub async fn get(
conn: &mut PoolConnection<Sqlite>,
id: i64,
) -> Result<Tag, DatabaseError> {
sqlx::query_as!(Tag, "SELECT * FROM tags WHERE id = ?", id)
.fetch_optional(conn.deref_mut())
.await
.map(|t| t.ok_or(DatabaseError::NotFound))?
}
pub async fn get_by_tag(
conn: &mut PoolConnection<Sqlite>,
target_tag: &str,
) -> Result<Tag, DatabaseError> {

View file

@ -0,0 +1,62 @@
use serde::{Serialize, Serializer};
use sqlx::{Decode, Encode, Sqlite, Type};
use sqlx::database::HasArguments;
use sqlx::encode::IsNull;
use sqlx::error::BoxDynError;
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
use uuid::Uuid;
#[derive(Clone, Debug)]
pub struct ControllerUid(Uuid);
impl Serialize for ControllerUid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
String::from(self).serialize(serializer)
}
}
impl From<&ControllerUid> for String {
fn from(uid: &ControllerUid) -> String {
uid.0.as_hyphenated().to_string()
}
}
impl Type<Sqlite> for ControllerUid {
fn type_info() -> SqliteTypeInfo {
<&[u8] as Type<Sqlite>>::type_info()
}
fn compatible(ty: &SqliteTypeInfo) -> bool {
<&[u8] as Type<Sqlite>>::compatible(ty)
}
}
impl<'q> Encode<'q, Sqlite> for ControllerUid {
//noinspection DuplicatedCode
fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
let uuid_val = self.0.as_bytes().to_vec();
<&Vec<u8> as Encode<Sqlite>>::encode(&uuid_val, buf)
}
}
impl<'r> Decode<'r, Sqlite> for ControllerUid {
//noinspection DuplicatedCode
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
Ok(Self::from(<&[u8] as Decode<Sqlite>>::decode(value)?))
}
}
impl From<&[u8]> for ControllerUid {
fn from(value: &[u8]) -> Self {
Self(Uuid::from_slice(&value).unwrap())
}
}
impl From<Vec<u8>> for ControllerUid {
fn from(value: Vec<u8>) -> Self {
Self::from(value.as_slice())
}
}

View file

@ -1,146 +0,0 @@
use std::convert::TryFrom;
use std::fmt::{Debug, Formatter};
use std::str::FromStr;
use serde::{Serialize, Serializer};
use sqlx::database::HasArguments;
use sqlx::encode::IsNull;
use sqlx::error::BoxDynError;
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
use sqlx::{Decode, Encode, Sqlite, Type};
use uuid::Uuid;
#[derive(Clone)]
pub enum EmgauwaUid {
Off,
On,
Any(Uuid),
}
impl EmgauwaUid {
const OFF_STR: &'static str = "off";
const ON_STR: &'static str = "on";
const OFF_U8: u8 = 0;
const ON_U8: u8 = 1;
const OFF_U128: u128 = 0;
const ON_U128: u128 = 1;
}
impl Default for EmgauwaUid {
fn default() -> Self {
EmgauwaUid::Any(Uuid::new_v4())
}
}
impl Debug for EmgauwaUid {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
EmgauwaUid::Off => EmgauwaUid::OFF_STR.fmt(f),
EmgauwaUid::On => EmgauwaUid::ON_STR.fmt(f),
EmgauwaUid::Any(value) => value.fmt(f),
}
}
}
impl Type<Sqlite> for EmgauwaUid {
fn type_info() -> SqliteTypeInfo {
<&[u8] as Type<Sqlite>>::type_info()
}
fn compatible(ty: &SqliteTypeInfo) -> bool {
<&[u8] as Type<Sqlite>>::compatible(ty)
}
}
impl<'q> Encode<'q, Sqlite> for EmgauwaUid {
//noinspection DuplicatedCode
fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
<&Vec<u8> as Encode<Sqlite>>::encode(&Vec::from(self), buf)
}
}
impl<'r> Decode<'r, Sqlite> for EmgauwaUid {
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
Ok(EmgauwaUid::from(<&[u8] as Decode<Sqlite>>::decode(value)?))
}
}
impl Serialize for EmgauwaUid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
String::from(self).serialize(serializer)
}
}
impl From<Uuid> for EmgauwaUid {
fn from(uid: Uuid) -> EmgauwaUid {
match uid.as_u128() {
EmgauwaUid::OFF_U128 => EmgauwaUid::Off,
EmgauwaUid::ON_U128 => EmgauwaUid::On,
_ => EmgauwaUid::Any(uid),
}
}
}
impl TryFrom<&str> for EmgauwaUid {
type Error = uuid::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
EmgauwaUid::OFF_STR => Ok(EmgauwaUid::Off),
EmgauwaUid::ON_STR => Ok(EmgauwaUid::On),
any => match Uuid::from_str(any) {
Ok(uuid) => Ok(EmgauwaUid::Any(uuid)),
Err(err) => Err(err),
},
}
}
}
impl From<&EmgauwaUid> for Uuid {
fn from(emgauwa_uid: &EmgauwaUid) -> Uuid {
match emgauwa_uid {
EmgauwaUid::Off => Uuid::from_u128(EmgauwaUid::OFF_U128),
EmgauwaUid::On => Uuid::from_u128(EmgauwaUid::ON_U128),
EmgauwaUid::Any(value) => *value,
}
}
}
impl From<&EmgauwaUid> for String {
fn from(emgauwa_uid: &EmgauwaUid) -> String {
match emgauwa_uid {
EmgauwaUid::Off => String::from(EmgauwaUid::OFF_STR),
EmgauwaUid::On => String::from(EmgauwaUid::ON_STR),
EmgauwaUid::Any(value) => value.as_hyphenated().to_string(),
}
}
}
impl From<&EmgauwaUid> for Vec<u8> {
fn from(emgauwa_uid: &EmgauwaUid) -> Vec<u8> {
match emgauwa_uid {
EmgauwaUid::Off => vec![EmgauwaUid::OFF_U8],
EmgauwaUid::On => vec![EmgauwaUid::ON_U8],
EmgauwaUid::Any(value) => value.as_bytes().to_vec(),
}
}
}
impl From<&[u8]> for EmgauwaUid {
fn from(value: &[u8]) -> Self {
match value {
[EmgauwaUid::OFF_U8] => EmgauwaUid::Off,
[EmgauwaUid::ON_U8] => EmgauwaUid::On,
value_bytes => EmgauwaUid::Any(Uuid::from_slice(value_bytes).unwrap()),
}
}
}
impl From<Vec<u8>> for EmgauwaUid {
fn from(value: Vec<u8>) -> Self {
EmgauwaUid::from(value.as_slice())
}
}

View file

@ -1,2 +1,5 @@
pub mod emgauwa_uid;
pub use emgauwa_uid::EmgauwaUid;
mod schedule_uid;
mod controller_uid;
pub use schedule_uid::ScheduleUid;
pub use controller_uid::ControllerUid;

View file

@ -0,0 +1,147 @@
use std::convert::TryFrom;
use std::fmt::{Debug, Formatter};
use std::str::FromStr;
use serde::{Serialize, Serializer};
use sqlx::database::HasArguments;
use sqlx::encode::IsNull;
use sqlx::error::BoxDynError;
use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef};
use sqlx::{Decode, Encode, Sqlite, Type};
use uuid::Uuid;
#[derive(Clone)]
pub enum ScheduleUid {
Off,
On,
Any(Uuid),
}
impl ScheduleUid {
const OFF_STR: &'static str = "off";
const ON_STR: &'static str = "on";
const OFF_U8: u8 = 0;
const ON_U8: u8 = 1;
const OFF_U128: u128 = 0;
const ON_U128: u128 = 1;
}
impl Default for ScheduleUid {
fn default() -> Self {
Self::Any(Uuid::new_v4())
}
}
impl Debug for ScheduleUid {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Off => Self::OFF_STR.fmt(f),
Self::On => Self::ON_STR.fmt(f),
Self::Any(value) => value.fmt(f),
}
}
}
impl Type<Sqlite> for ScheduleUid {
fn type_info() -> SqliteTypeInfo {
<&[u8] as Type<Sqlite>>::type_info()
}
fn compatible(ty: &SqliteTypeInfo) -> bool {
<&[u8] as Type<Sqlite>>::compatible(ty)
}
}
impl<'q> Encode<'q, Sqlite> for ScheduleUid {
//noinspection DuplicatedCode
fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
<&Vec<u8> as Encode<Sqlite>>::encode(&Vec::from(self), buf)
}
}
impl<'r> Decode<'r, Sqlite> for ScheduleUid {
//noinspection DuplicatedCode
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
Ok(Self::from(<&[u8] as Decode<Sqlite>>::decode(value)?))
}
}
impl Serialize for ScheduleUid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
String::from(self).serialize(serializer)
}
}
impl From<Uuid> for ScheduleUid {
fn from(uid: Uuid) -> Self {
match uid.as_u128() {
Self::OFF_U128 => Self::Off,
Self::ON_U128 => Self::On,
_ => Self::Any(uid),
}
}
}
impl TryFrom<&str> for ScheduleUid {
type Error = uuid::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
Self::OFF_STR => Ok(Self::Off),
Self::ON_STR => Ok(Self::On),
any => match Uuid::from_str(any) {
Ok(uuid) => Ok(Self::Any(uuid)),
Err(err) => Err(err),
},
}
}
}
impl From<&ScheduleUid> for Uuid {
fn from(uid: &ScheduleUid) -> Uuid {
match uid {
ScheduleUid::Off => Uuid::from_u128(ScheduleUid::OFF_U128),
ScheduleUid::On => Uuid::from_u128(ScheduleUid::ON_U128),
ScheduleUid::Any(value) => *value,
}
}
}
impl From<&ScheduleUid> for String {
fn from(uid: &ScheduleUid) -> String {
match uid {
ScheduleUid::Off => String::from(ScheduleUid::OFF_STR),
ScheduleUid::On => String::from(ScheduleUid::ON_STR),
ScheduleUid::Any(value) => value.as_hyphenated().to_string(),
}
}
}
impl From<&ScheduleUid> for Vec<u8> {
fn from(uid: &ScheduleUid) -> Vec<u8> {
match uid {
ScheduleUid::Off => vec![ScheduleUid::OFF_U8],
ScheduleUid::On => vec![ScheduleUid::ON_U8],
ScheduleUid::Any(value) => value.as_bytes().to_vec(),
}
}
}
impl From<&[u8]> for ScheduleUid {
fn from(value: &[u8]) -> Self {
match value {
[Self::OFF_U8] => Self::Off,
[Self::ON_U8] => Self::On,
value_bytes => Self::Any(Uuid::from_slice(value_bytes).unwrap()),
}
}
}
impl From<Vec<u8>> for ScheduleUid {
fn from(value: Vec<u8>) -> Self {
Self::from(value.as_slice())
}
}

View file

@ -6,7 +6,7 @@ use sqlx::{Pool, Sqlite};
use crate::db::errors::DatabaseError;
use crate::db::{Periods, Schedule};
use crate::db::tag::Tag;
use crate::db::types::EmgauwaUid;
use crate::db::types::ScheduleUid;
use crate::handlers::errors::ApiError;
use crate::return_models::ReturnSchedule;
use crate::utils::vec_has_error;
@ -41,7 +41,7 @@ pub async fn tagged(
let mut pool_conn = pool.acquire().await?;
let (tag,) = path.into_inner();
let tag_db = Tag::get(&mut pool_conn, &tag).await?;
let tag_db = Tag::get_by_tag(&mut pool_conn, &tag).await?;
let schedules = Schedule::get_by_tag(&mut pool_conn, &tag_db).await?;
@ -61,9 +61,9 @@ pub async fn show(
let mut pool_conn = pool.acquire().await?;
let (schedule_uid,) = path.into_inner();
let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?;
let uid = ScheduleUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?;
let schedule = Schedule::get_by_uid(&mut pool_conn, &emgauwa_uid).await?;
let schedule = Schedule::get_by_uid(&mut pool_conn, &uid).await?;
let mut return_schedule = ReturnSchedule::from(schedule);
return_schedule.load_tags(&mut pool_conn);
@ -148,9 +148,9 @@ pub async fn update(
let mut pool_conn = pool.acquire().await?;
let (schedule_uid,) = path.into_inner();
let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?;
let uid = ScheduleUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?;
let schedule = Schedule::get_by_uid(&mut pool_conn, &emgauwa_uid).await?;
let schedule = Schedule::get_by_uid(&mut pool_conn, &uid).await?;
let schedule = schedule
.update(&mut pool_conn, data.name.as_str(), &data.periods)
@ -173,13 +173,13 @@ pub async fn delete(
let mut pool_conn = pool.acquire().await?;
let (schedule_uid,) = path.into_inner();
let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?;
let uid = ScheduleUid::try_from(schedule_uid.as_str()).or(Err(ApiError::BadUid))?;
match emgauwa_uid {
EmgauwaUid::Off => Err(ApiError::ProtectedSchedule),
EmgauwaUid::On => Err(ApiError::ProtectedSchedule),
EmgauwaUid::Any(_) => {
Schedule::delete_by_uid(&mut pool_conn, emgauwa_uid).await?;
match uid {
ScheduleUid::Off => Err(ApiError::ProtectedSchedule),
ScheduleUid::On => Err(ApiError::ProtectedSchedule),
ScheduleUid::Any(_) => {
Schedule::delete_by_uid(&mut pool_conn, uid).await?;
Ok(HttpResponse::Ok().json("schedule got deleted"))
}
}

View file

@ -6,18 +6,15 @@ CREATE TABLE controllers
AUTOINCREMENT
NOT NULL,
uid
VARCHAR(36)
BLOB
NOT NULL
UNIQUE,
name
VARCHAR(128)
NOT NULL,
ip
VARCHAR(16),
port
INTEGER,
relay_count
INTEGER,
INTEGER
NOT NULL,
active
BOOLEAN
NOT NULL