1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2025-02-20 16:02:39 +00:00
comunicapiv3/src/helpers/account_helper.rs

153 lines
5.0 KiB
Rust
Raw Normal View History

2020-06-29 15:53:39 +02:00
use crate::constants::database_tables_names::{USER_ACCESS_TOKENS_TABLE, USERS_TABLE};
2020-05-23 19:17:48 +02:00
use crate::data::api_client::APIClient;
2020-05-24 16:35:54 +02:00
use crate::data::error::{ExecError, ResultBoxError};
2020-07-13 13:35:25 +02:00
use crate::data::new_account::NewAccount;
2020-05-24 16:35:54 +02:00
use crate::data::user::UserID;
use crate::data::user_token::UserAccessToken;
use crate::helpers::{database, user_helper};
2020-06-26 08:58:00 +02:00
use crate::helpers::database::{DeleteQuery, InsertQuery, QueryInfo};
2020-05-24 16:35:54 +02:00
use crate::utils::crypt_utils::{crypt_pass, rand_str};
2020-07-13 13:35:25 +02:00
use crate::utils::date_utils::{mysql_date, time};
2020-05-23 19:17:48 +02:00
/// Account helper
///
/// @author Pierre Hubert
2020-07-13 13:35:25 +02:00
/// Create a new account
pub fn create(new_account: &NewAccount) -> ResultBoxError {
database::InsertQuery::new(USERS_TABLE)
.add_str("nom", &new_account.first_name)
.add_str("prenom", &new_account.last_name)
.add_str("date_creation", &mysql_date())
.add_str("mail", &new_account.email)
.add_str("password", &crypt_pass(&new_account.password)?)
.insert_drop_result()
}
2020-05-23 19:17:48 +02:00
/// Attempt to sign-in user
///
/// In this version of the api, we consider that there is only one login token required
/// This is why I returns just a simple string, the token created for the user in case of success
pub fn login_user(email: &str, password: &str, client: &APIClient) -> ResultBoxError<String> {
let user = user_helper::find_user_by_email(email)?;
2020-05-24 16:35:54 +02:00
// Validate user password
let password = crypt_pass(password)?;
if !user.password.eq(&password) {
return Err(ExecError::boxed_new("The user gave an invalid password!"));
}
2020-05-23 19:17:48 +02:00
2020-05-24 16:35:54 +02:00
// Check if we already have a login token for this user
2020-06-25 10:08:34 +02:00
if let Ok(token) = get_client_tokens(&user.id, client) {
2020-05-24 16:35:54 +02:00
return Ok(token.token);
}
2020-05-23 19:17:48 +02:00
2020-05-24 16:35:54 +02:00
// Create new login tokens
let new_token = UserAccessToken {
2020-06-25 10:08:34 +02:00
user_id: user.id.clone(),
2020-05-24 16:35:54 +02:00
client_id: client.id,
2020-05-24 17:57:47 +02:00
token: rand_str(150),
2020-05-24 16:35:54 +02:00
};
// Save it
database::insert(
InsertQuery::new(USER_ACCESS_TOKENS_TABLE)
2020-06-25 10:08:34 +02:00
.add_user_id("user_id", &new_token.user_id)
2020-05-24 16:35:54 +02:00
.add_u32("service_id", client.id)
.add_str("token1", &new_token.token)
.add_str("token2", "dummy_data")
)?;
Ok(new_token.token)
}
/// Get user login tokens
2020-06-25 10:08:34 +02:00
fn get_client_tokens(user_id: &UserID, client: &APIClient) -> ResultBoxError<UserAccessToken> {
2020-05-24 16:35:54 +02:00
database::query_row(
QueryInfo::new(USER_ACCESS_TOKENS_TABLE)
2020-06-25 10:08:34 +02:00
.cond_user_id("user_id", user_id)
2020-05-24 16:39:48 +02:00
.cond_u32("service_id", client.id),
2020-05-24 16:35:54 +02:00
|res| {
Ok(UserAccessToken {
2020-06-25 10:08:34 +02:00
user_id: res.get_user_id("user_id")?,
2020-05-24 16:35:54 +02:00
client_id: res.get_int64("service_id")? as u32,
token: res.get_str("token1")?,
})
},
)
2020-05-24 17:57:47 +02:00
}
/// Find a user ID based on login token
pub fn get_user_by_login_token(token: &str, client: &APIClient) -> ResultBoxError<UserID> {
database::query_row(
QueryInfo::new(USER_ACCESS_TOKENS_TABLE)
.cond_u32("service_id", client.id)
2020-05-24 18:02:19 +02:00
.cond("token1", token)
.add_field("user_id"),
2020-06-25 10:08:34 +02:00
|res| res.get_user_id("user_id"),
2020-05-24 17:57:47 +02:00
)
2020-05-24 19:19:07 +02:00
}
/// Check out whether an email address exists or not
pub fn exists_mail(mail: &str) -> ResultBoxError<bool> {
database::QueryInfo::new(USERS_TABLE)
.cond("mail", mail)
.exec_count()
.map(|r| r > 0)
}
2020-05-24 19:19:07 +02:00
/// Destroy a given user login tokens
2020-06-25 10:08:34 +02:00
pub fn destroy_login_tokens(id: &UserID, client: &APIClient) -> ResultBoxError<()> {
2020-05-24 19:19:07 +02:00
database::delete(DeleteQuery::new(USER_ACCESS_TOKENS_TABLE)
.cond_u32("service_id", client.id)
2020-06-25 10:08:34 +02:00
.cond_user_id("user_id", id)
2020-05-24 19:19:07 +02:00
)?;
Ok(())
2020-06-26 08:58:00 +02:00
}
/// Destroy all login tokens of a user
pub fn destroy_all_user_tokens(id: &UserID) -> ResultBoxError {
database::DeleteQuery::new(USER_ACCESS_TOKENS_TABLE)
.cond_user_id("user_id", id)
.exec()
}
/// Generate a new password reset token
pub fn generate_password_reset_token(user_id: &UserID) -> ResultBoxError<String> {
let token = rand_str(255);
database::UpdateInfo::new(USERS_TABLE)
.cond_user_id("ID", user_id)
.set_str("password_reset_token", &token)
.set_u64("password_reset_token_time_create", time())
.exec()?;
Ok(token)
}
2020-06-26 08:58:00 +02:00
/// Check out whether a virtual directory is taken by a user or not
pub fn check_user_directory_availability(dir: &str, user_id: Option<UserID>) -> ResultBoxError<bool> {
let found_user = user_helper::find_user_by_virtual_directory(dir);
match (found_user, user_id) {
// A user was found, but we did not specify a user
(Ok(_), None) => Ok(false),
// A user was found, and we specified a user ID, we check if the IDs are the same
(Ok(user), Some(id)) => Ok(user.id == id),
// No user was found, virtual directory is considered as available
(Err(_), _) => Ok(true)
}
2020-06-29 15:53:39 +02:00
}
/// Update the last activity of a user
pub fn update_last_activity(user_id: &UserID) -> ResultBoxError {
database::UpdateInfo::new(USERS_TABLE)
.cond_user_id("ID", user_id)
.set_u64("last_activity", time())
.exec()
2020-05-23 19:17:48 +02:00
}