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")
  }
}