bazzar/api/src/actors/database/accounts.rs

144 lines
3.3 KiB
Rust
Raw Normal View History

use crate::async_handler;
use actix::{Handler, ResponseActFuture, WrapFuture};
use sqlx::PgPool;
use crate::database::Database;
use crate::model::{AccountId, Email, FullAccount, Login, PassHash, Role};
use super::Result;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Can't create account")]
CantCreate,
#[error("Can't find account does to lack of identity")]
NoIdentity,
#[error("Account does not exists")]
NotExists,
#[error("Failed to load all accounts")]
All,
}
#[derive(actix::Message)]
#[rtype(result = "Result<Vec<FullAccount>>")]
pub struct AllAccounts;
async_handler!(AllAccounts, all_accounts, Vec<FullAccount>);
pub async fn all_accounts(_msg: AllAccounts, pool: PgPool) -> Result<Vec<FullAccount>> {
sqlx::query_as(
r#"
SELECT id, email, login, pass_hash, role
FROM accounts
"#,
)
.fetch_all(&pool)
.await
.map_err(|e| {
log::error!("{e:?}");
super::Error::Account(Error::All)
})
}
#[derive(actix::Message)]
#[rtype(result = "Result<FullAccount>")]
pub struct CreateAccount {
pub email: Email,
pub login: Login,
pub pass_hash: PassHash,
pub role: Role,
}
async_handler!(CreateAccount, create_account, FullAccount);
async fn create_account(msg: CreateAccount, db: PgPool) -> Result<FullAccount> {
sqlx::query_as(
r#"
INSERT INTO accounts (login, email, role, pass_hash)
VALUES ($1, $2, $3, $4)
RETURNING id, email, login, pass_hash, role
"#,
)
.bind(msg.login)
.bind(msg.email)
.bind(msg.role)
.bind(msg.pass_hash)
.fetch_one(&db)
.await
.map_err(|e| {
log::error!("{e:?}");
super::Error::Account(Error::CantCreate)
})
}
#[derive(actix::Message)]
#[rtype(result = "Result<FullAccount>")]
pub struct FindAccount {
pub account_id: AccountId,
}
async_handler!(FindAccount, find_account, FullAccount);
async fn find_account(msg: FindAccount, db: PgPool) -> Result<FullAccount> {
sqlx::query_as(
r#"
SELECT id, email, login, pass_hash, role
FROM accounts
WHERE id = $1
"#,
)
.bind(msg.account_id)
.fetch_one(&db)
.await
.map_err(|e| {
log::error!("{e:?}");
super::Error::Account(Error::NotExists)
})
}
#[derive(actix::Message)]
#[rtype(result = "Result<FullAccount>")]
pub struct AccountByIdentity {
pub login: Option<Login>,
pub email: Option<Email>,
}
async_handler!(AccountByIdentity, account_by_identity, FullAccount);
async fn account_by_identity(msg: AccountByIdentity, db: PgPool) -> Result<FullAccount> {
match (msg.login, msg.email) {
(Some(login), None) => sqlx::query_as(
r#"
SELECT id, email, login, pass_hash, role
FROM accounts
WHERE login = $1
"#,
)
.bind(login),
(None, Some(email)) => sqlx::query_as(
r#"
SELECT id, email, login, pass_hash, role
FROM accounts
WHERE email = $1
"#,
)
.bind(email),
(Some(login), Some(email)) => sqlx::query_as(
r#"
SELECT id, email, login, pass_hash, role
FROM accounts
WHERE login = $1 AND email = $2
"#,
)
.bind(login)
.bind(email),
_ => return Err(super::Error::Account(Error::NoIdentity)),
}
.fetch_one(&db)
.await
.map_err(|e| {
log::error!("{e:?}");
super::Error::Account(Error::CantCreate)
})
}