Skip to main content

ahri_tre_app/projections/
governance.rs

1use super::*;
2use ahri_tre_protocol::{PublicUuid, refs::ObjectKind, session::SessionStatusPayload, study::*};
3use ahri_tre_types::StudyRecord;
4
5fn governance_scope(
6    session: &SessionStatusPayload,
7    study: &StudyRecord,
8) -> (PublicUuid, StudyRef, String) {
9    let ds = session
10        .datastore_id
11        .expect("governance Session retains its Datastore binding");
12    (
13        ds,
14        object_ref(ds, ObjectKind::Study, study.study_id.0),
15        study.name.as_str().to_owned(),
16    )
17}
18
19pub fn study_add_domain_response(
20    session: SessionStatusPayload,
21    registration: crate::StudyRegistration,
22) -> StudyAddDomainResponse {
23    let ds = session
24        .datastore_id
25        .expect("governance Session retains its Datastore binding");
26    StudyAddDomainResponse {
27        session,
28        registration: study_registration_payload(ds, registration),
29    }
30}
31
32pub fn study_access_grant_response(
33    session: SessionStatusPayload,
34    (study, result): (StudyRecord, crate::StudyAccessGrant),
35) -> StudyAccessGrantResponse {
36    let (ds, study, study_name) = governance_scope(&session, &study);
37    StudyAccessGrantResponse {
38        grant: study_access_grant_summary(ds, study_name.clone(), result.grant),
39        session,
40        study,
41        study_name,
42    }
43}
44
45pub fn study_access_list_response(
46    session: SessionStatusPayload,
47    (study, result): (StudyRecord, crate::StudyAccessGrantList),
48) -> StudyAccessListResponse {
49    let (ds, study, study_name) = governance_scope(&session, &study);
50    StudyAccessListResponse {
51        grants: result
52            .grants
53            .into_iter()
54            .map(|grant| study_access_grant_summary(ds, study_name.clone(), grant))
55            .collect(),
56        session,
57        study,
58        study_name,
59    }
60}
61
62pub fn study_access_revoke_response(
63    session: SessionStatusPayload,
64    (study, result): (StudyRecord, crate::StudyAccessRevocation),
65) -> StudyAccessRevokeResponse {
66    let (_ds, study, study_name) = governance_scope(&session, &study);
67    StudyAccessRevokeResponse {
68        target_user: result.target_user_id,
69        revoked: true,
70        session,
71        study,
72        study_name,
73    }
74}
75
76pub fn study_custodians_list_response(
77    session: SessionStatusPayload,
78    (study, result): (StudyRecord, crate::StudyCustodianList),
79) -> StudyCustodiansListResponse {
80    let (ds, study, study_name) = governance_scope(&session, &study);
81    StudyCustodiansListResponse {
82        custodians: result
83            .custodians
84            .into_iter()
85            .map(|custodian| study_custodian_summary(ds, study_name.clone(), custodian))
86            .collect(),
87        session,
88        study,
89        study_name,
90    }
91}
92
93pub fn study_custodians_add_delegate_response(
94    session: SessionStatusPayload,
95    (study, result): (StudyRecord, crate::StudyCustodian),
96) -> StudyCustodianMutationResponse {
97    let (ds, study, study_name) = governance_scope(&session, &study);
98    StudyCustodianMutationResponse {
99        target_user: result.custodian.user_id.clone(),
100        custodian: Some(study_custodian_summary(
101            ds,
102            study_name.clone(),
103            result.custodian,
104        )),
105        removed: false,
106        session,
107        study,
108        study_name,
109    }
110}
111
112pub fn study_custodians_transfer_primary_response(
113    session: SessionStatusPayload,
114    (study, result): (StudyRecord, crate::StudyPrimaryCustodianshipTransfer),
115) -> StudyCustodianMutationResponse {
116    let (ds, study, study_name) = governance_scope(&session, &study);
117    StudyCustodianMutationResponse {
118        target_user: result.primary_custodian.user_id.clone(),
119        custodian: Some(study_custodian_summary(
120            ds,
121            study_name.clone(),
122            result.primary_custodian,
123        )),
124        removed: false,
125        session,
126        study,
127        study_name,
128    }
129}
130
131pub fn study_custodians_remove_delegate_response(
132    session: SessionStatusPayload,
133    (study, result): (StudyRecord, crate::StudyDelegateCustodianRemoval),
134) -> StudyCustodianMutationResponse {
135    let (_ds, study, study_name) = governance_scope(&session, &study);
136    StudyCustodianMutationResponse {
137        target_user: result.target_user_id,
138        custodian: None,
139        removed: true,
140        session,
141        study,
142        study_name,
143    }
144}
145
146pub fn study_duo_list_response(
147    session: SessionStatusPayload,
148    (study, result): (StudyRecord, crate::StudyDuoRestrictionList),
149) -> StudyDuoListResponse {
150    let (ds, study, study_name) = governance_scope(&session, &study);
151    StudyDuoListResponse {
152        restrictions: result
153            .restrictions
154            .into_iter()
155            .map(|restriction| study_duo_restriction_summary(ds, study_name.clone(), restriction))
156            .collect(),
157        session,
158        study,
159        study_name,
160    }
161}
162
163pub fn study_duo_replace_response(
164    session: SessionStatusPayload,
165    (study, result): (StudyRecord, crate::StudyDuoRestrictionReplacement),
166) -> StudyDuoReplaceResponse {
167    let (ds, study, study_name) = governance_scope(&session, &study);
168    StudyDuoReplaceResponse {
169        restrictions: result
170            .restrictions
171            .into_iter()
172            .map(|restriction| study_duo_restriction_summary(ds, study_name.clone(), restriction))
173            .collect(),
174        session,
175        study,
176        study_name,
177    }
178}
179
180fn study_access_grant_summary(
181    datastore_id: PublicUuid,
182    study_name: String,
183    grant: ahri_tre_types::StudyAccessGrantRecord,
184) -> StudyAccessGrantSummary {
185    StudyAccessGrantSummary {
186        study: object_ref(datastore_id, ObjectKind::Study, grant.study_id.0),
187        study_name,
188        user: grant.user_id,
189        granted_by: grant.granted_by,
190    }
191}
192
193fn study_custodian_summary(
194    datastore_id: PublicUuid,
195    study_name: String,
196    custodian: ahri_tre_types::StudyCustodianLinkRecord,
197) -> StudyCustodianSummary {
198    StudyCustodianSummary {
199        study: object_ref(datastore_id, ObjectKind::Study, custodian.study_id.0),
200        study_name,
201        user: custodian.user_id,
202        primary: custodian.is_primary,
203        granted_by: custodian.granted_by,
204    }
205}
206
207fn study_duo_restriction_summary(
208    datastore_id: PublicUuid,
209    study_name: String,
210    restriction: ahri_tre_types::StudyDuoRestrictionRecord,
211) -> StudyDuoRestrictionSummary {
212    StudyDuoRestrictionSummary {
213        study: object_ref(datastore_id, ObjectKind::Study, restriction.study_id.0),
214        study_name,
215        duo_id: restriction.duo_id,
216        qualifier_ontology_namespace: restriction.qualifier_ontology_namespace,
217        qualifier_ontology_id: restriction.qualifier_ontology_id,
218        qualifier_text: restriction.qualifier_text,
219        qualifier_date: restriction.qualifier_date,
220        qualifier_integer: restriction.qualifier_integer,
221    }
222}
223
224pub fn asset_duo_restriction_summary(
225    study: StudyRef,
226    version: ahri_tre_protocol::refs::VersionRef,
227    restriction: crate::EffectiveAssetVersionDuoRestriction,
228) -> ahri_tre_protocol::asset::AssetDuoRestrictionSummary {
229    use ahri_tre_protocol::asset::AssetDuoRestrictionSource;
230    let (source, governing) = match restriction.source {
231        crate::AssetDuoRestrictionSource::AssetVersion => {
232            (AssetDuoRestrictionSource::AssetVersion, version)
233        }
234        crate::AssetDuoRestrictionSource::StudyDefault => {
235            (AssetDuoRestrictionSource::StudyDefault, study)
236        }
237    };
238    ahri_tre_protocol::asset::AssetDuoRestrictionSummary {
239        source,
240        governing,
241        duo_id: restriction.duo_id,
242        qualifier_ontology_namespace: restriction.qualifier_ontology_namespace,
243        qualifier_ontology_id: restriction.qualifier_ontology_id,
244        qualifier_text: restriction.qualifier_text,
245        qualifier_date: restriction.qualifier_date,
246        qualifier_integer: restriction.qualifier_integer,
247    }
248}
249
250pub fn asset_duo_list_response(
251    session: SessionStatusPayload,
252    result: crate::service::GovernedAssetDuo,
253) -> ahri_tre_protocol::asset::AssetDuoListResponse {
254    let ds = session
255        .datastore_id
256        .expect("governance Session retains its Datastore binding");
257    let asset = safe_asset_catalog(ds, result.catalog).asset;
258    let version = safe_asset_version_summary(ds, result.version);
259    let restrictions = result
260        .restrictions
261        .into_iter()
262        .map(|restriction| {
263            asset_duo_restriction_summary(asset.study_id, version.version_id, restriction)
264        })
265        .collect();
266    ahri_tre_protocol::asset::AssetDuoListResponse {
267        session,
268        study: result.study.name.as_str().into(),
269        asset,
270        version,
271        restrictions,
272        effective: result.effective,
273    }
274}
275pub fn asset_duo_replace_response(
276    session: SessionStatusPayload,
277    result: crate::service::GovernedAssetDuo,
278) -> ahri_tre_protocol::asset::AssetDuoReplaceResponse {
279    let ds = session
280        .datastore_id
281        .expect("governance Session retains its Datastore binding");
282    let asset = safe_asset_catalog(ds, result.catalog).asset;
283    let version = safe_asset_version_summary(ds, result.version);
284    let restrictions = result
285        .restrictions
286        .into_iter()
287        .map(|restriction| {
288            asset_duo_restriction_summary(asset.study_id, version.version_id, restriction)
289        })
290        .collect();
291    ahri_tre_protocol::asset::AssetDuoReplaceResponse {
292        session,
293        study: result.study.name.as_str().into(),
294        asset,
295        version,
296        restrictions,
297    }
298}
299pub fn asset_duo_clear_response(
300    session: SessionStatusPayload,
301    result: crate::service::GovernedAssetDuo,
302) -> ahri_tre_protocol::asset::AssetDuoClearResponse {
303    let ds = session
304        .datastore_id
305        .expect("governance Session retains its Datastore binding");
306    let asset = safe_asset_catalog(ds, result.catalog).asset;
307    let version = safe_asset_version_summary(ds, result.version);
308    let restrictions = result
309        .restrictions
310        .into_iter()
311        .map(|restriction| {
312            asset_duo_restriction_summary(asset.study_id, version.version_id, restriction)
313        })
314        .collect();
315    ahri_tre_protocol::asset::AssetDuoClearResponse {
316        session,
317        study: result.study.name.as_str().into(),
318        asset,
319        version,
320        restrictions,
321    }
322}