headless_lms_server/controllers/main_frontend/
roles.rs1use crate::prelude::*;
2use models::{
3 pending_roles::{self, PendingRole},
4 roles::{self, RoleDomain, RoleInfo, RoleUser},
5 users,
6};
7
8use crate::domain::authorization::skip_authorize;
9
10async fn authorize_role_management(
11 conn: &mut PgConnection,
12 domain: RoleDomain,
13 action: Act,
14 user_id: Uuid,
15) -> ControllerResult<()> {
16 let token = match domain {
17 RoleDomain::Global => {
18 authorize(conn, action, Some(user_id), Res::GlobalPermissions).await?
19 }
20 RoleDomain::Organization(id) => {
21 authorize(conn, action, Some(user_id), Res::Organization(id)).await?
22 }
23 RoleDomain::Course(id) => authorize(conn, action, Some(user_id), Res::Course(id)).await?,
24 RoleDomain::CourseInstance(id) => {
25 authorize(conn, action, Some(user_id), Res::CourseInstance(id)).await?
26 }
27 RoleDomain::Exam(id) => authorize(conn, Act::Edit, Some(user_id), Res::Exam(id)).await?,
28 };
29
30 token.authorized_ok(())
31}
32
33#[instrument(skip(pool))]
37pub async fn set(
38 pool: web::Data<PgPool>,
39 role_info: web::Json<RoleInfo>,
40 user: AuthUser,
41) -> ControllerResult<HttpResponse> {
42 let mut conn = pool.acquire().await?;
43 authorize_role_management(
44 &mut conn,
45 role_info.domain,
46 Act::EditRole(role_info.role),
47 user.id,
48 )
49 .await?;
50
51 let target_user = users::try_get_by_email(&mut conn, &role_info.email).await?;
52 if let Some(target_user) = target_user {
53 roles::insert(&mut conn, target_user.id, role_info.role, role_info.domain).await?;
54 let token = skip_authorize();
55 return token.authorized_ok(HttpResponse::Ok().finish());
56 }
57 Err(ControllerError::new(
58 ControllerErrorType::NotFound,
59 "The user either does not exist or has not logged in to this website previously."
60 .to_string(),
61 None,
62 ))
63}
64
65#[instrument(skip(pool))]
69pub async fn unset(
70 pool: web::Data<PgPool>,
71 role_info: web::Json<RoleInfo>,
72 user: AuthUser,
73) -> ControllerResult<HttpResponse> {
74 let mut conn = pool.acquire().await?;
75 authorize_role_management(
76 &mut conn,
77 role_info.domain,
78 Act::EditRole(role_info.role),
79 user.id,
80 )
81 .await?;
82 let target_user = users::get_by_email(&mut conn, &role_info.email).await?;
83 roles::remove(&mut conn, target_user.id, role_info.role, role_info.domain).await?;
84
85 let token = skip_authorize();
86 token.authorized_ok(HttpResponse::Ok().finish())
87}
88
89#[derive(Debug, Deserialize)]
90#[cfg_attr(feature = "ts_rs", derive(TS))]
91pub struct RoleQuery {
92 #[serde(skip_serializing_if = "Option::is_none")]
93 global: Option<bool>,
94 #[serde(skip_serializing_if = "Option::is_none")]
95 organization_id: Option<Uuid>,
96 #[serde(skip_serializing_if = "Option::is_none")]
97 course_id: Option<Uuid>,
98 #[serde(skip_serializing_if = "Option::is_none")]
99 course_instance_id: Option<Uuid>,
100 #[serde(skip_serializing_if = "Option::is_none")]
101 exam_id: Option<Uuid>,
102}
103
104impl TryFrom<RoleQuery> for RoleDomain {
105 type Error = ControllerError;
106
107 fn try_from(
108 RoleQuery {
109 global,
110 organization_id,
111 course_id,
112 course_instance_id,
113 exam_id,
114 }: RoleQuery,
115 ) -> Result<Self, Self::Error> {
116 let domain = if global.unwrap_or_default() {
117 RoleDomain::Global
118 } else if let Some(id) = organization_id {
119 RoleDomain::Organization(id)
120 } else if let Some(id) = course_id {
121 RoleDomain::Course(id)
122 } else if let Some(id) = course_instance_id {
123 RoleDomain::CourseInstance(id)
124 } else if let Some(id) = exam_id {
125 RoleDomain::Exam(id)
126 } else {
127 return Err(ControllerError::new(
128 ControllerErrorType::BadRequest,
129 "Invalid query".to_string(),
130 None,
131 ));
132 };
133 Ok(domain)
134 }
135}
136
137#[instrument(skip(pool))]
141
142pub async fn fetch(
143 pool: web::Data<PgPool>,
144 query: web::Query<RoleQuery>,
145 user: AuthUser,
146) -> ControllerResult<web::Json<Vec<RoleUser>>> {
147 let mut conn = pool.acquire().await?;
148 let domain = query.into_inner().try_into()?;
149 authorize_role_management(&mut conn, domain, Act::Edit, user.id).await?;
150
151 let roles = roles::get(&mut conn, domain).await?;
152
153 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::AnyCourse).await?;
154 token.authorized_ok(web::Json(roles))
155}
156
157#[instrument(skip(pool))]
161
162pub async fn fetch_pending(
163 pool: web::Data<PgPool>,
164 query: web::Query<RoleQuery>,
165 user: AuthUser,
166) -> ControllerResult<web::Json<Vec<PendingRole>>> {
167 let mut conn = pool.acquire().await?;
168 let domain = query.into_inner().try_into()?;
169 authorize_role_management(&mut conn, domain, Act::Edit, user.id).await?;
170
171 let roles = pending_roles::get_all(&mut conn, domain).await?;
172 let token = authorize(&mut conn, Act::Edit, Some(user.id), Res::AnyCourse).await?;
173 token.authorized_ok(web::Json(roles))
174}
175
176pub fn _add_routes(cfg: &mut ServiceConfig) {
184 cfg.route("/add", web::post().to(set))
185 .route("/remove", web::post().to(unset))
186 .route("", web::get().to(fetch))
187 .route("/pending", web::get().to(fetch_pending));
188}