1
use std::collections::HashMap;
2

            
3
use log::error;
4

            
5
use sylvia_iot_corelib::{err::ErrResp, role::Role};
6

            
7
use super::super::State as AppState;
8
use crate::models::{
9
    application::{Application, QueryCond as ApplicationQueryCond},
10
    device::{Device, QueryCond as DeviceQueryCond},
11
    network::{Network, QueryCond as NetworkQueryCond},
12
    unit::{QueryCond as UnitQueryCond, Unit},
13
};
14

            
15
/// To check if the user ID can access the unit. Choose `only_owner` to check if the user is the
16
/// owner or one of members.
17
///
18
/// # Errors
19
///
20
/// Returns Ok if the unit is found or not. Otherwise errors will be returned.
21
3528
pub async fn check_unit(
22
3528
    fn_name: &str,
23
3528
    user_id: &str,
24
3528
    roles: &HashMap<String, bool>,
25
3528
    unit_id: &str,
26
3528
    only_owner: bool,
27
3528
    state: &AppState,
28
3528
) -> Result<Option<Unit>, ErrResp> {
29
3528
    let mut cond = UnitQueryCond {
30
3528
        unit_id: Some(unit_id),
31
3528
        ..Default::default()
32
3528
    };
33
3528
    if !Role::is_role(roles, Role::ADMIN) && !Role::is_role(roles, Role::MANAGER) {
34
2094
        if only_owner {
35
798
            cond.owner_id = Some(user_id);
36
1296
        } else {
37
1296
            cond.member_id = Some(user_id);
38
1296
        }
39
1434
    }
40
3528
    match state.model.unit().get(&cond).await {
41
        Err(e) => {
42
            error!("[{}] check unit error: {}", fn_name, e);
43
            return Err(ErrResp::ErrDb(Some(format!("check unit error: {}", e))));
44
        }
45
3528
        Ok(unit) => Ok(unit),
46
    }
47
3528
}
48

            
49
/// To check if the user ID can access the application. Choose `only_owner` to check if the user is
50
/// the unit owner or one of unit members.
51
///
52
/// # Errors
53
///
54
/// Returns Ok if the application is found or not. Otherwise errors will be returned.
55
642
pub async fn check_application(
56
642
    fn_name: &str,
57
642
    application_id: &str,
58
642
    user_id: &str,
59
642
    only_owner: bool, // to check if this `user_id` is the owner.
60
642
    roles: &HashMap<String, bool>,
61
642
    state: &AppState,
62
642
) -> Result<Option<Application>, ErrResp> {
63
642
    let cond = ApplicationQueryCond {
64
642
        application_id: Some(application_id),
65
642
        ..Default::default()
66
642
    };
67
642
    let application = match state.model.application().get(&cond).await {
68
        Err(e) => {
69
            error!("[{}] get error: {}", fn_name, e);
70
            return Err(ErrResp::ErrDb(Some(e.to_string())));
71
        }
72
642
        Ok(application) => match application {
73
66
            None => return Ok(None),
74
576
            Some(application) => application,
75
576
        },
76
576
    };
77
576
    if Role::is_role(roles, Role::ADMIN) || Role::is_role(roles, Role::MANAGER) {
78
330
        return Ok(Some(application));
79
246
    }
80
246
    let unit_id = application.unit_id.as_str();
81
246
    match check_unit(fn_name, user_id, &roles, unit_id, only_owner, &state).await? {
82
66
        None => Ok(None),
83
180
        Some(_) => Ok(Some(application)),
84
    }
85
642
}
86

            
87
/// To check if the user ID can access the network. Choose `only_owner` to check if the user is the
88
/// unit owner or one of unit members.
89
///
90
/// # Errors
91
///
92
/// Returns OK if the network is found or not. Otherwise errors will be returned.
93
534
pub async fn check_network(
94
534
    fn_name: &str,
95
534
    network_id: &str,
96
534
    user_id: &str,
97
534
    only_owner: bool, // to check if this `user_id` is the owner.
98
534
    roles: &HashMap<String, bool>,
99
534
    state: &AppState,
100
534
) -> Result<Option<Network>, ErrResp> {
101
534
    let cond = NetworkQueryCond {
102
534
        network_id: Some(network_id),
103
534
        ..Default::default()
104
534
    };
105
534
    let network = match state.model.network().get(&cond).await {
106
        Err(e) => {
107
            error!("[{}] get error: {}", fn_name, e);
108
            return Err(ErrResp::ErrDb(Some(e.to_string())));
109
        }
110
534
        Ok(network) => match network {
111
72
            None => return Ok(None),
112
462
            Some(network) => network,
113
462
        },
114
462
    };
115
462
    if Role::is_role(roles, Role::ADMIN) || Role::is_role(roles, Role::MANAGER) {
116
240
        return Ok(Some(network));
117
222
    }
118
222
    let unit_id = match network.unit_id.as_ref() {
119
48
        None => return Ok(None),
120
174
        Some(unit_id) => unit_id.as_str(),
121
174
    };
122
174
    match check_unit(fn_name, user_id, &roles, unit_id, only_owner, &state).await? {
123
36
        None => Ok(None),
124
138
        Some(_) => Ok(Some(network)),
125
    }
126
534
}
127

            
128
/// To check if the user ID can access the device. Choose `only_owner` to check if the user is the
129
/// unit owner or one of unit members.
130
///
131
/// # Errors
132
///
133
/// Returns OK if the device is found or not. Otherwise errors will be returned.
134
498
pub async fn check_device(
135
498
    fn_name: &str,
136
498
    device_id: &str,
137
498
    user_id: &str,
138
498
    only_owner: bool, // to check if this `user_id` is the owner.
139
498
    roles: &HashMap<String, bool>,
140
498
    state: &AppState,
141
498
) -> Result<Option<Device>, ErrResp> {
142
498
    let cond = DeviceQueryCond {
143
498
        device_id: Some(device_id),
144
498
        ..Default::default()
145
498
    };
146
498
    let device = match state.model.device().get(&cond).await {
147
        Err(e) => {
148
            error!("[{}] get error: {}", fn_name, e);
149
            return Err(ErrResp::ErrDb(Some(e.to_string())));
150
        }
151
498
        Ok(device) => match device {
152
30
            None => return Ok(None),
153
468
            Some(device) => device,
154
468
        },
155
468
    };
156
468
    let unit_id = device.unit_id.as_str();
157
468
    match check_unit(fn_name, user_id, roles, unit_id, only_owner, state).await? {
158
108
        None => Ok(None),
159
360
        Some(_) => Ok(Some(device)),
160
    }
161
498
}
162

            
163
/// To generate a key for managing managers. Empty unit for public networks.
164
812
pub fn gen_mgr_key(unit: &str, name: &str) -> String {
165
812
    format!("{}.{}", unit, name)
166
812
}