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 *
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_ids(
51 conn: &mut PgConnection,
52 ids: &[Uuid],
53) -> ModelResult<Vec<StudyRegistryRegistrar>> {
54 let res = sqlx::query_as!(
55 StudyRegistryRegistrar,
56 "
57SELECT *
58FROM study_registry_registrars
59WHERE id = ANY($1)
60 AND deleted_at IS NULL
61 ",
62 ids,
63 )
64 .fetch_all(conn)
65 .await?;
66 Ok(res)
67}
68
69pub async fn get_by_secret_key(
70 conn: &mut PgConnection,
71 secret_key: &str,
72) -> ModelResult<StudyRegistryRegistrar> {
73 let res = sqlx::query_as!(
74 StudyRegistryRegistrar,
75 "
76SELECT *
77FROM study_registry_registrars
78WHERE secret_key = $1
79 AND deleted_at IS NULL
80 ",
81 secret_key
82 )
83 .fetch_one(conn)
84 .await?;
85 Ok(res)
86}
87
88pub async fn delete(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
89 sqlx::query!(
90 "
91UPDATE study_registry_registrars
92SET deleted_at = now()
93WHERE id = $1
94AND deleted_at IS NULL
95 ",
96 id,
97 )
98 .execute(conn)
99 .await?;
100 Ok(())
101}
102
103pub async fn get_or_create_default_registrar(conn: &mut PgConnection) -> ModelResult<Uuid> {
107 let existing = sqlx::query!(
108 r#"
109 SELECT id
110 FROM study_registry_registrars
111 WHERE name = 'Default Registrar'
112 AND deleted_at IS NULL
113 ORDER BY created_at
114 LIMIT 1
115 "#,
116 )
117 .fetch_optional(&mut *conn)
118 .await?;
119
120 if let Some(row) = existing {
121 return Ok(row.id);
122 }
123
124 let inserted = sqlx::query!(
125 r#"
126 INSERT INTO study_registry_registrars (
127 name,
128 secret_key
129 )
130 VALUES (
131 'Default Registrar',
132 encode(gen_random_bytes(32), 'hex')
133 )
134 RETURNING id
135 "#,
136 )
137 .fetch_one(&mut *conn)
138 .await?;
139
140 Ok(inserted.id)
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use crate::test_helper::*;
147
148 #[tokio::test]
149 async fn secret_key_needs_to_be_long_enough() {
150 insert_data!(:tx);
151 let id_1 = Uuid::parse_str("88eff75b-4c8f-46f7-a857-9d804b5ec054").unwrap();
152 let res = insert(
153 tx.as_mut(),
154 PKeyPolicy::Fixed(id_1),
155 "test registrar",
156 "12345",
157 )
158 .await;
159 assert!(res.is_err(), "Expected too short key to produce error.");
160 }
161
162 #[tokio::test]
163 async fn secret_key_needs_to_be_unique() {
164 insert_data!(:tx);
165 let id_1 = Uuid::parse_str("88eff75b-4c8f-46f7-a857-9d804b5ec054").unwrap();
166 let res = insert(
167 tx.as_mut(),
168 PKeyPolicy::Fixed(id_1),
169 "test registrar",
170 "123456789-123456",
171 )
172 .await;
173 assert!(res.is_ok(), "Expected insertion to succeed.");
174
175 let id_2 = Uuid::parse_str("d06abb84-0cad-4372-ad2a-7f87d3c1e420").unwrap();
176 let res = insert(
177 tx.as_mut(),
178 PKeyPolicy::Fixed(id_2),
179 "test registrar 2",
180 "123456789-123456",
181 )
182 .await;
183 assert!(
184 res.is_err(),
185 "Expected insertion to fail with duplicate secret key."
186 );
187 }
188}