darkwing/server/services/
user_services.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
use mockall::automock;
use std::sync::Arc;
use tracing::info;

use async_trait::async_trait;

use crate::{
  database::{
    team::{DynTeamsRepository, Plan},
    user::DynUsersRepository,
  },
  server::{
    dtos::{team_dto::ResponseTeamDto, user_dto::ResponseUserDto},
    error::AppResult,
  },
};

/// A reference counter for our user service allows us safely pass instances
/// user utils around which themselves depend on the user repostiory, and
/// ultimately, our MySQL connection pool.
pub type DynUsersService = Arc<dyn UsersServiceTrait + Send + Sync>;

#[automock]
#[async_trait]
pub trait UsersServiceTrait {
  async fn get_user_by_id(&self, user_id: u64) -> AppResult<ResponseUserDto>;
  async fn get_team_by_id(&self, team_id: i64) -> AppResult<ResponseTeamDto>;
  fn is_fully_free_plan(&self, team: &ResponseTeamDto) -> bool;
  fn does_plan_allows_scenarios(&self, plan: Plan) -> bool;
}

#[derive(Clone)]
pub struct UsersService {
  user_repository: DynUsersRepository,
  team_repository: DynTeamsRepository,
}

impl UsersService {
  pub fn new(
    user_repository: DynUsersRepository,
    team_repository: DynTeamsRepository,
  ) -> Self {
    Self {
      user_repository,
      team_repository,
    }
  }
}

#[async_trait]
impl UsersServiceTrait for UsersService {
  async fn get_user_by_id(&self, user_id: u64) -> AppResult<ResponseUserDto> {
    info!("retrieving user {:?}", user_id);

    let user = self.user_repository.get_user_by_id(user_id).await?;

    info!("user found with username {:?}", user.username);

    Ok(user.into_dto())
  }

  async fn get_team_by_id(&self, team_id: i64) -> AppResult<ResponseTeamDto> {
    info!("retrieving team id: {:?}", team_id);

    let team = self.team_repository.get_team_by_id(team_id).await?;

    Ok(team.into())
  }

  fn is_fully_free_plan(&self, team: &ResponseTeamDto) -> bool {
    team.plan == Plan::Free && team.browser_profiles_limit == 10
  }

  fn does_plan_allows_scenarios(&self, plan: Plan) -> bool {
    plan == Plan::Paid
  }
}