Added QoL error handling

This commit is contained in:
xeovalyte 2024-10-04 17:00:09 +02:00
parent a53ad775dc
commit 2bca9bba60
Signed by: xeovalyte
SSH Key Fingerprint: SHA256:kSQDrQDmKzljJzfGYcd3m9RqHi4h8rSwkZ3sQ9kBURo
4 changed files with 56 additions and 31 deletions

View File

@ -318,7 +318,7 @@ async fn relate_member(registration_token: String) -> Result<(), ServerFnError>
let user = Session::fetch_current_user().await?; let user = Session::fetch_current_user().await?;
let member_id = Member::fetch_from_registration_token(registration_token).await?; let member_id = Member::fetch_from_registration_token(registration_token).await?;
user.relate_member(member_id.id).await?; user.relate_member(&member_id.id).await?;
Ok(()) Ok(())
} }
@ -326,6 +326,6 @@ async fn relate_member(registration_token: String) -> Result<(), ServerFnError>
async fn delete_member_relation(member_id: String) -> Result<(), ServerFnError> { async fn delete_member_relation(member_id: String) -> Result<(), ServerFnError> {
let user = Session::fetch_current_user().await?; let user = Session::fetch_current_user().await?;
user.remove_relation(member_id).await?; user.remove_relation(&member_id).await?;
Ok(()) Ok(())
} }

View File

@ -34,6 +34,8 @@ impl Member {
pub async fn fetch_all() -> Result<Vec<Self>, surrealdb::Error> { pub async fn fetch_all() -> Result<Vec<Self>, surrealdb::Error> {
let mut res = DB.query("SELECT id, name.first, name.full, hours, groups, diploma, registration_token FROM member").await?; let mut res = DB.query("SELECT id, name.first, name.full, hours, groups, diploma, registration_token FROM member").await?;
res = res.check()?;
let members: Vec<Self> = res.take(0)?; let members: Vec<Self> = res.take(0)?;
Ok(members) Ok(members)
@ -47,6 +49,8 @@ impl Member {
.bind(("registration_token", registration_token)) .bind(("registration_token", registration_token))
.await?; .await?;
res = res.check()?;
match res.take(0)? { match res.take(0)? {
Some(m) => Ok(m), Some(m) => Ok(m),
None => Err(crate::Error::NoDocument), None => Err(crate::Error::NoDocument),
@ -61,6 +65,8 @@ impl Member {
.bind(("user_id", user_id)) .bind(("user_id", user_id))
.await?; .await?;
res = res.check()?;
let members: Vec<Self> = res.take(0)?; let members: Vec<Self> = res.take(0)?;
Ok(members) Ok(members)

View File

@ -24,6 +24,8 @@ impl Session {
.bind(("user_id", user_id)) .bind(("user_id", user_id))
.await?; .await?;
res = res.check()?;
let session: Option<Self> = res.take(0)?; let session: Option<Self> = res.take(0)?;
match session { match session {
@ -67,6 +69,8 @@ impl Session {
.bind(("session_token", session_token)) .bind(("session_token", session_token))
.await?; .await?;
res = res.check()?;
let user: Option<User> = res.take(0)?; let user: Option<User> = res.take(0)?;
match user { match user {
@ -111,10 +115,13 @@ impl Session {
} }
pub async fn delete_session(user_id: String) -> Result<(), crate::Error> { pub async fn delete_session(user_id: String) -> Result<(), crate::Error> {
DB.query("DELETE ONLY session WHERE user = type::thing('user', $user_id)") let res = DB
.query("DELETE ONLY session WHERE user = type::thing('user', $user_id)")
.bind(("user_id", user_id)) .bind(("user_id", user_id))
.await?; .await?;
res.check()?;
Ok(()) Ok(())
} }

View File

@ -3,7 +3,10 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "server")] #[cfg(feature = "server")]
use crate::util::surrealdb::{thing_to_string, DB}; use crate::util::surrealdb::{thing_to_string, DB};
#[cfg(feature = "server")] #[cfg(feature = "server")]
use surrealdb::sql::statements::{BeginStatement, CommitStatement}; use surrealdb::sql::{
statements::{BeginStatement, CommitStatement},
Thing,
};
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)] #[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
pub struct User { pub struct User {
@ -37,6 +40,8 @@ impl User {
.query(CommitStatement::default()) .query(CommitStatement::default())
.await?; .await?;
res = res.check()?;
let user: Option<Self> = res.take(0)?; let user: Option<Self> = res.take(0)?;
match user { match user {
@ -45,36 +50,40 @@ impl User {
} }
} }
pub async fn relate_member(&self, member_id: String) -> Result<(), crate::Error> { pub async fn relate_member(&self, member_id: &str) -> Result<(), crate::Error> {
let mut res = DB let res = DB
.query(" .query("
IF (SELECT * FROM ONLY user_to_member WHERE in = type::thing('user', $user_id) AND out = type::thing('member', $member_id) LIMIT 1) == NONE { IF (SELECT id FROM ONLY user_to_member WHERE in = $user AND out = $member LIMIT 1) == NONE {
RELATE ONLY (type::thing('user', $user_id))->user_to_member->(type::thing('member', $member_id)); RELATE ONLY $user->user_to_member->$member;
} ELSE { } ELSE {
THROW 'Relation already exists' THROW 'Relation already exists'
}; };
") ")
.bind(("user_id", self.id.to_string())) .bind(("user", Thing::from(("user", self.id.as_str()))))
.bind(("member_id", member_id)) .bind(("member", Thing::from(("member", member_id))))
.await?; .await?;
if res.take_errors().len() != 0 { res.check()?;
return Err(crate::Error::NoDocument);
}
Ok(()) Ok(())
} }
pub async fn remove_relation(&self, member_id: String) -> Result<(), crate::Error> { pub async fn remove_relation(&self, member_id: &str) -> Result<(), crate::Error> {
let mut res = DB let res = DB
.query("DELETE type::thing('user', $user_id)->user_to_member WHERE out = type::thing('member', $member_id)") .query(
.bind(("user_id", self.id.clone())) "
.bind(("member_id", member_id)) IF (SELECT count() FROM user_to_member WHERE in = $user GROUP ALL)[0].count == 1 {
THROW 'At least one relation is required'
} ELSE {
DELETE $user->user_to_member WHERE out = $member
};
",
)
.bind(("user", Thing::from(("user", self.id.as_str()))))
.bind(("member", Thing::from(("member", member_id))))
.await?; .await?;
if res.take_errors().len() != 0 { res.check()?;
return Err(crate::Error::NoDocument);
}
Ok(()) Ok(())
} }
@ -85,9 +94,12 @@ impl User {
) -> Result<String, crate::Error> { ) -> Result<String, crate::Error> {
let mut res = DB let mut res = DB
.query("SELECT VALUE id FROM user WHERE email = $email AND crypto::argon2::compare(password, $password)") .query("SELECT VALUE id FROM user WHERE email = $email AND crypto::argon2::compare(password, $password)")
.bind(("email", email)).bind(("password", password)) .bind(("email", email))
.bind(("password", password))
.await?; .await?;
res = res.check()?;
let id: Option<String> = res.take(0)?; let id: Option<String> = res.take(0)?;
match id { match id {
@ -98,11 +110,13 @@ impl User {
pub async fn change_email(&self, new_email: String) -> Result<String, crate::Error> { pub async fn change_email(&self, new_email: String) -> Result<String, crate::Error> {
let mut res = DB let mut res = DB
.query("UPDATE type::thing('user', $user_id) SET email = $email RETURN VALUE email") .query("UPDATE $user SET email = $email RETURN VALUE email")
.bind(("user_id", self.id.to_string())) .bind(("user", Thing::from(("user", self.id.as_str()))))
.bind(("email", new_email)) .bind(("email", new_email))
.await?; .await?;
res = res.check()?;
let email: Option<String> = res.take(0)?; let email: Option<String> = res.take(0)?;
match email { match email {
@ -116,26 +130,24 @@ impl User {
old_password: String, old_password: String,
new_password: String, new_password: String,
) -> Result<(), crate::Error> { ) -> Result<(), crate::Error> {
let mut res = DB let res = DB
.query( .query(
" "
LET $user = (SELECT * FROM ONLY type::thing('user', $user_id)); LET $user = (SELECT * FROM ONLY $user);
IF crypto::argon2::compare($user.password, $old_password) { IF crypto::argon2::compare($user.password, $old_password) {
UPDATE type::thing('user', $user_id) SET password = crypto::argon2::generate($new_password) UPDATE $user SET password = crypto::argon2::generate($new_password)
} ELSE { } ELSE {
THROW 'Password dit not match' THROW 'Password dit not match'
}; };
", ",
) )
.bind(("user_id", self.id.to_string())) .bind(("user", Thing::from(("user", self.id.as_str()))))
.bind(("old_password", old_password)) .bind(("old_password", old_password))
.bind(("new_password", new_password)) .bind(("new_password", new_password))
.await?; .await?;
if res.take_errors().len() != 0 { res.check()?;
return Err(crate::Error::NoDocument);
}
Ok(()) Ok(())
} }