headless_lms_models/
study_registry_registrars.rs

1use 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    // Try to find an existing registrar
86    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    // Insert a new registrar
103    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}