183 lines
4.6 KiB
Rust
183 lines
4.6 KiB
Rust
use app_error::AppError;
|
|
use sqlx::postgres::PgArguments;
|
|
use sqlx::types::JsonValue;
|
|
use sqlx::{Arguments, Executor, PgPool, Postgres};
|
|
use tracing::{instrument, warn};
|
|
use uuid::Uuid;
|
|
|
|
/// Updates the user's details in the `af_user` table.
|
|
///
|
|
/// This function allows for updating the user's name, email, and metadata based on the provided UUID.
|
|
/// If the `metadata` is provided, it merges the new metadata with the existing one, with the new values
|
|
/// overriding the old ones in case of conflicts.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `pool` - A reference to the database connection pool.
|
|
/// * `user_uuid` - The UUID of the user to be updated.
|
|
/// * `name` - An optional new name for the user.
|
|
/// * `email` - An optional new email for the user.
|
|
/// * `metadata` - An optional JSON value containing new metadata for the user.
|
|
///
|
|
#[instrument(skip_all, err)]
|
|
#[inline]
|
|
pub async fn update_user(
|
|
pool: &PgPool,
|
|
user_uuid: &uuid::Uuid,
|
|
name: Option<String>,
|
|
email: Option<String>,
|
|
metadata: Option<JsonValue>,
|
|
) -> Result<(), AppError> {
|
|
let mut set_clauses = Vec::new();
|
|
let mut args = PgArguments::default();
|
|
let mut args_num = 0;
|
|
|
|
if let Some(n) = name {
|
|
args_num += 1;
|
|
set_clauses.push(format!("name = ${}", args_num));
|
|
args.add(n);
|
|
}
|
|
|
|
if let Some(e) = email {
|
|
args_num += 1;
|
|
set_clauses.push(format!("email = ${}", args_num));
|
|
args.add(e);
|
|
}
|
|
|
|
if let Some(m) = metadata {
|
|
args_num += 1;
|
|
// Merge existing metadata with new metadata
|
|
set_clauses.push(format!("metadata = metadata || ${}", args_num));
|
|
args.add(m);
|
|
}
|
|
|
|
if set_clauses.is_empty() {
|
|
warn!("No update params provided");
|
|
return Ok(());
|
|
}
|
|
|
|
// where
|
|
args_num += 1;
|
|
let query = format!(
|
|
"UPDATE af_user SET {} WHERE uuid = ${}",
|
|
set_clauses.join(", "),
|
|
args_num
|
|
);
|
|
args.add(user_uuid);
|
|
|
|
sqlx::query_with(&query, args).execute(pool).await?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Attempts to create a new user in the database if they do not already exist.
|
|
///
|
|
/// This function will:
|
|
/// - Insert a new user record into the `af_user` table if the email is unique.
|
|
/// - If the user is newly created, it will also:
|
|
/// - Create a new workspace for the user in the `af_workspace` table.
|
|
/// - Assign the user a role in the `af_workspace_member` table.
|
|
/// - Add the user to the `af_collab_member` table with the appropriate permissions.
|
|
///
|
|
/// # Returns
|
|
/// A `Result` containing the workspace_id of the user's newly created workspace
|
|
#[instrument(skip(executor), err)]
|
|
#[inline]
|
|
pub async fn create_user<'a, E: Executor<'a, Database = Postgres>>(
|
|
executor: E,
|
|
uid: i64,
|
|
user_uuid: &Uuid,
|
|
email: &str,
|
|
name: &str,
|
|
) -> Result<String, AppError> {
|
|
let row = sqlx::query!(
|
|
r#"
|
|
WITH ins_user AS (
|
|
INSERT INTO af_user (uid, uuid, email, name)
|
|
VALUES ($1, $2, $3, $4)
|
|
ON CONFLICT(email) DO NOTHING
|
|
RETURNING uid
|
|
),
|
|
owner_role AS (
|
|
SELECT id FROM af_roles WHERE name = 'Owner'
|
|
),
|
|
ins_workspace AS (
|
|
INSERT INTO af_workspace (owner_uid)
|
|
SELECT uid FROM ins_user
|
|
RETURNING workspace_id, owner_uid
|
|
),
|
|
ins_collab_member AS (
|
|
INSERT INTO af_collab_member (uid, oid, permission_id)
|
|
SELECT ins_workspace.owner_uid,
|
|
ins_workspace.workspace_id::TEXT,
|
|
(SELECT permission_id FROM af_role_permissions WHERE role_id = owner_role.id)
|
|
FROM ins_workspace, owner_role
|
|
)
|
|
SELECT workspace_id FROM ins_workspace;
|
|
"#,
|
|
uid,
|
|
user_uuid,
|
|
email,
|
|
name
|
|
)
|
|
.fetch_one(executor)
|
|
.await?;
|
|
|
|
Ok(row.workspace_id.to_string())
|
|
}
|
|
|
|
#[inline]
|
|
#[instrument(level = "trace", skip(executor), err)]
|
|
pub async fn select_uid_from_uuid<'a, E: Executor<'a, Database = Postgres>>(
|
|
executor: E,
|
|
user_uuid: &Uuid,
|
|
) -> Result<i64, AppError> {
|
|
let uid = sqlx::query!(
|
|
r#"
|
|
SELECT uid FROM af_user WHERE uuid = $1
|
|
"#,
|
|
user_uuid
|
|
)
|
|
.fetch_one(executor)
|
|
.await?
|
|
.uid;
|
|
Ok(uid)
|
|
}
|
|
|
|
#[inline]
|
|
pub async fn select_uid_from_email<'a, E: Executor<'a, Database = Postgres>>(
|
|
executor: E,
|
|
email: &str,
|
|
) -> Result<i64, AppError> {
|
|
let uid = sqlx::query!(
|
|
r#"
|
|
SELECT uid FROM af_user WHERE email = $1
|
|
"#,
|
|
email
|
|
)
|
|
.fetch_one(executor)
|
|
.await?
|
|
.uid;
|
|
Ok(uid)
|
|
}
|
|
|
|
#[inline]
|
|
pub async fn is_user_exist<'a, E: Executor<'a, Database = Postgres>>(
|
|
executor: E,
|
|
user_uuid: &Uuid,
|
|
) -> Result<bool, AppError> {
|
|
let exists = sqlx::query_scalar!(
|
|
r#"
|
|
SELECT EXISTS(
|
|
SELECT 1
|
|
FROM af_user
|
|
WHERE uuid = $1
|
|
) AS user_exists;
|
|
"#,
|
|
user_uuid
|
|
)
|
|
.fetch_one(executor)
|
|
.await?;
|
|
|
|
Ok(exists.unwrap_or(false))
|
|
}
|