headless_lms_models/
pending_roles.rs1use crate::{
2 prelude::*,
3 roles::{RoleDomain, RoleInfo, UserRole},
4};
5use utoipa::ToSchema;
6
7#[derive(Debug, Serialize, ToSchema)]
8
9pub struct PendingRole {
10 pub id: Uuid,
11 pub created_at: DateTime<Utc>,
12 pub updated_at: DateTime<Utc>,
13 pub deleted_at: Option<DateTime<Utc>>,
14 pub user_email: String,
15 pub role: UserRole,
16 pub course_id: Option<Uuid>,
17 pub course_instance_id: Option<Uuid>,
18 pub expires_at: DateTime<Utc>,
19}
20
21pub async fn insert(
22 conn: &mut PgConnection,
23 pkey_policy: PKeyPolicy<Uuid>,
24 role_info: RoleInfo,
25) -> ModelResult<Uuid> {
26 match role_info.domain {
27 crate::roles::RoleDomain::Global
28 | crate::roles::RoleDomain::Organization(_)
29 | crate::roles::RoleDomain::Exam(_) => {
30 return Err(ModelError::new(
31 ModelErrorType::InvalidRequest,
32 "Cannot use a pending role for a role this broad".to_string(),
33 None,
34 ));
35 }
36
37 crate::roles::RoleDomain::Course(_) | crate::roles::RoleDomain::CourseInstance(_) => (),
38 };
39
40 match role_info.role {
41 UserRole::Admin | UserRole::Teacher => {
42 return Err(ModelError::new(
43 ModelErrorType::InvalidRequest,
44 "Cannot use a pending role with this much power".to_string(),
45 None,
46 ));
47 }
48 _ => (),
49 }
50
51 let course_id = match role_info.domain {
52 crate::roles::RoleDomain::Course(id) => Some(id),
53 _ => None,
54 };
55
56 let course_instance_id = match role_info.domain {
57 crate::roles::RoleDomain::CourseInstance(id) => Some(id),
58 _ => None,
59 };
60
61 let id = sqlx::query!(
62 r#"
63INSERT INTO pending_roles (
64 id,
65 user_email,
66 role,
67 course_id,
68 course_instance_id
69 )
70VALUES ($1, $2, $3, $4, $5)
71RETURNING *;
72 "#,
73 pkey_policy.into_uuid(),
74 role_info.email,
75 role_info.role as UserRole,
76 course_id,
77 course_instance_id
78 )
79 .fetch_one(conn)
80 .await?
81 .id;
82 Ok(id)
83}
84
85pub async fn get_all(conn: &mut PgConnection, domain: RoleDomain) -> ModelResult<Vec<PendingRole>> {
86 let res = match domain {
87 RoleDomain::Global | RoleDomain::Organization(_) | RoleDomain::Exam(_) => {
88 return Ok(Vec::new());
89 }
90 RoleDomain::Course(course_id) => {
91 sqlx::query_as!(
92 PendingRole,
93 r#"
94SELECT * FROM pending_roles
95WHERE course_id = $1
96AND deleted_at IS NULL
97AND expires_at > NOW()
98 "#,
99 course_id
100 )
101 .fetch_all(&mut *conn)
102 .await?
103 }
104 RoleDomain::CourseInstance(course_instance_id) => {
105 sqlx::query_as!(
106 PendingRole,
107 r#"
108SELECT * FROM pending_roles
109WHERE course_instance_id = $1
110AND deleted_at IS NULL
111AND expires_at > NOW()
112 "#,
113 course_instance_id
114 )
115 .fetch_all(&mut *conn)
116 .await?
117 }
118 };
119 Ok(res)
120}