98bebc9ba1778bc33ff5e1e6a32839a6af7b006e
[recipes.git] / backend / src / main.rs
1 use std::fs::File;
2 use std::sync::Mutex;
3
4 use actix_files as fs;
5 use actix_web::{get, web, Responder, middleware, App, HttpServer, HttpRequest};
6 use askama_actix::Template;
7 use chrono::prelude::*;
8 use clap::Parser;
9 use ron::de::from_reader;
10 use serde::Deserialize;
11
12 mod consts;
13 mod db;
14 mod hash;
15 mod model;
16 mod user;
17
18 #[derive(Template)]
19 #[template(path = "home.html")]
20 struct HomeTemplate {
21 recipes: Vec<(i32, String)>,
22 }
23
24 #[derive(Template)]
25 #[template(path = "view_recipe.html")]
26 struct ViewRecipeTemplate {
27 recipes: Vec<(i32, String)>,
28 current_recipe: model::Recipe,
29 }
30
31 #[derive(Deserialize)]
32 pub struct Request {
33 m: Option<String>
34 }
35
36 #[get("/")]
37 async fn home_page(req: HttpRequest, connection: web::Data<db::Connection>) -> impl Responder {
38 HomeTemplate { recipes: connection.get_all_recipe_titles().unwrap() } // TODO: unwrap.
39 }
40
41 #[get("/recipe/view/{id}")]
42 async fn view_recipe(req: HttpRequest, path: web::Path<(i32,)>, connection: web::Data<db::Connection>) -> impl Responder {
43 ViewRecipeTemplate {
44 recipes: connection.get_all_recipe_titles().unwrap(),
45 current_recipe: connection.get_recipe(path.0).unwrap(),
46 }
47 }
48
49 #[derive(Debug, Deserialize)]
50 struct Config {
51 port: u16
52 }
53
54 fn get_exe_name() -> String {
55 let first_arg = std::env::args().nth(0).unwrap();
56 let sep: &[_] = &['\\', '/'];
57 first_arg[first_arg.rfind(sep).unwrap()+1..].to_string()
58 }
59
60 #[actix_web::main]
61 async fn main() -> std::io::Result<()> {
62 if process_args() { return Ok(()) }
63
64 std::env::set_var("RUST_LOG", "actix_web=debug");
65 env_logger::init();
66
67 println!("Starting Recipes as web server...");
68
69 let config: Config = {
70 let f = File::open(consts::FILE_CONF).unwrap_or_else(|_| panic!("Failed to open configuration file {}", consts::FILE_CONF));
71 match from_reader(f) {
72 Ok(c) => c,
73 Err(e) => panic!("Failed to load config: {}", e)
74 }
75 };
76
77 println!("Configuration: {:?}", config);
78
79 let db_connection = web::Data::new(db::Connection::new().unwrap()); // TODO: remove unwrap.
80
81 std::env::set_var("RUST_LOG", "actix_web=info");
82
83 let mut server =
84 HttpServer::new(
85 move || {
86 App::new()
87 .wrap(middleware::Logger::default())
88 .wrap(middleware::Compress::default())
89 .app_data(db_connection.clone())
90 .service(home_page)
91 .service(view_recipe)
92 .service(fs::Files::new("/static", "static").show_files_listing())
93 }
94 );
95
96 server = server.bind(&format!("0.0.0.0:{}", config.port)).unwrap();
97
98 server.run().await
99 }
100
101 #[derive(Parser, Debug)]
102 struct Args {
103 #[arg(long)]
104 dbtest: bool
105 }
106
107 fn process_args() -> bool {
108 let args = Args::parse();
109
110 if args.dbtest {
111 match db::Connection::new() {
112 Ok(con) => {
113 if let Err(error) = con.execute_file("sql/data_test.sql") {
114 println!("Error: {:?}", error);
115 }
116 // Set the creation datetime to 'now'.
117 con.execute_sql("UPDATE [User] SET [creation_datetime] = ?1 WHERE [email] = 'paul@test.org'", [Utc::now()]).unwrap();
118 },
119 Err(error) => {
120 println!("Error: {:?}", error)
121 },
122 }
123
124 return true;
125 }
126
127 false
128
129 /*
130
131
132 fn print_usage() {
133 println!("Usage:");
134 println!(" {} [--help] [--test]", get_exe_name());
135 }
136
137 let args: Vec<String> = args().collect();
138
139 if args.iter().any(|arg| arg == "--help") {
140 print_usage();
141 return true
142 } else if args.iter().any(|arg| arg == "--test") {
143 match db::Connection::new() {
144 Ok(_) => (),
145 Err(error) => println!("Error: {:?}", error)
146 }
147 return true
148 }
149 false
150 */
151 }