pub mod admin;
pub mod jobs;
pub mod packages;
pub mod stats;
pub mod users;
use std::future::Future;
use crate::model::auth::ROLE_ADMIN;
use crate::utils::apierror::{error_forbidden, error_not_found, error_unauthorized, specialize, ApiError};
use crate::utils::db::{AppTransaction, RwSqlitePool};
pub async fn db_transaction_read<F, FUT, T, E>(pool: &RwSqlitePool, workload: F) -> Result<T, E>
where
F: FnOnce(Database) -> FUT,
FUT: Future<Output = Result<T, E>>,
E: From<sqlx::Error>,
{
let transaction = pool.acquire_read().await?;
let result = {
let database = Database {
transaction: transaction.clone(),
};
workload(database).await
};
let transaction = transaction.into_original().unwrap();
match result {
Ok(t) => {
transaction.commit().await?;
Ok(t)
}
Err(error) => {
transaction.rollback().await?;
Err(error)
}
}
}
pub async fn db_transaction_write<F, FUT, T, E>(pool: &RwSqlitePool, operation: &'static str, workload: F) -> Result<T, E>
where
F: FnOnce(Database) -> FUT,
FUT: Future<Output = Result<T, E>>,
E: From<sqlx::Error>,
{
let transaction = pool.acquire_write(operation).await?;
let result = {
let database = Database {
transaction: transaction.clone(),
};
workload(database).await
};
let transaction = transaction.into_original().unwrap();
match result {
Ok(t) => {
transaction.commit().await?;
Ok(t)
}
Err(error) => {
transaction.rollback().await?;
Err(error)
}
}
}
pub struct Database {
pub(crate) transaction: AppTransaction,
}
impl Database {
pub async fn check_is_user(&self, email: &str) -> Result<i64, ApiError> {
let maybe_row = sqlx::query!("SELECT id FROM RegistryUser WHERE isActive = TRUE AND email = $1", email)
.fetch_optional(&mut *self.transaction.borrow().await)
.await?;
let row = maybe_row.ok_or_else(error_unauthorized)?;
Ok(row.id)
}
pub async fn get_is_admin(&self, uid: i64) -> Result<bool, ApiError> {
let roles = sqlx::query!("SELECT roles FROM RegistryUser WHERE id = $1", uid)
.fetch_optional(&mut *self.transaction.borrow().await)
.await?
.ok_or_else(error_forbidden)?
.roles;
Ok(roles.split(',').any(|role| role.trim() == ROLE_ADMIN))
}
pub async fn check_is_admin(&self, uid: i64) -> Result<(), ApiError> {
let is_admin = self.get_is_admin(uid).await?;
if is_admin {
Ok(())
} else {
Err(error_forbidden())
}
}
pub async fn check_crate_exists(&self, package: &str, version: &str) -> Result<(), ApiError> {
let _row = sqlx::query!(
"SELECT id FROM PackageVersion WHERE package = $1 AND version = $2 LIMIT 1",
package,
version
)
.fetch_optional(&mut *self.transaction.borrow().await)
.await?
.ok_or_else(error_not_found)?;
Ok(())
}
pub async fn check_is_crate_manager(&self, uid: i64, package: &str) -> Result<i64, ApiError> {
if self.check_is_admin(uid).await.is_ok() {
return Ok(uid);
}
let row = sqlx::query!(
"SELECT id from PackageOwner WHERE package = $1 AND owner = $2 LIMIT 1",
package,
uid
)
.fetch_optional(&mut *self.transaction.borrow().await)
.await?;
match row {
Some(_) => Ok(uid),
None => Err(specialize(
error_forbidden(),
String::from("User is not an owner of this package"),
)),
}
}
}