Add saving periods
This commit is contained in:
		
							parent
							
								
									12d57d020f
								
							
						
					
					
						commit
						483fd60daa
					
				
					 13 changed files with 271 additions and 52 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -9,3 +9,4 @@ emgauwa-core.sqlite
 | 
				
			||||||
# Added by cargo
 | 
					# Added by cargo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/target
 | 
					/target
 | 
				
			||||||
 | 
					/api.http
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										50
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										50
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -81,7 +81,7 @@ dependencies = [
 | 
				
			||||||
 "serde_urlencoded",
 | 
					 "serde_urlencoded",
 | 
				
			||||||
 "sha-1",
 | 
					 "sha-1",
 | 
				
			||||||
 "slab",
 | 
					 "slab",
 | 
				
			||||||
 "time",
 | 
					 "time 0.2.27",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					@ -247,7 +247,7 @@ dependencies = [
 | 
				
			||||||
 "serde_json",
 | 
					 "serde_json",
 | 
				
			||||||
 "serde_urlencoded",
 | 
					 "serde_urlencoded",
 | 
				
			||||||
 "socket2",
 | 
					 "socket2",
 | 
				
			||||||
 "time",
 | 
					 "time 0.2.27",
 | 
				
			||||||
 "tinyvec",
 | 
					 "tinyvec",
 | 
				
			||||||
 "url",
 | 
					 "url",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
| 
						 | 
					@ -417,6 +417,20 @@ version = "1.0.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 | 
					checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "chrono"
 | 
				
			||||||
 | 
					version = "0.4.19"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "num-integer",
 | 
				
			||||||
 | 
					 "num-traits",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 | 
					 "time 0.1.43",
 | 
				
			||||||
 | 
					 "winapi 0.3.9",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "const_fn"
 | 
					name = "const_fn"
 | 
				
			||||||
version = "0.4.8"
 | 
					version = "0.4.8"
 | 
				
			||||||
| 
						 | 
					@ -436,7 +450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951"
 | 
					checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "percent-encoding",
 | 
					 "percent-encoding",
 | 
				
			||||||
 "time",
 | 
					 "time 0.2.27",
 | 
				
			||||||
 "version_check",
 | 
					 "version_check",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -542,6 +556,7 @@ name = "emgauwa-core"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "actix-web",
 | 
					 "actix-web",
 | 
				
			||||||
 | 
					 "chrono",
 | 
				
			||||||
 "diesel",
 | 
					 "diesel",
 | 
				
			||||||
 "diesel_migrations",
 | 
					 "diesel_migrations",
 | 
				
			||||||
 "dotenv",
 | 
					 "dotenv",
 | 
				
			||||||
| 
						 | 
					@ -1047,6 +1062,25 @@ dependencies = [
 | 
				
			||||||
 "winapi 0.3.9",
 | 
					 "winapi 0.3.9",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "num-integer"
 | 
				
			||||||
 | 
					version = "0.1.44"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "autocfg",
 | 
				
			||||||
 | 
					 "num-traits",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "num-traits"
 | 
				
			||||||
 | 
					version = "0.2.14"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "autocfg",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "num_cpus"
 | 
					name = "num_cpus"
 | 
				
			||||||
version = "1.13.0"
 | 
					version = "1.13.0"
 | 
				
			||||||
| 
						 | 
					@ -1541,6 +1575,16 @@ dependencies = [
 | 
				
			||||||
 "num_cpus",
 | 
					 "num_cpus",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "time"
 | 
				
			||||||
 | 
					version = "0.1.43"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "winapi 0.3.9",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "time"
 | 
					name = "time"
 | 
				
			||||||
version = "0.2.27"
 | 
					version = "0.2.27"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ authors = ["Tobias Reisinger <tobias@msrg.cc>"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
actix-web = "3"
 | 
					actix-web = "3"
 | 
				
			||||||
 | 
					chrono = { version = "0.4", features = ["serde"] }
 | 
				
			||||||
diesel = { version = "1.4", features = ["sqlite", "uuid"] }
 | 
					diesel = { version = "1.4", features = ["sqlite", "uuid"] }
 | 
				
			||||||
diesel_migrations = "1.4"
 | 
					diesel_migrations = "1.4"
 | 
				
			||||||
dotenv = "0.15"
 | 
					dotenv = "0.15"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,13 +41,13 @@ CREATE TABLE schedules
 | 
				
			||||||
            UNIQUE,
 | 
					            UNIQUE,
 | 
				
			||||||
    name    VARCHAR(128)
 | 
					    name    VARCHAR(128)
 | 
				
			||||||
            NOT NULL,
 | 
					            NOT NULL,
 | 
				
			||||||
    periods TEXT
 | 
					    periods BLOB
 | 
				
			||||||
            NOT NULL
 | 
					            NOT NULL
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
--INSERT INTO schedules (uid, name, periods) VALUES (x'6f666600000000000000000000000000', 'off', x'00');
 | 
					--INSERT INTO schedules (uid, name, periods) VALUES (x'6f666600000000000000000000000000', 'off', x'00');
 | 
				
			||||||
--INSERT INTO schedules (uid, name, periods) VALUES (x'6f6e0000000000000000000000000000',  'on', x'010000009F05');
 | 
					--INSERT INTO schedules (uid, name, periods) VALUES (x'6f6e0000000000000000000000000000',  'on', x'010000009F05');
 | 
				
			||||||
INSERT INTO schedules (uid, name, periods) VALUES (x'00', 'off', '00');
 | 
					INSERT INTO schedules (uid, name, periods) VALUES (x'00', 'off', x'');
 | 
				
			||||||
INSERT INTO schedules (uid, name, periods) VALUES (x'01',  'on', '010000009F05');
 | 
					INSERT INTO schedules (uid, name, periods) VALUES (x'01',  'on', x'0000173B');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CREATE TABLE tags
 | 
					CREATE TABLE tags
 | 
				
			||||||
(
 | 
					(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										41
									
								
								src/db.rs
									
										
									
									
									
								
							
							
						
						
									
										41
									
								
								src/db.rs
									
										
									
									
									
								
							| 
						 | 
					@ -1,20 +1,18 @@
 | 
				
			||||||
 | 
					use std::env;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use diesel::dsl::sql;
 | 
				
			||||||
 | 
					use diesel::prelude::*;
 | 
				
			||||||
 | 
					use diesel_migrations::embed_migrations;
 | 
				
			||||||
 | 
					use dotenv::dotenv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use errors::DatabaseError;
 | 
				
			||||||
 | 
					use models::*;
 | 
				
			||||||
 | 
					use schema::schedules::dsl::*;
 | 
				
			||||||
 | 
					use crate::types::EmgauwaUid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod errors;
 | 
					pub mod errors;
 | 
				
			||||||
pub mod models;
 | 
					pub mod models;
 | 
				
			||||||
pub mod schema;
 | 
					pub mod schema;
 | 
				
			||||||
mod types;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use diesel::prelude::*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use diesel::dsl::sql;
 | 
					 | 
				
			||||||
use dotenv::dotenv;
 | 
					 | 
				
			||||||
use std::env;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use models::*;
 | 
					 | 
				
			||||||
use schema::schedules::dsl::*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use diesel_migrations::embed_migrations;
 | 
					 | 
				
			||||||
use errors::DatabaseError;
 | 
					 | 
				
			||||||
use types::EmgauwaUid;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
embed_migrations!("migrations");
 | 
					embed_migrations!("migrations");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,18 +32,27 @@ pub fn run_migrations() {
 | 
				
			||||||
pub fn get_schedules() -> Vec<Schedule> {
 | 
					pub fn get_schedules() -> Vec<Schedule> {
 | 
				
			||||||
    let connection = get_connection();
 | 
					    let connection = get_connection();
 | 
				
			||||||
    schedules
 | 
					    schedules
 | 
				
			||||||
        .limit(5)
 | 
					 | 
				
			||||||
        .load::<Schedule>(&connection)
 | 
					        .load::<Schedule>(&connection)
 | 
				
			||||||
        .expect("Error loading schedules")
 | 
					        .expect("Error loading schedules")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn create_schedule(new_name: &str) -> Result<Schedule, DatabaseError> {
 | 
					pub fn get_schedule_by_uid(filter_uid: EmgauwaUid) -> Result<Schedule, DatabaseError> {
 | 
				
			||||||
 | 
					    let connection = get_connection();
 | 
				
			||||||
 | 
					    let result = schedules
 | 
				
			||||||
 | 
					        .filter(uid.eq(filter_uid))
 | 
				
			||||||
 | 
					        .first::<Schedule>(&connection)
 | 
				
			||||||
 | 
					        .or(Err(DatabaseError::NotFound))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(result)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn create_schedule(new_name: &str, new_periods: &Periods) -> Result<Schedule, DatabaseError> {
 | 
				
			||||||
    let connection = get_connection();
 | 
					    let connection = get_connection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let new_schedule = NewSchedule {
 | 
					    let new_schedule = NewSchedule {
 | 
				
			||||||
        uid: &EmgauwaUid::default(),
 | 
					        uid: &EmgauwaUid::default(),
 | 
				
			||||||
        name: new_name,
 | 
					        name: new_name,
 | 
				
			||||||
        periods: "",
 | 
					        periods: new_periods
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    diesel::insert_into(schedules)
 | 
					    diesel::insert_into(schedules)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,16 @@ use serde::{Serialize, Serializer};
 | 
				
			||||||
pub enum DatabaseError {
 | 
					pub enum DatabaseError {
 | 
				
			||||||
    InsertError,
 | 
					    InsertError,
 | 
				
			||||||
    InsertGetError,
 | 
					    InsertGetError,
 | 
				
			||||||
 | 
					    NotFound,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl DatabaseError {
 | 
				
			||||||
 | 
					    fn to_code(&self) -> u32 {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            DatabaseError::NotFound => 404,
 | 
				
			||||||
 | 
					            _ => 500
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Serialize for DatabaseError {
 | 
					impl Serialize for DatabaseError {
 | 
				
			||||||
| 
						 | 
					@ -11,8 +21,9 @@ impl Serialize for DatabaseError {
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        S: Serializer,
 | 
					        S: Serializer,
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        let mut s = serializer.serialize_struct("error", 2)?;
 | 
					        let mut s = serializer.serialize_struct("error", 3)?;
 | 
				
			||||||
        s.serialize_field("code", &500)?;
 | 
					        s.serialize_field("type", "database-error")?;
 | 
				
			||||||
 | 
					        s.serialize_field("code", &self.to_code())?;
 | 
				
			||||||
        s.serialize_field("description", &String::from(self))?;
 | 
					        s.serialize_field("description", &String::from(self))?;
 | 
				
			||||||
        s.end()
 | 
					        s.end()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -25,6 +36,7 @@ impl From<&DatabaseError> for String {
 | 
				
			||||||
            DatabaseError::InsertGetError => {
 | 
					            DatabaseError::InsertGetError => {
 | 
				
			||||||
                String::from("error retrieving new entry from database (your entry was saved)")
 | 
					                String::from("error retrieving new entry from database (your entry was saved)")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            DatabaseError::NotFound => String::from("model was not found in database")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,24 @@
 | 
				
			||||||
use super::types::EmgauwaUid;
 | 
					use chrono::{NaiveTime, Timelike};
 | 
				
			||||||
use serde::Serialize;
 | 
					use diesel::backend::Backend;
 | 
				
			||||||
 | 
					use diesel::deserialize::FromSql;
 | 
				
			||||||
 | 
					use diesel::serialize::{IsNull, Output, ToSql};
 | 
				
			||||||
 | 
					use diesel::sql_types::Binary;
 | 
				
			||||||
 | 
					use diesel::sqlite::Sqlite;
 | 
				
			||||||
 | 
					use diesel::{deserialize, serialize};
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					use std::io::Write;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::schema::schedules;
 | 
					use super::schema::schedules;
 | 
				
			||||||
 | 
					use crate::types::EmgauwaUid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Queryable)]
 | 
					#[derive(Serialize, Queryable)]
 | 
				
			||||||
pub struct Schedule {
 | 
					pub struct Schedule {
 | 
				
			||||||
 | 
					    #[serde(skip)]
 | 
				
			||||||
    pub id: i32,
 | 
					    pub id: i32,
 | 
				
			||||||
 | 
					    #[serde(alias = "id")]
 | 
				
			||||||
    pub uid: EmgauwaUid,
 | 
					    pub uid: EmgauwaUid,
 | 
				
			||||||
    pub name: String,
 | 
					    pub name: String,
 | 
				
			||||||
    pub periods: String,
 | 
					    pub periods: Periods,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Insertable)]
 | 
					#[derive(Insertable)]
 | 
				
			||||||
| 
						 | 
					@ -16,5 +26,74 @@ pub struct Schedule {
 | 
				
			||||||
pub struct NewSchedule<'a> {
 | 
					pub struct NewSchedule<'a> {
 | 
				
			||||||
    pub uid: &'a EmgauwaUid,
 | 
					    pub uid: &'a EmgauwaUid,
 | 
				
			||||||
    pub name: &'a str,
 | 
					    pub name: &'a str,
 | 
				
			||||||
    pub periods: &'a str,
 | 
					    pub periods: &'a Periods,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Serialize, Deserialize, AsExpression, FromSqlRow, PartialEq, Clone)]
 | 
				
			||||||
 | 
					#[sql_type = "Binary"]
 | 
				
			||||||
 | 
					pub struct Period {
 | 
				
			||||||
 | 
					    #[serde(with = "period_format")]
 | 
				
			||||||
 | 
					    pub start: NaiveTime,
 | 
				
			||||||
 | 
					    #[serde(with = "period_format")]
 | 
				
			||||||
 | 
					    pub end: NaiveTime,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Serialize, Deserialize, AsExpression, FromSqlRow, PartialEq, Clone)]
 | 
				
			||||||
 | 
					#[sql_type = "Binary"]
 | 
				
			||||||
 | 
					pub struct Periods(pub(crate) Vec<Period>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod period_format {
 | 
				
			||||||
 | 
					    use chrono::NaiveTime;
 | 
				
			||||||
 | 
					    use serde::{self, Deserialize, Deserializer, Serializer};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const FORMAT: &'static str = "%H:%M";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn serialize<S>(time: &NaiveTime, serializer: S) -> Result<S::Ok, S::Error>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        S: Serializer,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let s = format!("{}", time.format(FORMAT));
 | 
				
			||||||
 | 
					        serializer.serialize_str(&s)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn deserialize<'de, D>(deserializer: D) -> Result<NaiveTime, D::Error>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        D: Deserializer<'de>,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let s = String::deserialize(deserializer)?;
 | 
				
			||||||
 | 
					        NaiveTime::parse_from_str(&s, FORMAT).map_err(serde::de::Error::custom)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ToSql<Binary, Sqlite> for Periods {
 | 
				
			||||||
 | 
					    fn to_sql<W: Write>(&self, out: &mut Output<W, Sqlite>) -> serialize::Result {
 | 
				
			||||||
 | 
					        for period in self.0.iter() {
 | 
				
			||||||
 | 
					            out.write_all(&[
 | 
				
			||||||
 | 
					                period.start.hour() as u8,
 | 
				
			||||||
 | 
					                period.start.minute() as u8,
 | 
				
			||||||
 | 
					                period.end.hour() as u8,
 | 
				
			||||||
 | 
					                period.end.minute() as u8,
 | 
				
			||||||
 | 
					            ])?;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(IsNull::No)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl FromSql<Binary, Sqlite> for Periods {
 | 
				
			||||||
 | 
					    fn from_sql(bytes: Option<&<Sqlite as Backend>::RawValue>) -> deserialize::Result<Self> {
 | 
				
			||||||
 | 
					        let blob =  bytes.unwrap().read_blob();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut vec = Vec::new();
 | 
				
			||||||
 | 
					        for i in (3..blob.len()).step_by(4) {
 | 
				
			||||||
 | 
					            let start_val_h: u32 = blob[i - 3] as u32;
 | 
				
			||||||
 | 
					            let start_val_m: u32 = blob[i - 2] as u32;
 | 
				
			||||||
 | 
					            let end_val_h: u32 = blob[i - 1] as u32;
 | 
				
			||||||
 | 
					            let end_val_m: u32 = blob[i - 0] as u32;
 | 
				
			||||||
 | 
					            vec.push(Period {
 | 
				
			||||||
 | 
					                start: NaiveTime::from_hms(start_val_h, start_val_m, 0),
 | 
				
			||||||
 | 
					                end: NaiveTime::from_hms(end_val_h, end_val_m, 0),
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(Periods(vec))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,7 +60,7 @@ table! {
 | 
				
			||||||
        id -> Integer,
 | 
					        id -> Integer,
 | 
				
			||||||
        uid -> Binary,
 | 
					        uid -> Binary,
 | 
				
			||||||
        name -> Text,
 | 
					        name -> Text,
 | 
				
			||||||
        periods -> Text,
 | 
					        periods -> Binary,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								src/handlers/errors.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/handlers/errors.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					use serde::ser::SerializeStruct;
 | 
				
			||||||
 | 
					use serde::{Serialize, Serializer};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum HandlerError {
 | 
				
			||||||
 | 
					    BadUidError,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl HandlerError {
 | 
				
			||||||
 | 
					    fn to_code(&self) -> u32 {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            HandlerError::BadUidError => 400
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Serialize for HandlerError {
 | 
				
			||||||
 | 
					    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 | 
				
			||||||
 | 
					        where
 | 
				
			||||||
 | 
					            S: Serializer,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let mut s = serializer.serialize_struct("error", 2)?;
 | 
				
			||||||
 | 
					        s.serialize_field("code", &self.to_code())?;
 | 
				
			||||||
 | 
					        s.serialize_field("description", &String::from(self))?;
 | 
				
			||||||
 | 
					        s.end()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<&HandlerError> for String {
 | 
				
			||||||
 | 
					    fn from(err: &HandlerError) -> Self {
 | 
				
			||||||
 | 
					        match err {
 | 
				
			||||||
 | 
					            HandlerError::BadUidError => String::from("the uid is in a bad format"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1 +1,2 @@
 | 
				
			||||||
pub mod v1;
 | 
					pub mod v1;
 | 
				
			||||||
 | 
					mod errors;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,58 @@
 | 
				
			||||||
 | 
					use std::str::FromStr;
 | 
				
			||||||
 | 
					use actix_web::{HttpResponse, Responder, web, get};
 | 
				
			||||||
 | 
					use serde::{Serialize, Deserialize};
 | 
				
			||||||
 | 
					use uuid::Uuid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::db;
 | 
					use crate::db;
 | 
				
			||||||
use actix_web::{HttpResponse, Responder};
 | 
					use crate::db::models::Periods;
 | 
				
			||||||
 | 
					use crate::handlers::errors::HandlerError;
 | 
				
			||||||
 | 
					use crate::types::EmgauwaUid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct RequestSchedule {
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					    periods: Periods,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn index() -> impl Responder {
 | 
					pub async fn index() -> impl Responder {
 | 
				
			||||||
    let schedules = db::get_schedules();
 | 
					    let schedules = db::get_schedules();
 | 
				
			||||||
    HttpResponse::Ok().json(schedules)
 | 
					    HttpResponse::Ok().json(schedules)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn get() -> impl Responder {
 | 
					#[get("/api/v1/schedules/{schedule_id}")]
 | 
				
			||||||
    "hello from get schedules by id"
 | 
					pub async fn show(web::Path((schedule_uid,)): web::Path<(String,)>) -> impl Responder {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let emgauwa_uid = match schedule_uid.as_str() {
 | 
				
			||||||
 | 
					        "on" => Ok(EmgauwaUid::On),
 | 
				
			||||||
 | 
					        "off" => Ok(EmgauwaUid::Off),
 | 
				
			||||||
 | 
					        any => match Uuid::from_str(any) {
 | 
				
			||||||
 | 
					            Ok(uuid) => Ok(EmgauwaUid::Any(uuid)),
 | 
				
			||||||
 | 
					            Err(_) => Err(HandlerError::BadUidError)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    match emgauwa_uid {
 | 
				
			||||||
 | 
					        Ok(uid) => {
 | 
				
			||||||
 | 
					            let schedule = db::get_schedule_by_uid(uid);
 | 
				
			||||||
 | 
					            match schedule {
 | 
				
			||||||
 | 
					                Ok(ok) => HttpResponse::Ok().json(ok),
 | 
				
			||||||
 | 
					                Err(err) => HttpResponse::NotFound().json(err),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        Err(err) => HttpResponse::BadRequest().json(err)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn add() -> impl Responder {
 | 
					}
 | 
				
			||||||
    let new_schedule = db::create_schedule("TEST");
 | 
					
 | 
				
			||||||
 | 
					pub async fn add(post: web::Json<RequestSchedule>) -> impl Responder {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    println!("model: {:?}", post);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for period in post.periods.0.iter() {
 | 
				
			||||||
 | 
					        println!("start: {:?}; end: {:?}", period.start, period.end);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let new_schedule = db::create_schedule(&post.name, &post.periods);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    match new_schedule {
 | 
					    match new_schedule {
 | 
				
			||||||
        Ok(ok) => HttpResponse::Ok().json(ok),
 | 
					        Ok(ok) => HttpResponse::Ok().json(ok),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								src/main.rs
									
										
									
									
									
								
							| 
						 | 
					@ -1,13 +1,14 @@
 | 
				
			||||||
mod db;
 | 
					 | 
				
			||||||
mod handlers;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[macro_use]
 | 
					#[macro_use]
 | 
				
			||||||
extern crate diesel;
 | 
					extern crate diesel;
 | 
				
			||||||
#[macro_use]
 | 
					#[macro_use]
 | 
				
			||||||
extern crate diesel_migrations;
 | 
					extern crate diesel_migrations;
 | 
				
			||||||
extern crate dotenv;
 | 
					extern crate dotenv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use actix_web::{web, App, HttpServer};
 | 
					use actix_web::{App, HttpServer, web};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod db;
 | 
				
			||||||
 | 
					mod handlers;
 | 
				
			||||||
 | 
					mod types;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[actix_web::main]
 | 
					#[actix_web::main]
 | 
				
			||||||
async fn main() -> std::io::Result<()> {
 | 
					async fn main() -> std::io::Result<()> {
 | 
				
			||||||
| 
						 | 
					@ -23,10 +24,7 @@ async fn main() -> std::io::Result<()> {
 | 
				
			||||||
                "/api/v1/schedules",
 | 
					                "/api/v1/schedules",
 | 
				
			||||||
                web::post().to(handlers::v1::schedules::add),
 | 
					                web::post().to(handlers::v1::schedules::add),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            .route(
 | 
					            .service(handlers::v1::schedules::show)
 | 
				
			||||||
                "/api/v1/schedules/{id}",
 | 
					 | 
				
			||||||
                web::get().to(handlers::v1::schedules::get),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            .route(
 | 
					            .route(
 | 
				
			||||||
                "/api/v1/schedules/{id}",
 | 
					                "/api/v1/schedules/{id}",
 | 
				
			||||||
                web::delete().to(handlers::v1::schedules::delete),
 | 
					                web::delete().to(handlers::v1::schedules::delete),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,6 @@
 | 
				
			||||||
 | 
					use std::fmt::{Debug, Formatter};
 | 
				
			||||||
 | 
					use std::io::Write;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use diesel::backend::Backend;
 | 
					use diesel::backend::Backend;
 | 
				
			||||||
use diesel::deserialize::FromSql;
 | 
					use diesel::deserialize::FromSql;
 | 
				
			||||||
use diesel::serialize::{IsNull, Output, ToSql};
 | 
					use diesel::serialize::{IsNull, Output, ToSql};
 | 
				
			||||||
| 
						 | 
					@ -5,8 +8,6 @@ use diesel::sql_types::Binary;
 | 
				
			||||||
use diesel::sqlite::Sqlite;
 | 
					use diesel::sqlite::Sqlite;
 | 
				
			||||||
use diesel::{deserialize, serialize};
 | 
					use diesel::{deserialize, serialize};
 | 
				
			||||||
use serde::{Serialize, Serializer};
 | 
					use serde::{Serialize, Serializer};
 | 
				
			||||||
use std::fmt::{Debug, Formatter};
 | 
					 | 
				
			||||||
use std::io::Write;
 | 
					 | 
				
			||||||
use uuid::Uuid;
 | 
					use uuid::Uuid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(AsExpression, FromSqlRow, PartialEq, Clone)]
 | 
					#[derive(AsExpression, FromSqlRow, PartialEq, Clone)]
 | 
				
			||||||
| 
						 | 
					@ -22,6 +23,7 @@ impl Default for EmgauwaUid {
 | 
				
			||||||
        EmgauwaUid::Any(Uuid::new_v4())
 | 
					        EmgauwaUid::Any(Uuid::new_v4())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Debug for EmgauwaUid {
 | 
					impl Debug for EmgauwaUid {
 | 
				
			||||||
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
 | 
					    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
| 
						 | 
					@ -31,6 +33,7 @@ impl Debug for EmgauwaUid {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ToSql<Binary, Sqlite> for EmgauwaUid {
 | 
					impl ToSql<Binary, Sqlite> for EmgauwaUid {
 | 
				
			||||||
    fn to_sql<W: Write>(&self, out: &mut Output<W, Sqlite>) -> serialize::Result {
 | 
					    fn to_sql<W: Write>(&self, out: &mut Output<W, Sqlite>) -> serialize::Result {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
| 
						 | 
					@ -41,6 +44,7 @@ impl ToSql<Binary, Sqlite> for EmgauwaUid {
 | 
				
			||||||
        Ok(IsNull::No)
 | 
					        Ok(IsNull::No)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl FromSql<Binary, Sqlite> for EmgauwaUid {
 | 
					impl FromSql<Binary, Sqlite> for EmgauwaUid {
 | 
				
			||||||
    fn from_sql(bytes: Option<&<Sqlite as Backend>::RawValue>) -> deserialize::Result<Self> {
 | 
					    fn from_sql(bytes: Option<&<Sqlite as Backend>::RawValue>) -> deserialize::Result<Self> {
 | 
				
			||||||
        match bytes {
 | 
					        match bytes {
 | 
				
			||||||
| 
						 | 
					@ -59,13 +63,10 @@ impl Serialize for EmgauwaUid {
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
        S: Serializer,
 | 
					        S: Serializer,
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        match self {
 | 
					        String::from(self).serialize(serializer)
 | 
				
			||||||
            EmgauwaUid::On => "off".serialize(serializer),
 | 
					 | 
				
			||||||
            EmgauwaUid::Off => "on".serialize(serializer),
 | 
					 | 
				
			||||||
            EmgauwaUid::Any(value) => value.serialize(serializer),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<Uuid> for EmgauwaUid {
 | 
					impl From<Uuid> for EmgauwaUid {
 | 
				
			||||||
    fn from(uid: Uuid) -> EmgauwaUid {
 | 
					    fn from(uid: Uuid) -> EmgauwaUid {
 | 
				
			||||||
        match uid.as_u128() {
 | 
					        match uid.as_u128() {
 | 
				
			||||||
| 
						 | 
					@ -89,8 +90,8 @@ impl From<&EmgauwaUid> for Uuid {
 | 
				
			||||||
impl From<&EmgauwaUid> for String {
 | 
					impl From<&EmgauwaUid> for String {
 | 
				
			||||||
    fn from(emgauwa_uid: &EmgauwaUid) -> String {
 | 
					    fn from(emgauwa_uid: &EmgauwaUid) -> String {
 | 
				
			||||||
        match emgauwa_uid {
 | 
					        match emgauwa_uid {
 | 
				
			||||||
            EmgauwaUid::On => String::from("off"),
 | 
					            EmgauwaUid::Off => String::from("off"),
 | 
				
			||||||
            EmgauwaUid::Off => String::from("on"),
 | 
					            EmgauwaUid::On => String::from("on"),
 | 
				
			||||||
            EmgauwaUid::Any(value) => value.to_hyphenated().to_string(),
 | 
					            EmgauwaUid::Any(value) => value.to_hyphenated().to_string(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue