parent
c9c29748b2
commit
a71ba86e45
25
src/main.rs
25
src/main.rs
@ -10,7 +10,6 @@ mod views;
|
|||||||
use actix_identity::{CookieIdentityPolicy, IdentityService};
|
use actix_identity::{CookieIdentityPolicy, IdentityService};
|
||||||
use actix_web::middleware::Logger;
|
use actix_web::middleware::Logger;
|
||||||
use actix_web::{web, App, HttpResponse, HttpServer};
|
use actix_web::{web, App, HttpResponse, HttpServer};
|
||||||
use actix_web_static_files;
|
|
||||||
|
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use tera::Tera;
|
use tera::Tera;
|
||||||
@ -124,7 +123,29 @@ async fn main() -> std::io::Result<()> {
|
|||||||
// view an existing url
|
// view an existing url
|
||||||
.service(
|
.service(
|
||||||
web::scope("/view")
|
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(
|
.service(
|
||||||
web::scope("/download")
|
web::scope("/download")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{forms::LinkForm, ServerError};
|
use crate::{forms::LinkForm, ServerError};
|
||||||
|
|
||||||
use super::schema::{links, users};
|
use super::schema::{links, users};
|
||||||
use argonautica::Hasher;
|
use argonautica::{Hasher, Verifier};
|
||||||
use diesel::{Insertable, Queryable};
|
use diesel::{Insertable, Queryable};
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -28,22 +28,28 @@ impl NewUser {
|
|||||||
email: String,
|
email: String,
|
||||||
password: String,
|
password: String,
|
||||||
) -> Result<Self, ServerError> {
|
) -> Result<Self, ServerError> {
|
||||||
|
let hash = Self::hash_password(password)?;
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
|
|
||||||
let secret = std::env::var("SECRET_KEY")?;
|
|
||||||
|
|
||||||
let hash = Hasher::default()
|
|
||||||
.with_password(password)
|
|
||||||
.with_secret_key(secret)
|
|
||||||
.hash()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Ok(NewUser {
|
Ok(NewUser {
|
||||||
username,
|
username,
|
||||||
email,
|
email,
|
||||||
password: hash,
|
password: hash,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn hash_password(password: String) -> Result<String, ServerError> {
|
||||||
|
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)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
122
src/views.rs
122
src/views.rs
@ -1,19 +1,16 @@
|
|||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use actix_identity::Identity;
|
|
||||||
|
|
||||||
use crate::ServerError;
|
use crate::ServerError;
|
||||||
|
use actix_identity::Identity;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
http::header::{CacheControl, CacheDirective, ContentType, Expires},
|
http::header::{CacheControl, CacheDirective, ContentType, Expires},
|
||||||
web, HttpResponse,
|
web, HttpResponse,
|
||||||
};
|
};
|
||||||
use argonautica::Verifier;
|
use argonautica::Verifier;
|
||||||
use diesel::sqlite::SqliteConnection;
|
use diesel::{prelude::*, result::Error::NotFound, sqlite::SqliteConnection};
|
||||||
use diesel::{prelude::*, result::Error::NotFound};
|
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use image::{DynamicImage, ImageOutputFormat, Luma};
|
use image::{DynamicImage, ImageOutputFormat, Luma};
|
||||||
use qrcode::render::svg;
|
use qrcode::{render::svg, QrCode};
|
||||||
use qrcode::QrCode;
|
|
||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
|
|
||||||
use super::forms::LinkForm;
|
use super::forms::LinkForm;
|
||||||
@ -75,7 +72,6 @@ pub(crate) async fn view_link(
|
|||||||
id: Identity,
|
id: Identity,
|
||||||
link_id: web::Path<String>,
|
link_id: web::Path<String>,
|
||||||
) -> Result<HttpResponse, ServerError> {
|
) -> Result<HttpResponse, ServerError> {
|
||||||
println!("Viewing link!");
|
|
||||||
use super::schema::links::dsl::{code, links};
|
use super::schema::links::dsl::{code, links};
|
||||||
if let Some(id) = id.identity() {
|
if let Some(id) = id.identity() {
|
||||||
let connection = establish_connection()?;
|
let connection = establish_connection()?;
|
||||||
@ -111,6 +107,104 @@ pub(crate) async fn view_link(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn view_profile(
|
||||||
|
tera: web::Data<Tera>,
|
||||||
|
identity: Identity,
|
||||||
|
user_id: web::Path<String>,
|
||||||
|
) -> Result<HttpResponse, ServerError> {
|
||||||
|
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::<i32>() {
|
||||||
|
let user = users.filter(id.eq(&uid)).first::<User>(&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<Tera>,
|
||||||
|
identity: Identity,
|
||||||
|
user_id: web::Path<String>,
|
||||||
|
) -> Result<HttpResponse, ServerError> {
|
||||||
|
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::<i32>() {
|
||||||
|
let user = users.filter(id.eq(&uid)).first::<User>(&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<NewUser>,
|
||||||
|
id: Identity,
|
||||||
|
user_id: web::Path<String>,
|
||||||
|
) -> Result<HttpResponse, ServerError> {
|
||||||
|
if let Some(_id) = id.identity() {
|
||||||
|
use super::schema::users::dsl::{email, id, password, username, users};
|
||||||
|
|
||||||
|
if let Ok(uid) = user_id.parse::<i32>() {
|
||||||
|
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(
|
pub(crate) async fn download_png(
|
||||||
id: Identity,
|
id: Identity,
|
||||||
link_id: web::Path<String>,
|
link_id: web::Path<String>,
|
||||||
@ -210,23 +304,25 @@ pub(crate) async fn process_login(
|
|||||||
Ok(u) => {
|
Ok(u) => {
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
let secret = std::env::var("SECRET_KEY")?;
|
let secret = std::env::var("SECRET_KEY")?;
|
||||||
|
|
||||||
let valid = Verifier::default()
|
let valid = Verifier::default()
|
||||||
.with_hash(u.password)
|
.with_hash(&u.password)
|
||||||
.with_password(data.password.clone())
|
.with_password(&data.password)
|
||||||
.with_secret_key(secret)
|
.with_secret_key(&secret)
|
||||||
.verify()?;
|
.verify()?;
|
||||||
|
|
||||||
if valid {
|
if valid {
|
||||||
|
println!("Login of user: {}", &u.username);
|
||||||
let session_token = u.username;
|
let session_token = u.username;
|
||||||
id.remember(session_token);
|
id.remember(session_token);
|
||||||
|
|
||||||
Ok(redirect_builder("/admin/index/"))
|
Ok(redirect_builder("/admin/index/"))
|
||||||
} else {
|
} else {
|
||||||
Ok(redirect_builder("/admin/login/"))
|
Ok(redirect_builder("/admin/login/"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_e) => Ok(redirect_builder("/admin/login/")),
|
Err(e) => {
|
||||||
|
println!("Failed to login: {}", e);
|
||||||
|
Ok(redirect_builder("/admin/login/"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,5 +49,26 @@ svg {
|
|||||||
|
|
||||||
div.welcome {
|
div.welcome {
|
||||||
text-align: right;
|
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;
|
||||||
}
|
}
|
21
templates/edit_profile.html
Normal file
21
templates/edit_profile.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{% extends "admin.html" %}
|
||||||
|
|
||||||
|
{% block admin %}
|
||||||
|
<h1>Profil von {{user.username}}</h1>
|
||||||
|
<form action="" method="POST">
|
||||||
|
<div>
|
||||||
|
<label for="username">Benutzername:</label>
|
||||||
|
<input type="text" name="username" value="{{ user.username }}">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="email">E-mail:</label>
|
||||||
|
<input type="email" name="email" value="{{ user.email }}">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="password">Passwort:</label>
|
||||||
|
<input type="password" name="password" placeholder="Leer lassen um nichts zu ändern">
|
||||||
|
</div>
|
||||||
|
<input type="submit" value="Editieren">
|
||||||
|
</form>
|
||||||
|
<h2> </h2>
|
||||||
|
{% endblock %}
|
@ -7,16 +7,16 @@
|
|||||||
{% set u = links_user[1] %}
|
{% set u = links_user[1] %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="/admin/view/{{l.code}}"><span>{{l.code}}:</span>
|
<a href="/admin/view/link/{{l.code}}"><span>{{l.code}}:</span>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="/admin/view/{{l.code}}">{{ l.target }}
|
<a href="/admin/view/link/{{l.code}}">{{ l.target }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
<a href="/admin/view/{{l.code}}"><small>{{ u.username }}</small>
|
<a href="/admin/view/profile/{{u.id}}"><small>{{ u.username }}</small>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
23
templates/view_profile.html
Normal file
23
templates/view_profile.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{% extends "admin.html" %}
|
||||||
|
|
||||||
|
{% block admin %}
|
||||||
|
<h1>Profil von {{user.username}}</h1>
|
||||||
|
<form action="" method="POST">
|
||||||
|
<div>
|
||||||
|
<label for="username">Benutzername:</label>
|
||||||
|
<input type="text" name="username" value="{{ user.username }}" readonly>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="email">E-mail:</label>
|
||||||
|
<input type="email" name="email" value="{{ user.email }}" readonly>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="password">Passwort:</label>
|
||||||
|
<input type="password" name="password" value="verschlüsselt" readonly>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="actions">
|
||||||
|
<a class="button" href="/admin/edit/profile/{{ user.id }}">Editieren</a>
|
||||||
|
</div>
|
||||||
|
<h2> </h2>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user