headless_lms_models/
study_registry_registrars.rs1use crate::prelude::*;
2
3#[derive(Clone, PartialEq, Deserialize, Serialize)]
4pub struct StudyRegistryRegistrar {
5 pub id: Uuid,
6 pub created_at: DateTime<Utc>,
7 pub updated_at: DateTime<Utc>,
8 pub deleted_at: Option<DateTime<Utc>>,
9 pub name: String,
10 pub secret_key: String,
11}
12
13pub async fn insert(
14 conn: &mut PgConnection,
15 pkey_policy: PKeyPolicy<Uuid>,
16 name: &str,
17 secret_key: &str,
18) -> ModelResult<Uuid> {
19 let res = sqlx::query!(
20 "
21INSERT INTO study_registry_registrars (id, name, secret_key)
22VALUES ($1, $2, $3)
23RETURNING id
24 ",
25 pkey_policy.into_uuid(),
26 name,
27 secret_key
28 )
29 .fetch_one(conn)
30 .await?;
31 Ok(res.id)
32}
33
34pub async fn get_by_id(conn: &mut PgConnection, id: Uuid) -> ModelResult<StudyRegistryRegistrar> {
35 let res = sqlx::query_as!(
36 StudyRegistryRegistrar,
37 "
38SELECT *
39FROM study_registry_registrars
40WHERE id = $1
41 AND deleted_at IS NULL
42 ",
43 id,
44 )
45 .fetch_one(conn)
46 .await?;
47 Ok(res)
48}
49
50pub async fn get_by_secret_key(
51 conn: &mut PgConnection,
52 secret_key: &str,
53) -> ModelResult<StudyRegistryRegistrar> {
54 let res = sqlx::query_as!(
55 StudyRegistryRegistrar,
56 "
57SELECT *
58FROM study_registry_registrars
59WHERE secret_key = $1
60 AND deleted_at IS NULL
61 ",
62 secret_key
63 )
64 .fetch_one(conn)
65 .await?;
66 Ok(res)
67}
68
69pub async fn delete(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
70 sqlx::query!(
71 "
72UPDATE study_registry_registrars
73SET deleted_at = now()
74WHERE id = $1
75AND deleted_at IS NULL
76 ",
77 id,
78 )
79 .execute(conn)
80 .await?;
81 Ok(())
82}
83
84pub async fn get_or_create_default_registrar(conn: &mut PgConnection) -> ModelResult<Uuid> {
85 let existing = sqlx::query!(
87 r#"
88 SELECT id
89 FROM study_registry_registrars
90 WHERE deleted_at IS NULL
91 ORDER BY created_at
92 LIMIT 1
93 "#,
94 )
95 .fetch_optional(&mut *conn)
96 .await?;
97
98 if let Some(row) = existing {
99 return Ok(row.id);
100 }
101
102 let inserted = sqlx::query!(
104 r#"
105 INSERT INTO study_registry_registrars (
106 name,
107 secret_key
108 )
109 VALUES (
110 'Default Registrar',
111 encode(gen_random_bytes(32), 'hex')
112 )
113 RETURNING id
114 "#,
115 )
116 .fetch_one(&mut *conn)
117 .await?;
118
119 Ok(inserted.id)
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use crate::test_helper::*;
126
127 #[tokio::test]
128 async fn secret_key_needs_to_be_long_enough() {
129 insert_data!(:tx);
130 let id_1 = Uuid::parse_str("88eff75b-4c8f-46f7-a857-9d804b5ec054").unwrap();
131 let res = insert(
132 tx.as_mut(),
133 PKeyPolicy::Fixed(id_1),
134 "test registrar",
135 "12345",
136 )
137 .await;
138 assert!(res.is_err(), "Expected too short key to produce error.");
139 }
140
141 #[tokio::test]
142 async fn secret_key_needs_to_be_unique() {
143 insert_data!(:tx);
144 let id_1 = Uuid::parse_str("88eff75b-4c8f-46f7-a857-9d804b5ec054").unwrap();
145 let res = insert(
146 tx.as_mut(),
147 PKeyPolicy::Fixed(id_1),
148 "test registrar",
149 "123456789-123456",
150 )
151 .await;
152 assert!(res.is_ok(), "Expected insertion to succeed.");
153
154 let id_2 = Uuid::parse_str("d06abb84-0cad-4372-ad2a-7f87d3c1e420").unwrap();
155 let res = insert(
156 tx.as_mut(),
157 PKeyPolicy::Fixed(id_2),
158 "test registrar 2",
159 "123456789-123456",
160 )
161 .await;
162 assert!(
163 res.is_err(),
164 "Expected insertion to fail with duplicate secret key."
165 );
166 }
167}