headless_lms_models/
lib.rs1#![allow(rustdoc::private_intra_doc_links)]
8pub mod agent_changeset_calls;
9pub mod agent_changeset_entities;
10pub mod agent_changesets;
11pub mod application_task_default_language_models;
12pub mod certificate_configuration_to_requirements;
13pub mod certificate_configurations;
14pub mod certificate_fonts;
15pub mod chapter_lock_action_logs;
16pub mod chapters;
17pub mod chatbot_action_logs;
18pub mod chatbot_configurations;
19pub mod chatbot_configurations_models;
20pub mod chatbot_conversation_message_messages;
21pub mod chatbot_conversation_message_reasoning;
22pub mod chatbot_conversation_message_tool_calls;
23pub mod chatbot_conversation_message_tool_outputs;
24pub mod chatbot_conversation_messages;
25pub mod chatbot_conversation_messages_citations;
26pub mod chatbot_conversation_suggested_messages;
27pub mod chatbot_conversations;
28pub mod chatbot_page_sync_statuses;
29pub mod cheating_confirmation_grade_snapshots;
30pub mod cms_ai;
31pub mod code_giveaway_codes;
32pub mod code_giveaways;
33pub mod completion_registration_credit_justifications;
34pub mod course_audiences;
35pub mod course_background_question_answers;
36pub mod course_background_questions;
37pub mod course_custom_privacy_policy_checkbox_texts;
38pub mod course_designer_analysis_workspace;
39pub mod course_designer_plan_members;
40pub mod course_designer_plans;
41pub mod course_exams;
42pub mod course_instance_enrollments;
43pub mod course_instances;
44pub mod course_language_groups;
45pub mod course_module_completion_registered_to_study_registries;
46pub mod course_module_completions;
47pub mod course_module_suotar_configurations;
48pub mod course_modules;
49pub mod course_page_markdown_content;
50pub mod course_prerequisites;
51pub mod courses;
52pub mod credit_registration_account_linking_emails;
53pub mod credit_registration_admin_actions;
54pub mod credit_registration_daily_snapshots;
55pub mod credit_registration_enrolment_check_outcomes;
56pub mod credit_registration_enrolment_check_signals;
57pub mod credit_registration_enrolment_routes;
58pub mod credit_registration_events;
59pub mod credit_registration_phase_state;
60pub mod credit_registration_roster_schedules;
61pub mod credit_registrations;
62pub mod email_deliveries;
63pub mod email_layouts;
64pub mod email_templates;
65pub mod email_verification_tokens;
66pub mod ended_processed_exams;
67pub mod entity_history;
68pub mod error;
69pub mod errors;
70pub mod exams;
71pub mod exercise_answer_uploads;
72pub mod exercise_language_groups;
73pub mod exercise_repositories;
74pub mod exercise_reset_logs;
75pub mod exercise_service_info;
76pub mod exercise_services;
77pub mod exercise_slide_submission_shares;
78pub mod exercise_slide_submissions;
79pub mod exercise_slides;
80pub mod exercise_spec_uploads;
81pub mod exercise_task_gradings;
82pub mod exercise_task_regrading_submissions;
83pub mod exercise_task_spec_files;
84pub mod exercise_task_submission_files;
85pub mod exercise_task_submissions;
86pub mod exercise_tasks;
87pub mod exercises;
88pub mod external_courses;
89pub mod feedback;
90pub mod feedback_categories;
91pub mod file_uploads;
92pub mod flagged_answers;
93pub mod generated_certificates;
94pub mod glossary;
95pub mod join_code_uses;
96pub mod library;
97pub mod marketing_consents;
98pub mod material_references;
99pub mod oauth_access_token;
100pub mod oauth_auth_code;
101pub mod oauth_client;
102pub mod oauth_device_codes;
103pub mod oauth_dpop_proofs;
104pub mod oauth_refresh_tokens;
105pub mod oauth_user_client_scopes;
106pub mod offered_answers_to_peer_review_temporary;
107pub mod open_university_registration_links;
108pub mod organizations;
109pub mod other_domain_to_course_redirections;
110pub mod page_audio_files;
111pub mod page_history;
112pub mod page_history_spec_files;
113pub mod page_language_groups;
114pub mod page_visit_datum;
115pub mod page_visit_datum_daily_visit_hashing_keys;
116pub mod page_visit_datum_summary_by_courses;
117pub mod page_visit_datum_summary_by_courses_countries;
118pub mod page_visit_datum_summary_by_courses_device_types;
119pub mod page_visit_datum_summary_by_pages;
120pub mod pages;
121pub mod partner_block;
122pub mod peer_or_self_review_configs;
123pub mod peer_or_self_review_question_submissions;
124pub mod peer_or_self_review_questions;
125pub mod peer_or_self_review_submissions;
126pub mod peer_review_queue_entries;
127pub mod pending_roles;
128pub mod playground_examples;
129pub mod points_breakdowns;
130pub mod privacy_link;
131pub mod proposed_block_edits;
132pub mod proposed_page_edits;
133pub mod re_exports;
134pub mod regradings;
135pub mod rejected_exercise_slide_submissions;
136pub mod repository_exercises;
137pub mod research_forms;
138pub mod roles;
139pub mod secret;
140pub mod student_countries;
141pub mod student_number_verification_tokens;
142pub mod study_registry_registrars;
143pub mod study_registry_student_number_conflicts;
144pub mod suotar_api_calls;
145pub mod suotar_circuit_breakers;
146pub mod suotar_endpoint_rate_limits;
147pub mod suspected_cheaters;
148pub mod teacher_grading_decisions;
149pub mod url_redirections;
150pub mod user_ai_usage_notice_acknowledgements;
151pub mod user_chapter_locking_statuses;
152pub mod user_course_exercise_service_variables;
153pub mod user_course_settings;
154pub mod user_details;
155pub mod user_email_codes;
156pub mod user_exercise_slide_states;
157pub mod user_exercise_states;
158pub mod user_exercise_task_states;
159pub mod user_passwords;
160pub mod user_research_consents;
161pub mod users;
162pub mod verified_student_numbers;
163
164pub mod prelude;
165#[cfg(any(test, feature = "test-helpers"))]
166pub mod test_helper;
167
168use exercises::Exercise;
169use futures::future::BoxFuture;
170use url::Url;
171use user_exercise_states::UserExerciseState;
172use uuid::Uuid;
173
174pub use self::error::{HttpErrorType, ModelError, ModelErrorType, ModelResult};
175use crate::prelude::*;
176
177#[macro_use]
178extern crate tracing;
179
180pub enum PKeyPolicy<T> {
273 Fixed(T),
276 Generate,
279}
280
281impl<T> PKeyPolicy<T> {
282 pub fn fixed(&self) -> Option<&T> {
284 match self {
285 PKeyPolicy::Fixed(t) => Some(t),
286 PKeyPolicy::Generate => None,
287 }
288 }
289
290 pub fn map<U, F>(self, f: F) -> PKeyPolicy<U>
292 where
293 F: FnOnce(T) -> U,
294 {
295 match self {
296 PKeyPolicy::Fixed(x) => PKeyPolicy::Fixed(f(x)),
297 PKeyPolicy::Generate => PKeyPolicy::Generate,
298 }
299 }
300
301 pub fn map_ref<U, F>(&self, f: F) -> PKeyPolicy<U>
305 where
306 F: FnOnce(&T) -> U,
307 {
308 match self {
309 PKeyPolicy::Fixed(x) => PKeyPolicy::Fixed(f(x)),
310 PKeyPolicy::Generate => PKeyPolicy::Generate,
311 }
312 }
313}
314
315impl PKeyPolicy<Uuid> {
316 pub fn into_uuid(self) -> Uuid {
318 match self {
319 PKeyPolicy::Fixed(uuid) => uuid,
320 PKeyPolicy::Generate => Uuid::new_v4(),
321 }
322 }
323}
324
325pub trait SpecFetcher:
331 for<'a> Fn(
332 Url,
333 &'a str,
334 Option<&'a serde_json::Value>,
335) -> BoxFuture<'a, ModelResult<serde_json::Value>>
336{
337}
338
339impl<
340 T: for<'a> Fn(
341 Url,
342 &'a str,
343 Option<&'a serde_json::Value>,
344 ) -> BoxFuture<'a, ModelResult<serde_json::Value>>,
345> SpecFetcher for T
346{
347}
348
349#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, Hash)]
354pub enum CourseOrExamId {
355 Course(Uuid),
356 Exam(Uuid),
357}
358
359impl CourseOrExamId {
360 pub fn from_course_and_exam_ids(
361 course_id: Option<Uuid>,
362 exam_id: Option<Uuid>,
363 ) -> ModelResult<Self> {
364 match (course_id, exam_id) {
365 (None, None) => Err(ModelError::new(
366 ModelErrorType::Generic,
367 "Expected either course or exam id, but neither were provided.",
368 None,
369 )),
370 (Some(course_id), None) => Ok(Self::Course(course_id)),
371 (None, Some(exam_id)) => Ok(Self::Exam(exam_id)),
372 (Some(_), Some(_)) => Err(ModelError::new(
373 ModelErrorType::Generic,
374 "Expected either course or exam id, but both were provided.",
375 None,
376 )),
377 }
378 }
379
380 pub fn to_course_and_exam_ids(&self) -> (Option<Uuid>, Option<Uuid>) {
381 match self {
382 CourseOrExamId::Course(course_id) => (Some(*course_id), None),
383 CourseOrExamId::Exam(exam_id) => (None, Some(*exam_id)),
384 }
385 }
386}
387
388impl TryFrom<UserExerciseState> for CourseOrExamId {
389 type Error = ModelError;
390
391 fn try_from(user_exercise_state: UserExerciseState) -> Result<Self, Self::Error> {
392 Self::from_course_and_exam_ids(user_exercise_state.course_id, user_exercise_state.exam_id)
393 }
394}
395
396impl TryFrom<&UserExerciseState> for CourseOrExamId {
397 type Error = ModelError;
398
399 fn try_from(user_exercise_state: &UserExerciseState) -> Result<Self, Self::Error> {
400 Self::from_course_and_exam_ids(user_exercise_state.course_id, user_exercise_state.exam_id)
401 }
402}
403
404impl TryFrom<Exercise> for CourseOrExamId {
405 type Error = ModelError;
406
407 fn try_from(exercise: Exercise) -> Result<Self, Self::Error> {
408 Self::from_course_and_exam_ids(exercise.course_id, exercise.exam_id)
409 }
410}
411
412impl TryFrom<&Exercise> for CourseOrExamId {
413 type Error = ModelError;
414
415 fn try_from(exercise: &Exercise) -> Result<Self, Self::Error> {
416 Self::from_course_and_exam_ids(exercise.course_id, exercise.exam_id)
417 }
418}