Buchung funktioniert email anfänglich
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
pub mod errors;
|
||||
pub mod read;
|
||||
pub mod write;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use actix_web::{error, web, Error, HttpResponse};
|
||||
|
||||
use crate::db::{self, Pool};
|
||||
@@ -19,8 +17,15 @@ pub async fn get_subjects_json(pool: web::Data<Pool>) -> Result<HttpResponse, Er
|
||||
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)
|
||||
pub async fn get_slots_json(pool: web::Data<Pool>) -> Result<HttpResponse, Error> {
|
||||
let tasks = db::read::get_slots(&pool)
|
||||
.await
|
||||
.map_err(error::ErrorInternalServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(tasks))
|
||||
}
|
||||
pub async fn get_unavailable_json(pool: web::Data<Pool>) -> Result<HttpResponse, Error> {
|
||||
let tasks = db::read::get_unavailable(&pool)
|
||||
.await
|
||||
.map_err(error::ErrorInternalServerError)?;
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
use actix_web::{error, web, HttpResponse};
|
||||
use lettre::{
|
||||
transport::smtp::{authentication::Credentials, SmtpTransportBuilder},
|
||||
Message, SmtpTransport, Transport,
|
||||
};
|
||||
use terminwahl_typen::{PlannedAppointment, RequestState};
|
||||
|
||||
use crate::db::{self, Pool};
|
||||
|
||||
pub async fn save_appointments_json(
|
||||
pool: web::Data<Pool>,
|
||||
mailer: web::Data<SmtpTransport>,
|
||||
appointments: web::Json<Vec<PlannedAppointment>>,
|
||||
) -> Result<HttpResponse, error::Error> {
|
||||
db::write::save_appointments(&pool, &appointments)
|
||||
.await
|
||||
.map_err(error::ErrorInternalServerError)?;
|
||||
|
||||
let email = Message::builder()
|
||||
.from(
|
||||
"Franz Dietrich <franz.dietrich@uhlandshoehe.de>"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
)
|
||||
.to("Franz Dietrich <dietrich@teilgedanken.de>".parse().unwrap())
|
||||
.subject("Happy new year")
|
||||
.body(String::from("Be happy!"))
|
||||
.unwrap();
|
||||
|
||||
// Send the email
|
||||
match mailer.send(&email) {
|
||||
Ok(_) => println!("Email sent successfully!"),
|
||||
Err(e) => panic!("Could not send email: {:?}", e),
|
||||
}
|
||||
|
||||
Ok(HttpResponse::Ok().json(RequestState::Success))
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use sqlx::query_as;
|
||||
|
||||
use crate::types::{AppointmentSlot, AppointmentSlots, Subject, Subjects, Teacher, Teachers};
|
||||
use terminwahl_typen::{
|
||||
AppointmentSlot, AppointmentSlots, SlotId, Subject, Subjects, Teacher, Teachers,
|
||||
};
|
||||
|
||||
use super::Pool;
|
||||
|
||||
@@ -11,7 +15,7 @@ pub async fn get_teachers(db: &Pool) -> Result<Teachers, sqlx::Error> {
|
||||
SELECT *
|
||||
FROM `teachers`"#,
|
||||
)
|
||||
.fetch_all(&*db)
|
||||
.fetch_all(db)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -22,21 +26,35 @@ pub async fn get_subjects(db: &Pool) -> Result<Subjects, sqlx::Error> {
|
||||
SELECT *
|
||||
FROM `subjects`"#,
|
||||
)
|
||||
.fetch_all(&*db)
|
||||
.fetch_all(db)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_free_slots(db: &Pool) -> Result<AppointmentSlots, sqlx::Error> {
|
||||
pub async fn get_slots(db: &Pool) -> Result<AppointmentSlots, sqlx::Error> {
|
||||
match query_as!(
|
||||
AppointmentSlot,
|
||||
r#"
|
||||
SELECT *
|
||||
FROM `appointment_slots`"#,
|
||||
)
|
||||
.fetch_all(&*db)
|
||||
.fetch_all(db)
|
||||
.await
|
||||
{
|
||||
Ok(elems) => Ok(elems.into_iter().map(|e| (e.id, e)).collect()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
pub async fn get_unavailable(db: &Pool) -> Result<HashSet<SlotId>, sqlx::Error> {
|
||||
match query_as!(
|
||||
SlotId,
|
||||
r#"
|
||||
SELECT teacher_id, slot_id
|
||||
FROM `appointments`"#,
|
||||
)
|
||||
.fetch_all(db)
|
||||
.await
|
||||
{
|
||||
Ok(elems) => Ok(elems.into_iter().collect()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
use terminwahl_typen::PlannedAppointment;
|
||||
|
||||
use super::Pool;
|
||||
|
||||
pub async fn save_appointments(
|
||||
pool: &Pool,
|
||||
appointments: &[PlannedAppointment],
|
||||
) -> Result<(), sqlx::Error> {
|
||||
for appointment in appointments {
|
||||
sqlx::query("INSERT INTO appointments (teacher_id, slot_id) VALUES ($1, $2)")
|
||||
.bind(appointment.teacher_id)
|
||||
.bind(appointment.slot_id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
pub mod api;
|
||||
pub mod db;
|
||||
pub mod types;
|
||||
|
||||
@@ -7,10 +7,8 @@ use actix_web::{
|
||||
web, App, HttpServer,
|
||||
};
|
||||
use dotenv::dotenv;
|
||||
use std::{
|
||||
env,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use lettre::{transport::smtp::authentication::Credentials, SmtpTransport};
|
||||
use std::env;
|
||||
use terminwahl_back::{api, db};
|
||||
|
||||
#[actix_web::main]
|
||||
@@ -22,6 +20,15 @@ async fn main() -> std::io::Result<()> {
|
||||
let pool = db::init_pool(&database_url)
|
||||
.await
|
||||
.expect("Failed to create pool");
|
||||
let smtp_user = env::var("SMTP_USER").expect("Failed to get smtp user");
|
||||
let smtp_password = env::var("SMTP_PASSWORD").expect("Failed to get smtp password");
|
||||
let credentials = Credentials::new(smtp_user, smtp_password);
|
||||
let smtp_pool = SmtpTransport::relay("smtp.1und1.de")
|
||||
.expect("Failed to connect to smtp")
|
||||
// Add credentials for authentication
|
||||
.credentials(credentials)
|
||||
// Connection pool settings
|
||||
.build();
|
||||
|
||||
log::info!("starting HTTP server at http://localhost:8080");
|
||||
|
||||
@@ -40,6 +47,7 @@ async fn main() -> std::io::Result<()> {
|
||||
|
||||
App::new()
|
||||
.app_data(web::Data::new(pool.clone()))
|
||||
.app_data(web::Data::new(smtp_pool.clone()))
|
||||
.wrap(Logger::default())
|
||||
.wrap(session_store)
|
||||
.wrap(error_handlers)
|
||||
@@ -49,9 +57,14 @@ async fn main() -> std::io::Result<()> {
|
||||
.service(
|
||||
web::resource("/get/subjects").route(web::get().to(api::read::get_subjects_json)),
|
||||
)
|
||||
.service(web::resource("/get/slots").route(web::get().to(api::read::get_slots_json)))
|
||||
.service(
|
||||
web::resource("/get/free_slots")
|
||||
.route(web::get().to(api::read::get_free_slots_json)),
|
||||
web::resource("/get/unavailable")
|
||||
.route(web::get().to(api::read::get_unavailable_json)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/send/appointments")
|
||||
.route(web::post().to(api::write::save_appointments_json)),
|
||||
)
|
||||
.service(Files::new("/", "./terminwahl_front/dist/").index_file("index.html"))
|
||||
})
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
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,
|
||||
}
|
||||
Reference in New Issue
Block a user