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