backend/service/
map_access_control.rs

1use actix_http::StatusCode;
2
3use crate::model::entity::Map;
4#[cfg(feature = "access_control")]
5use crate::model::entity::MapCollaborator;
6#[cfg(feature = "access_control")]
7use crate::model::r#enum::privacy_access_control::AccessControl;
8use crate::{
9    config::{auth::user_info::UserInfo, data::SharedPool},
10    error::ServiceError,
11};
12
13/// Order of the variants is important for comparison.
14#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
15pub enum AccessRights {
16    /// The user has no rights.
17    None,
18    /// The user has read rights to a map.
19    Read,
20    /// The user has read/write rights to a map.
21    Write,
22}
23
24/// Check if the current user has the correct permissions to view or perform an action on a map.
25///
26/// # Errors
27/// If the connection to the database could not be established.
28/// If the user does not have the required rights for performing an action on a map.
29#[cfg(feature = "access_control")]
30pub async fn check_permissions(
31    map_id: i32,
32    pool: &SharedPool,
33    user_info: UserInfo,
34    required_rights: AccessRights,
35) -> Result<(), ServiceError> {
36    let mut conn = pool.get().await?;
37
38    let map_id_i64 = i64::from(map_id);
39    let result = Map::find_by_id(map_id_i64, &mut conn).await?;
40
41    if result.created_by == user_info.id || user_info.is_admin() {
42        return Ok(());
43    }
44
45    let is_collaborator =
46        MapCollaborator::contains_user_as_collaborator(user_info.id, map_id_i64, &mut conn).await?;
47
48    if is_collaborator {
49        return Ok(());
50    }
51
52    let actual_rights = result.privacy.check_access(&user_info);
53
54    if actual_rights == AccessRights::None {
55        return Err(ServiceError::new(StatusCode::NOT_FOUND, "Map not found"));
56    } else if actual_rights < required_rights {
57        return Err(ServiceError::new(
58            StatusCode::FORBIDDEN,
59            "no permissions to update data",
60        ));
61    }
62    Ok(())
63}
64
65/// Check if the current user has the correct permissions to create a map.
66///
67/// # Errors
68/// If the user does not have the required rights for creating a map.
69pub async fn check_creation_permission(user_info: &UserInfo) -> Result<(), ServiceError> {
70    if user_info.is_member() || user_info.is_admin() || user_info.is_testing() {
71        Ok(())
72    } else {
73        Err(ServiceError::new(
74            StatusCode::FORBIDDEN,
75            "Only members are allowed to create",
76        ))
77    }
78}
79
80/// This mirrors the the initial behavior of Access Control.
81/// Only owners are allowed to modify maps.
82///
83/// # Errors
84/// If the user is not the owner of the map and requires writing access.
85#[cfg(not(feature = "access_control"))]
86pub async fn check_permissions(
87    map_id: i32,
88    pool: &SharedPool,
89    user_info: UserInfo,
90    required_rights: AccessRights,
91) -> Result<(), ServiceError> {
92    if user_info.is_admin() {
93        return Ok(());
94    }
95    let mut conn = pool.get().await?;
96    let map = Map::find_by_id(map_id, &mut conn).await?;
97    if required_rights > AccessRights::Read && map.created_by != user_info.id {
98        return Err(ServiceError {
99            status_code: StatusCode::FORBIDDEN,
100            reason: "no permission to update data".to_owned(),
101        });
102    }
103    Ok(())
104}