initial working

This commit is contained in:
2023-01-28 00:22:59 +01:00
commit 0cd75a9ff5
26 changed files with 3995 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
pub mod errors;
pub mod read;
+26
View File
@@ -0,0 +1,26 @@
use actix_files::NamedFile;
use actix_web::{dev, middleware::ErrorHandlerResponse, Result};
pub fn bad_request<B>(res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
let new_resp = NamedFile::open("static/errors/400.html")?
.set_status_code(res.status())
.into_response(res.request())
.map_into_right_body();
Ok(ErrorHandlerResponse::Response(res.into_response(new_resp)))
}
pub fn not_found<B>(res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
let new_resp = NamedFile::open("static/errors/404.html")?
.set_status_code(res.status())
.into_response(res.request())
.map_into_right_body();
Ok(ErrorHandlerResponse::Response(res.into_response(new_resp)))
}
pub fn internal_server_error<B>(res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
let new_resp = NamedFile::open("static/errors/500.html")?
.set_status_code(res.status())
.into_response(res.request())
.map_into_right_body();
Ok(ErrorHandlerResponse::Response(res.into_response(new_resp)))
}
+28
View File
@@ -0,0 +1,28 @@
use std::collections::HashMap;
use actix_web::{error, web, Error, HttpResponse};
use crate::db::{self, Pool};
pub async fn get_teachers_json(pool: web::Data<Pool>) -> Result<HttpResponse, Error> {
let tasks = db::read::get_teachers(&pool)
.await
.map_err(error::ErrorInternalServerError)?;
Ok(HttpResponse::Ok().json(tasks))
}
pub async fn get_subjects_json(pool: web::Data<Pool>) -> Result<HttpResponse, Error> {
let tasks = db::read::get_subjects(&pool)
.await
.map_err(error::ErrorInternalServerError)?;
Ok(HttpResponse::Ok().json(tasks))
}
pub async fn get_free_slots_json(pool: web::Data<Pool>) -> Result<HttpResponse, Error> {
let tasks = db::read::get_free_slots(&pool)
.await
.map_err(error::ErrorInternalServerError)?;
Ok(HttpResponse::Ok().json(tasks))
}
+41
View File
@@ -0,0 +1,41 @@
use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use dotenv::dotenv;
use std::env;
use terminwahl_back::db;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
dotenv().ok();
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let pool = db::init_pool(&database_url)
.await
.expect("Failed to create pool");
let duration = chrono::Duration::minutes(15);
let date = NaiveDate::from_ymd_opt(2023, 2, 28).unwrap();
let time = NaiveTime::from_hms_opt(14, 30, 0).unwrap();
let mut start = NaiveDateTime::new(date, time);
for _ in 0..4 {
let end = start + duration;
sqlx::query("INSERT INTO appointment_slots (start_time, end_time) VALUES (?, ?)")
.bind(start)
.bind(end)
.execute(&pool)
.await
.unwrap();
start = end;
}
start += duration;
for _ in 0..4 {
let end = start + duration;
sqlx::query("INSERT INTO appointment_slots (start_time, end_time) VALUES (?, ?)")
.bind(start)
.bind(end)
.execute(&pool)
.await
.unwrap();
start = end;
}
Ok(())
}
+10
View File
@@ -0,0 +1,10 @@
pub mod read;
pub mod write;
use sqlx::sqlite::{SqlitePool, SqlitePoolOptions};
pub async fn init_pool(database_url: &str) -> Result<SqlitePool, sqlx::Error> {
SqlitePoolOptions::new().connect(database_url).await
}
pub type Pool = SqlitePool;
+42
View File
@@ -0,0 +1,42 @@
use sqlx::query_as;
use crate::types::{AppointmentSlot, AppointmentSlots, Subject, Subjects, Teacher, Teachers};
use super::Pool;
pub async fn get_teachers(db: &Pool) -> Result<Teachers, sqlx::Error> {
query_as!(
Teacher,
r#"
SELECT *
FROM `teachers`"#,
)
.fetch_all(&*db)
.await
}
pub async fn get_subjects(db: &Pool) -> Result<Subjects, sqlx::Error> {
query_as!(
Subject,
r#"
SELECT *
FROM `subjects`"#,
)
.fetch_all(&*db)
.await
}
pub async fn get_free_slots(db: &Pool) -> Result<AppointmentSlots, sqlx::Error> {
match query_as!(
AppointmentSlot,
r#"
SELECT *
FROM `appointment_slots`"#,
)
.fetch_all(&*db)
.await
{
Ok(elems) => Ok(elems.into_iter().map(|e| (e.id, e)).collect()),
Err(e) => Err(e),
}
}
View File
+3
View File
@@ -0,0 +1,3 @@
pub mod api;
pub mod db;
pub mod types;
+62
View File
@@ -0,0 +1,62 @@
use actix_files::Files;
use actix_session::{storage::CookieSessionStore, SessionMiddleware};
use actix_web::{
cookie::Key,
http,
middleware::{ErrorHandlers, Logger},
web, App, HttpServer,
};
use dotenv::dotenv;
use std::{
env,
sync::{Arc, Mutex},
};
use terminwahl_back::{api, db};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
dotenv().ok();
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let pool = db::init_pool(&database_url)
.await
.expect("Failed to create pool");
log::info!("starting HTTP server at http://localhost:8080");
HttpServer::new(move || {
log::debug!("Constructing the App");
let session_store = SessionMiddleware::new(CookieSessionStore::default(), Key::generate());
let error_handlers = ErrorHandlers::new()
.handler(
http::StatusCode::INTERNAL_SERVER_ERROR,
api::errors::internal_server_error,
)
.handler(http::StatusCode::BAD_REQUEST, api::errors::bad_request)
.handler(http::StatusCode::NOT_FOUND, api::errors::not_found);
App::new()
.app_data(web::Data::new(pool.clone()))
.wrap(Logger::default())
.wrap(session_store)
.wrap(error_handlers)
.service(
web::resource("/get/teachers").route(web::get().to(api::read::get_teachers_json)),
)
.service(
web::resource("/get/subjects").route(web::get().to(api::read::get_subjects_json)),
)
.service(
web::resource("/get/free_slots")
.route(web::get().to(api::read::get_free_slots_json)),
)
.service(Files::new("/", "./terminwahl_front/dist/").index_file("index.html"))
})
.bind(("127.0.0.1", 8080))?
.workers(2)
.run()
.await
}
+39
View File
@@ -0,0 +1,39 @@
use std::collections::HashMap;
use chrono::{DateTime, Local, NaiveDateTime};
use serde::{Deserialize, Serialize};
pub type IdType = i64;
#[derive(Debug, Deserialize, Serialize)]
pub struct Teacher {
pub id: IdType,
pub ansprache: String,
pub last_name: String,
pub subject_id: IdType,
}
pub type Teachers = Vec<Teacher>;
#[derive(Debug, Deserialize, Serialize)]
pub struct Subject {
pub id: IdType,
pub name: String,
}
pub type Subjects = Vec<Subject>;
#[derive(Debug, Deserialize, Serialize)]
pub struct Appointment {
pub id: IdType,
pub teacher_id: IdType,
pub slot_id: IdType,
}
pub type AppointmentSlots = HashMap<IdType, AppointmentSlot>;
#[derive(Debug, Deserialize, Serialize)]
pub struct AppointmentSlot {
pub id: IdType,
pub start_time: NaiveDateTime,
pub end_time: NaiveDateTime,
}