Improve error handling

This commit is contained in:
Sofía Aritz 2024-10-16 21:15:14 +02:00
parent e667b4452b
commit 29e0907b58
Signed by: sofia
GPG key ID: 90B5116E3542B28F
4 changed files with 207 additions and 199 deletions

View file

@ -95,10 +95,7 @@ macro_rules! retrieve_sub_entry {
}};
}
pub fn entry_recursive(
entry_id: &str,
conn: Connection,
) -> QueryResult<FullDatabaseEntry> {
pub fn entry_recursive(entry_id: &str, conn: Connection) -> QueryResult<FullDatabaseEntry> {
use crate::database::schema::entries::dsl::entries;
let entry: Entry = entries

View file

@ -2,13 +2,13 @@ use crate::AppState;
use axum::{
async_trait,
extract::FromRequestParts,
http::{header::AUTHORIZATION, request::Parts, StatusCode},
http::{request::Parts, StatusCode},
};
use diesel::{
r2d2::{ConnectionManager, PooledConnection},
SqliteConnection,
};
use tracing::{error, warn};
use tracing::error;
pub struct Database(pub PooledConnection<ConnectionManager<SqliteConnection>>);

View file

@ -80,20 +80,18 @@ async fn genkey(
use crate::database::schema::session_keys::dsl::*;
let session_key = Uuid::new_v4().to_string();
let result = diesel::insert_into(session_keys)
diesel::insert_into(session_keys)
.values((user_id.eq(&user.uid), key.eq(&session_key)))
.execute(&mut conn);
if result.is_ok() {
Ok(Json(GenkeyResponse { session_key }))
} else {
.execute(&mut conn)
.map_err(|err| {
error!(
"failed to insert into session_keys {}, error: {:?}",
user.uid,
result.err()
"failed to insert into session_keys {}, error: {err:?}",
user.uid
);
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(Json(GenkeyResponse { session_key }))
}
#[derive(Debug, Deserialize)]
@ -113,27 +111,26 @@ async fn login(
) -> Result<Json<LoginResponse>, StatusCode> {
if let Ok(Some(user)) = actions::user_by_email(&req.email, &mut conn) {
let parsed_hash = PasswordHash::new(&user.password).expect("invalid argon2 password hash");
if Argon2::default()
Argon2::default()
.verify_password(req.password.as_bytes(), &parsed_hash)
.is_err()
{
.map_err(|_err| {
info!("failed login attempt, invalid password: {}", &req.email);
Err(StatusCode::UNAUTHORIZED)
} else {
StatusCode::UNAUTHORIZED
})?;
info!("valid login attempt: {}", req.email);
match encode_jwt(&JwtUser {
let token = encode_jwt(&JwtUser {
uid: user.id,
email: user.email,
name: user.name,
exp: expiration_time(),
}) {
Ok(token) => Ok(Json(LoginResponse { token })),
Err(err) => {
})
.map_err(|err| {
error!("token couldn't be encoded: {:?}", err);
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
}
}
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(Json(LoginResponse { token }))
} else {
info!("failed login attempt, email does not exist: {}", &req.email);
Err(StatusCode::UNAUTHORIZED)
@ -159,47 +156,46 @@ async fn register(
use crate::database::schema::limits::dsl as limits;
use crate::database::schema::users::dsl as users;
let user = actions::user_by_email(&req.email, &mut conn);
if user.is_err() {
let user = actions::user_by_email(&req.email, &mut conn).map_err(|err| {
error!(
"failed to retrieve potential existing user from database: {}, error: {:?}",
&req.email,
user.err()
"failed to retrieve potential existing user from database: {}, error: {err:?}",
&req.email
);
return Err(StatusCode::INTERNAL_SERVER_ERROR);
}
StatusCode::INTERNAL_SERVER_ERROR
})?;
if user.is_ok_and(|v| v.is_some()) {
if user.is_some() {
info!("tried to register existing user: {}", &req.email);
return Err(StatusCode::BAD_REQUEST);
}
let limit_id = Uuid::new_v4().to_string();
let result = diesel::insert_into(limits::limits)
diesel::insert_into(limits::limits)
.values((
limits::id.eq(&limit_id),
limits::current_asset_count.eq(0),
limits::max_asset_count.eq(10),
))
.execute(&mut conn);
if result.is_err() {
.execute(&mut conn)
.map_err(|err| {
error!(
"failed to insert into limits: {}, error: {:?}",
&req.email,
result.err()
"failed to insert into limits: {}, error: {err:?}",
&req.email
);
return Err(StatusCode::INTERNAL_SERVER_ERROR);
}
StatusCode::INTERNAL_SERVER_ERROR
})?;
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
let password_hash = argon2.hash_password(req.password.as_bytes(), &salt);
let password_hash = argon2
.hash_password(req.password.as_bytes(), &salt)
.map_err(|err| {
error!("failed to hash password: {err:?}");
StatusCode::INTERNAL_SERVER_ERROR
})?;
if let Ok(password_hash) = password_hash {
let user_id = Uuid::new_v4().to_string();
let result = diesel::insert_into(users::users)
diesel::insert_into(users::users)
.values((
users::id.eq(&user_id),
users::created_at.eq(Utc::now().naive_utc()),
@ -211,33 +207,24 @@ async fn register(
// FIXME(sofia): Implement diesel::Expression for List
users::assets.eq("[]"),
))
.execute(&mut conn);
.execute(&mut conn)
.map_err(|err| {
error!("failed to insert into users: {}, error: {err:?}", req.email);
StatusCode::INTERNAL_SERVER_ERROR
})?;
if result.is_err() {
error!(
"failed to insert into users: {}, error: {:?}",
req.email,
result.err()
);
return Err(StatusCode::INTERNAL_SERVER_ERROR);
}
match crate::auth::encode_jwt(&JwtUser {
let token = crate::auth::encode_jwt(&JwtUser {
uid: user_id,
email: req.email,
name: req.name,
exp: expiration_time(),
}) {
Ok(token) => Ok(Json(RegisterResponse { token })),
Err(err) => {
})
.map_err(|err| {
error!("token couldn't be encoded: {:?}", err);
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
}
} else {
error!("failed to hash password: {:?}", password_hash.err());
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(Json(RegisterResponse { token }))
}
#[derive(Debug, Serialize, Deserialize)]
@ -265,17 +252,16 @@ async fn list_heirs(
Database(mut conn): Database,
ExtractJwtUser(user): ExtractJwtUser,
) -> Result<Json<Vec<HttpHeir>>, StatusCode> {
let result = actions::list_heirs(&user.uid, &mut conn);
if let Ok(heirs) = result {
Ok(Json(heirs.into_iter().map(HttpHeir::from).collect()))
} else {
let heirs = actions::list_heirs(&user.uid, &mut conn)
.map_err(|err| {
error!(
"failed to obtain heirs: {}, error: {:?}",
user.uid,
result.err()
"failed to obtain heirs: {}, error: {err:?}",
user.uid
);
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(Json(heirs.into_iter().map(HttpHeir::from).collect()))
}
#[derive(Debug, Deserialize)]
@ -294,7 +280,7 @@ async fn insert_heir(
use crate::database::schema::heirs::dsl::*;
let heir_id = Uuid::new_v4().to_string();
let result = diesel::insert_into(heirs)
diesel::insert_into(heirs)
.values((
id.eq(heir_id),
created_at.eq(Utc::now().naive_utc()),
@ -303,28 +289,25 @@ async fn insert_heir(
// Only e-mail is implemented right now
email.eq(req.value),
))
.execute(&mut conn);
if result.is_err() {
.execute(&mut conn)
.map_err(|err| {
error!(
"failed to insert into heirs: {}, error: {:?}",
user.uid,
result.err()
"failed to insert into heirs: {}, error: {err:?}",
user.uid
);
return Err(StatusCode::INTERNAL_SERVER_ERROR);
}
StatusCode::INTERNAL_SERVER_ERROR
})?;
let heirs_list = actions::list_heirs(&user.uid, &mut conn)
.map_err(|err| {
error!(
"failed to obtain heirs: {}, error: {err:?}",
user.uid
);
StatusCode::INTERNAL_SERVER_ERROR
})?;
let result = actions::list_heirs(&user.uid, &mut conn);
if let Ok(heirs_list) = result {
Ok(Json(heirs_list.into_iter().map(HttpHeir::from).collect()))
} else {
error!(
"failed to obtain heirs: {}, error: {:?}",
user.uid,
result.err()
);
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
}
#[derive(Debug, Deserialize)]
@ -339,26 +322,24 @@ async fn delete_heir(
) -> Result<Json<Vec<HttpHeir>>, StatusCode> {
use crate::database::schema::heirs::dsl::*;
let result = diesel::delete(heirs.filter(id.eq(&req.id))).execute(&mut conn);
if result.is_err() {
diesel::delete(heirs.filter(id.eq(&req.id))).execute(&mut conn)
.map_err(|err| {
error!(
"failed to delete from heirs: {}, heir_id: {}, error: {:?}",
"failed to delete from heirs: {}, heir_id: {}, error: {err:?}",
user.uid,
req.id,
result.err()
);
return Err(StatusCode::INTERNAL_SERVER_ERROR);
}
StatusCode::INTERNAL_SERVER_ERROR
})?;
let result = actions::list_heirs(&user.uid, &mut conn);
if let Ok(heirs_list) = result {
Ok(Json(heirs_list.into_iter().map(HttpHeir::from).collect()))
} else {
let heirs_list = actions::list_heirs(&user.uid, &mut conn)
.map_err(|err| {
error!(
"failed to obtain heirs: {}, error: {:?}",
"failed to obtain heirs: {}, error: {err:?}",
user.uid,
result.err()
);
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(Json(heirs_list.into_iter().map(HttpHeir::from).collect()))
}

View file

@ -30,7 +30,7 @@ use crate::{
AppState,
};
use axum::{
extract::{Query, State},
extract::Query,
http::StatusCode,
routing::{delete, get, put},
Json, Router,
@ -85,18 +85,18 @@ async fn list_entries(
Query(query): Query<ListEntriesQuery>,
ExtractUser(user): ExtractUser,
) -> Result<Json<Vec<HttpEntry>>, StatusCode> {
let result = actions::list_entries_recursive(&user.id, query.offset, query.limit, &mut conn);
if let Ok(entries) = result {
let entries = actions::list_entries_recursive(&user.id, query.offset, query.limit, &mut conn)
.map_err(|err| {
error!("failed to obtain entries {}: {err:?}", user.id);
StatusCode::INTERNAL_SERVER_ERROR
})?;
Ok(Json(
entries
.into_iter()
.filter_map(|v| HttpEntry::try_from(v).ok())
.collect(),
))
} else {
error!("failed to obtain entries {}: {:?}", user.id, result.err());
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
}
#[derive(Debug, Deserialize)]
@ -115,8 +115,18 @@ async fn insert_entry(
let entry = entry.entry;
match entry.base {
HttpEntryBase::Album { ref artist, ref title, ref links, ref id }
| HttpEntryBase::Song { ref artist, ref title, ref links, ref id } => {
HttpEntryBase::Album {
ref artist,
ref title,
ref links,
ref id,
}
| HttpEntryBase::Song {
ref artist,
ref title,
ref links,
ref id,
} => {
music_entry = Some(MusicEntry {
id: Uuid::new_v4().to_string(),
// FIXME(sofia): These clones seems unnecesary
@ -125,7 +135,7 @@ async fn insert_entry(
artist: artist.clone(),
universal_ids: id.clone().into(),
})
},
}
HttpEntryBase::Environment { ref location } => {
if entry.title.as_ref().is_none_or(|v| v.is_empty()) {
warn!(
@ -167,19 +177,19 @@ async fn insert_entry(
HttpEntryBase::Date {
ref referenced_date,
} => {
let naive_date = NaiveDate::parse_from_str(referenced_date, "%Y-%m-%d");
if let Err(err) = naive_date {
let naive_date = NaiveDate::parse_from_str(referenced_date, "%Y-%m-%d")
.map_err(|err| {
warn!(
"invalid date in request for inserting entry: {}, err: {err:?}",
user.id
);
return Err(StatusCode::BAD_REQUEST);
}
StatusCode::BAD_REQUEST
})?;
date_entry = Some(DateEntry {
id: Uuid::new_v4().to_string(),
referenced_date: NaiveDateTime::new(
naive_date.unwrap(),
naive_date,
NaiveTime::from_hms_milli_opt(0, 0, 0, 0).unwrap(),
),
});
@ -216,26 +226,47 @@ async fn insert_entry(
}
let music_entry_id = music_entry.as_ref().map(|v| v.id.clone());
music_entry.map(|music_entry| actions::insert_music_entry(&music_entry, &mut conn).map_err(|err| {
error!("failed to insert into music_entries: {}, error: {err:?}",user.id);
music_entry
.map(|music_entry| {
actions::insert_music_entry(&music_entry, &mut conn).map_err(|err| {
error!(
"failed to insert into music_entries: {}, error: {err:?}",
user.id
);
StatusCode::INTERNAL_SERVER_ERROR
})).transpose()?;
})
})
.transpose()?;
let location_entry_id = location_entry.as_ref().map(|v| v.id.clone());
location_entry.map(|location_entry| actions::insert_location_entry(&location_entry, &mut conn).map_err(|err| {
error!("failed to insert into location_entries: {}, error: {err:?}",user.id);
location_entry
.map(|location_entry| {
actions::insert_location_entry(&location_entry, &mut conn).map_err(|err| {
error!(
"failed to insert into location_entries: {}, error: {err:?}",
user.id
);
StatusCode::INTERNAL_SERVER_ERROR
})).transpose()?;
})
})
.transpose()?;
let date_entry_id = date_entry.as_ref().map(|v| v.id.clone());
date_entry.map(|date_entry| actions::insert_date_entry(&date_entry, &mut conn).map_err(|err| {
error!("failed to insert into date_entries: {}, error: {err:?}",user.id);
date_entry
.map(|date_entry| {
actions::insert_date_entry(&date_entry, &mut conn).map_err(|err| {
error!(
"failed to insert into date_entries: {}, error: {err:?}",
user.id
);
StatusCode::INTERNAL_SERVER_ERROR
})).transpose()?;
})
})
.transpose()?;
{
use crate::database::schema::entries::dsl as entries;
let result = diesel::insert_into(entries::entries)
diesel::insert_into(entries::entries)
.values((
entries::id.eq(Uuid::new_v4().to_string()),
entries::user_id.eq(&user.id),
@ -250,15 +281,14 @@ async fn insert_entry(
entries::music_entry.eq(music_entry_id),
entries::location_entry.eq(location_entry_id),
))
.execute(&mut conn);
if let Err(err) = result {
.execute(&mut conn)
.map_err(|err| {
error!(
"failed to insert into entries: {}, error: {:?}",
user.id, err
"failed to insert into entries: {}, error: {err:?}",
user.id
);
return Err(StatusCode::INTERNAL_SERVER_ERROR);
}
StatusCode::INTERNAL_SERVER_ERROR
})?;
}
Ok(())