diff --git a/src/main.rs b/src/main.rs index 3ac7b4d..5d64595 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,6 @@ mod views; use actix_identity::{CookieIdentityPolicy, IdentityService}; use actix_web::middleware::Logger; use actix_web::{web, App, HttpResponse, HttpServer}; -use actix_web_static_files; use dotenv::dotenv; use tera::Tera; @@ -124,7 +123,29 @@ async fn main() -> std::io::Result<()> { // view an existing url .service( web::scope("/view") - .route("/{redirect_id}", web::get().to(views::view_link)), + .service( + web::scope("/link") + .route("/{redirect_id}", web::get().to(views::view_link)), + ) + .service( + web::scope("/profile") + .route("/{user_id}", web::get().to(views::view_profile)), + ), + ) + .service( + web::scope("/edit") + .service( + web::scope("/link") + .route("/{redirect_id}", web::get().to(views::view_link)), + ) + .service( + web::scope("/profile") + .route("/{user_id}", web::get().to(views::edit_profile)) + .route( + "/{user_id}", + web::post().to(views::process_edit_profile), + ), + ), ) .service( web::scope("/download") diff --git a/src/models.rs b/src/models.rs index 0cb1216..aea6a28 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,7 +1,7 @@ use crate::{forms::LinkForm, ServerError}; use super::schema::{links, users}; -use argonautica::Hasher; +use argonautica::{Hasher, Verifier}; use diesel::{Insertable, Queryable}; use dotenv::dotenv; use serde::{Deserialize, Serialize}; @@ -28,22 +28,28 @@ impl NewUser { email: String, password: String, ) -> Result { + let hash = Self::hash_password(password)?; dotenv().ok(); - let secret = std::env::var("SECRET_KEY")?; - - let hash = Hasher::default() - .with_password(password) - .with_secret_key(secret) - .hash() - .unwrap(); - Ok(NewUser { username, email, password: hash, }) } + + pub(crate) fn hash_password(password: String) -> Result { + dotenv().ok(); + + let secret = std::env::var("SECRET_KEY")?; + + let hash = Hasher::default() + .with_password(&password) + .with_secret_key(&secret) + .hash()?; + + Ok(hash) + } } #[derive(Debug, Deserialize)] diff --git a/src/views.rs b/src/views.rs index 40480c2..937d68d 100644 --- a/src/views.rs +++ b/src/views.rs @@ -1,19 +1,16 @@ use std::time::SystemTime; -use actix_identity::Identity; - use crate::ServerError; +use actix_identity::Identity; use actix_web::{ http::header::{CacheControl, CacheDirective, ContentType, Expires}, web, HttpResponse, }; use argonautica::Verifier; -use diesel::sqlite::SqliteConnection; -use diesel::{prelude::*, result::Error::NotFound}; +use diesel::{prelude::*, result::Error::NotFound, sqlite::SqliteConnection}; use dotenv::dotenv; use image::{DynamicImage, ImageOutputFormat, Luma}; -use qrcode::render::svg; -use qrcode::QrCode; +use qrcode::{render::svg, QrCode}; use tera::{Context, Tera}; use super::forms::LinkForm; @@ -75,7 +72,6 @@ pub(crate) async fn view_link( id: Identity, link_id: web::Path, ) -> Result { - println!("Viewing link!"); use super::schema::links::dsl::{code, links}; if let Some(id) = id.identity() { let connection = establish_connection()?; @@ -111,6 +107,104 @@ pub(crate) async fn view_link( } } +pub(crate) async fn view_profile( + tera: web::Data, + identity: Identity, + user_id: web::Path, +) -> Result { + use super::schema::users::dsl::{id, users}; + println!("Viewing Profile!"); + if let Some(identity) = identity.identity() { + let connection = establish_connection()?; + if let Ok(uid) = user_id.parse::() { + let user = users.filter(id.eq(&uid)).first::(&connection)?; + + let mut data = Context::new(); + data.insert("name", &identity); + data.insert( + "title", + &format!( + "Benutzer {} der Freien Hochschule Stuttgart", + &user.username + ), + ); + data.insert("user", &user); + + let rendered = tera.render("view_profile.html", &data)?; + Ok(HttpResponse::Ok().body(rendered)) + } else { + Ok(redirect_builder("/admin/index/")) + } + } else { + Ok(redirect_builder("/admin/login/")) + } +} + +pub(crate) async fn edit_profile( + tera: web::Data, + identity: Identity, + user_id: web::Path, +) -> Result { + use super::schema::users::dsl::{id, users}; + println!("Viewing Profile!"); + if let Some(identity) = identity.identity() { + let connection = establish_connection()?; + if let Ok(uid) = user_id.parse::() { + let user = users.filter(id.eq(&uid)).first::(&connection)?; + + let mut data = Context::new(); + data.insert("name", &identity); + data.insert( + "title", + &format!( + "Benutzer {} der Freien Hochschule Stuttgart", + &user.username + ), + ); + data.insert("user", &user); + + let rendered = tera.render("edit_profile.html", &data)?; + Ok(HttpResponse::Ok().body(rendered)) + } else { + Ok(redirect_builder("/admin/index/")) + } + } else { + Ok(redirect_builder("/admin/login/")) + } +} + +pub(crate) async fn process_edit_profile( + data: web::Form, + id: Identity, + user_id: web::Path, +) -> Result { + if let Some(_id) = id.identity() { + use super::schema::users::dsl::{email, id, password, username, users}; + + if let Ok(uid) = user_id.parse::() { + println!("Updating userinfo: "); + let connection = establish_connection()?; + diesel::update(users.filter(id.eq(uid))) + .set(( + username.eq(data.username.clone()), + email.eq(data.email.clone()), + )) + .execute(&connection)?; + if data.password.len() > 3 { + let hash = NewUser::hash_password(data.password.clone())?; + diesel::update(users.filter(id.eq(uid))) + .set((password.eq(hash),)) + .execute(&connection)?; + } + Ok(HttpResponse::Ok().body(format!("Successfully saved user: {}", data.username))) + } else { + Ok(redirect_builder("/admin/index/")) + } + } else { + Ok(redirect_builder("/admin/login/")) + } +} + pub(crate) async fn download_png( id: Identity, link_id: web::Path, @@ -210,23 +304,25 @@ pub(crate) async fn process_login( Ok(u) => { dotenv().ok(); let secret = std::env::var("SECRET_KEY")?; - let valid = Verifier::default() - .with_hash(u.password) - .with_password(data.password.clone()) - .with_secret_key(secret) + .with_hash(&u.password) + .with_password(&data.password) + .with_secret_key(&secret) .verify()?; if valid { + println!("Login of user: {}", &u.username); let session_token = u.username; id.remember(session_token); - Ok(redirect_builder("/admin/index/")) } else { Ok(redirect_builder("/admin/login/")) } } - Err(_e) => Ok(redirect_builder("/admin/login/")), + Err(e) => { + println!("Failed to login: {}", e); + Ok(redirect_builder("/admin/login/")) + } } } diff --git a/static/admin.css b/static/admin.css index 1ae20e5..2c1da5e 100644 --- a/static/admin.css +++ b/static/admin.css @@ -49,5 +49,26 @@ svg { div.welcome { text-align: right; - font-size: 24pt; + font-size: 16pt; +} + +div.actions { + width: 400px; + height: 400px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 30px; + color: #333; +} + +a.button { + display:block; + padding: 15px; + text-align: center; + border-radius: 1px; + border: 1px solid rgb(90, 90, 90); + font-family: inherit; + background-color: #eae9ea; } \ No newline at end of file diff --git a/templates/edit_profile.html b/templates/edit_profile.html new file mode 100644 index 0000000..127191c --- /dev/null +++ b/templates/edit_profile.html @@ -0,0 +1,21 @@ +{% extends "admin.html" %} + +{% block admin %} +

Profil von {{user.username}}

+
+
+ + +
+
+ + +
+
+ + +
+ +
+

 

+{% endblock %} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 2505972..a407b20 100644 --- a/templates/index.html +++ b/templates/index.html @@ -7,16 +7,16 @@ {% set u = links_user[1] %} - {{l.code}}: + {{l.code}}: - {{ l.target }} + {{ l.target }} - {{ u.username }} + {{ u.username }} diff --git a/templates/view_profile.html b/templates/view_profile.html new file mode 100644 index 0000000..4613f1b --- /dev/null +++ b/templates/view_profile.html @@ -0,0 +1,23 @@ +{% extends "admin.html" %} + +{% block admin %} +

Profil von {{user.username}}

+
+
+ + +
+
+ + +
+
+ + +
+
+ +

 

+{% endblock %} \ No newline at end of file