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_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> {
90 let existing = sqlx::query!(
91 r#"
92 SELECT id
93 FROM study_registry_registrars
94 WHERE name = 'Default Registrar'
95 AND deleted_at IS NULL
96 ORDER BY created_at
97 LIMIT 1
98 "#,
99 )
100 .fetch_optional(&mut *conn)
101 .await?;
102
103 if let Some(row) = existing {
104 return Ok(row.id);
105 }
106
107 let inserted = sqlx::query!(
108 r#"
109 INSERT INTO study_registry_registrars (
110 name,
111 secret_key
112 )
113 VALUES (
114 'Default Registrar',
115 encode(gen_random_bytes(32), 'hex')
116 )
117 RETURNING id
118 "#,
119 )
120 .fetch_one(&mut *conn)
121 .await?;
122
123 Ok(inserted.id)
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use crate::test_helper::*;
130
131 #[tokio::test]
132 async fn secret_key_needs_to_be_long_enough() {
133 insert_data!(:tx);
134 let id_1 = Uuid::parse_str("88eff75b-4c8f-46f7-a857-9d804b5ec054").unwrap();
135 let res = insert(
136 tx.as_mut(),
137 PKeyPolicy::Fixed(id_1),
138 "test registrar",
139 "12345",
140 )
141 .await;
142 assert!(res.is_err(), "Expected too short key to produce error.");
143 }
144
145 #[tokio::test]
146 async fn secret_key_needs_to_be_unique() {
147 insert_data!(:tx);
148 let id_1 = Uuid::parse_str("88eff75b-4c8f-46f7-a857-9d804b5ec054").unwrap();
149 let res = insert(
150 tx.as_mut(),
151 PKeyPolicy::Fixed(id_1),
152 "test registrar",
153 "123456789-123456",
154 )
155 .await;
156 assert!(res.is_ok(), "Expected insertion to succeed.");
157
158 let id_2 = Uuid::parse_str("d06abb84-0cad-4372-ad2a-7f87d3c1e420").unwrap();
159 let res = insert(
160 tx.as_mut(),
161 PKeyPolicy::Fixed(id_2),
162 "test registrar 2",
163 "123456789-123456",
164 )
165 .await;
166 assert!(
167 res.is_err(),
168 "Expected insertion to fail with duplicate secret key."
169 );
170 }
171}