darkwing/database/browser_profile_access/repository.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
//! Repository module for managing browser profile access data.
//!
//! This module provides functionality to interact with the database for browser
//! profile access-related operations, including retrieving access permissions
//! and teamlead relationships.
use std::sync::Arc;
use crate::database::Database;
use crate::server::dtos::browser_profile_dto::MiniBrowserProfile;
use anyhow::Context as _;
use async_trait::async_trait;
use mockall::automock;
use sqlx::{query_as, query_scalar};
use super::BrowserProfileAccess;
/// A thread-safe reference-counted pointer to a
/// `BrowserProfileAccessRepository` implementation.
///
/// This type alias is used to manage shared access to the repository across
/// multiple threads while maintaining proper reference counting for the
/// connection pool.
pub type DynBrowserProfileAccessRepository =
Arc<dyn BrowserProfileAccessRepository + Send + Sync>;
/// Defines the interface for accessing browser profile access data.
///
/// This trait provides methods to query browser profile access permissions
/// and related teamlead information from the database.
#[automock]
#[async_trait]
pub trait BrowserProfileAccessRepository {
/// Retrieves browser profile access permissions for a specific user and
/// profile.
///
/// # Arguments
/// * `user_id` - The ID of the user whose permissions are being queried
/// * `browser_profile_id` - The ID of the browser profile to check
/// permissions for
///
/// # Returns
/// * `Ok(Some(BrowserProfileAccess))` if permissions are found
/// * `Ok(None)` if no permissions exist
/// * `Err` if there was a database error
async fn get_by_user_id_and_browser_profile_id(
&self,
user_id: i64,
browser_profile_id: i64,
) -> anyhow::Result<Option<BrowserProfileAccess>>;
/// Retrieves the teamlead ID associated with a browser profile.
///
/// # Arguments
/// * `browser_profile` - The browser profile to look up teamlead information
/// for
///
/// # Returns
/// * `Ok(Some(i64))` if a teamlead ID is found
/// * `Ok(None)` if no teamlead relationship exists
/// * `Err` if there was a database error
async fn get_teamlead_id_by_browser_profile(
&self,
browser_profile: MiniBrowserProfile,
) -> anyhow::Result<Option<i64>>;
}
/// Implementation of `BrowserProfileAccessRepository` for the main database.
#[async_trait]
impl BrowserProfileAccessRepository for Database {
async fn get_by_user_id_and_browser_profile_id(
&self,
user_id: i64,
browser_profile_id: i64,
) -> anyhow::Result<Option<BrowserProfileAccess>> {
query_as!(
BrowserProfileAccess,
r#"
SELECT `roleId`, `usage`, `view`, `update`, `share`, `delete`, `transfer`
FROM browser_profile_access
WHERE browserProfileId = ?
AND userId = ?
AND deleted_at IS NULL
LIMIT 1;
"#,
browser_profile_id,
user_id,
)
.fetch_optional(&self.pool)
.await
.context("failed to fetch browser profile access")
}
async fn get_teamlead_id_by_browser_profile(
&self,
browser_profile: MiniBrowserProfile,
) -> anyhow::Result<Option<i64>> {
// TODO(@tltsutltsu): this is a mess, and I do not know _why_ this should be this way, but it is how it is in current `anty-sync` (https://github.com/dolphin-anty/anty-sync/commit/3116c77d47a7db972ec900ec38fea49365601056, commit by Nikolai Golomolzin), and we should transfer the logic as is and fix it later.
query_scalar!(
r#"
SELECT teamleadId FROM user_teamlead WHERE userId = ? OR `userId` in (SELECT `userId` FROM `browser_profile_access` WHERE `browserProfileId` = ? AND deleted_at is null) LIMIT 1;
"#,
browser_profile.user_id,
browser_profile.id,
)
.fetch_optional(&self.pool)
.await
.context("failed to fetch browser profile access")
}
}