headless_lms_credit_registration/registry/
mod.rs1mod answers;
6mod batch;
7mod ids;
8mod requests;
9
10pub(crate) use answers::{
11 CourseCodeVerdicts, EnrolmentAnswer, EnrolmentReading, FoundPerson, HeldCredit, ImportAnswer,
12 PersonAnswer, PersonReading, RosterListing, RosterSearch, VerificationAnswer,
13 VerificationReading,
14};
15pub use answers::{PersonLookupError, RegistryPerson};
16pub(crate) use batch::{
17 AnsweredRow, BatchEntry, BatchOptions, BatchReply, BatchRequest, ExchangeAudit, RefusedFor,
18 RefusedRow,
19};
20pub(crate) use ids::{AttainmentId, CourseCode, StudentNumber, SubmittedAttainmentRef};
21pub(crate) use requests::{
22 AttainmentSubmission, Credits, EnrolmentLookup, PersonLookup, RosterCode, VerificationRequest,
23};
24
25use headless_lms_models::library::credit_registration::study_registry::RegistryErrorKind;
26pub(crate) use headless_lms_models::library::credit_registration::study_registry::RegistryOperation;
27
28pub(crate) trait StudyRegistry {
34 fn allowance(&self, operation: RegistryOperation) -> usize;
37
38 fn roster_request_size(&self) -> usize;
41
42 async fn resolve_persons<K>(
43 &mut self,
44 entries: Vec<BatchEntry<K, PersonLookup>>,
45 options: BatchOptions,
46 ) -> BatchReply<K, PersonLookup, PersonAnswer>;
47
48 async fn resolve_enrolments<K>(
49 &mut self,
50 entries: Vec<BatchEntry<K, EnrolmentLookup>>,
51 options: BatchOptions,
52 ) -> BatchReply<K, EnrolmentLookup, EnrolmentAnswer>;
53
54 async fn import_attainments<K>(
56 &mut self,
57 entries: Vec<BatchEntry<K, AttainmentSubmission>>,
58 options: BatchOptions,
59 ) -> BatchReply<K, AttainmentSubmission, ImportAnswer>;
60
61 async fn verify_attainments<K>(
62 &mut self,
63 entries: Vec<BatchEntry<K, VerificationRequest>>,
64 options: BatchOptions,
65 ) -> BatchReply<K, VerificationRequest, VerificationAnswer>;
66
67 async fn list_course_roster(
69 &mut self,
70 request: &[RosterCode],
71 ) -> Result<RosterListing, RegistryError>;
72
73 async fn validate_course_codes(
76 &mut self,
77 codes: &[CourseCode],
78 ) -> Result<CourseCodeVerdicts, RegistryError>;
79}
80
81pub(crate) trait InteractiveStudyRegistry {
85 async fn look_up_person(
87 &self,
88 student_number: &StudentNumber,
89 ) -> Result<Option<RegistryPerson>, PersonLookupError>;
90
91 async fn search_course_rosters(
93 &self,
94 codes: &[CourseCode],
95 student_number: &StudentNumber,
96 ) -> RosterSearch;
97}
98
99pub(crate) struct RegistryError {
102 pub kind: RegistryErrorKind,
103 pub message: String,
105}
106
107impl RegistryError {
108 pub(crate) fn new(kind: RegistryErrorKind, message: impl Into<String>) -> Self {
109 Self {
110 kind,
111 message: message.into(),
112 }
113 }
114
115 pub(crate) fn blames_request_items(&self) -> bool {
118 !matches!(
119 self.kind,
120 RegistryErrorKind::NotDelivered | RegistryErrorKind::AuthenticationFailure
121 )
122 }
123}