Skip to main content

canvas_lms_api/resources/
course.rs

1use crate::{
2    error::Result,
3    http::Requester,
4    pagination::PageStream,
5    params::wrap_params,
6    resources::{
7        assignment::Assignment,
8        blueprint::{BlueprintSubscription, BlueprintTemplate},
9        content_migration::{ContentMigration, Migrator},
10        discussion_topic::DiscussionTopic,
11        enrollment::Enrollment,
12        external_tool::{ExternalTool, ExternalToolParams},
13        file::File,
14        gradebook_history::{Day, Grader, SubmissionHistory, SubmissionVersion},
15        group::Group,
16        module::Module,
17        outcome::{OutcomeGroup, OutcomeLink, UpdateOutcomeGroupParams},
18        page::Page,
19        params::{
20            assignment_params::CreateAssignmentParams, course_params::UpdateCourseParams,
21            quiz_params::CreateQuizParams,
22        },
23        quiz::Quiz,
24        rubric::{Rubric, RubricAssociation, RubricParams},
25        section::Section,
26        tab::Tab,
27        types::WorkflowState,
28        user::User,
29    },
30};
31use chrono::{DateTime, Utc};
32use serde::{Deserialize, Serialize};
33use std::sync::Arc;
34
35#[derive(Debug, Clone, Deserialize, Serialize)]
36pub struct Course {
37    pub id: u64,
38    pub name: Option<String>,
39    pub course_code: Option<String>,
40    pub workflow_state: Option<WorkflowState>,
41    pub account_id: Option<u64>,
42    pub root_account_id: Option<u64>,
43    pub enrollment_term_id: Option<u64>,
44    pub sis_course_id: Option<String>,
45    pub start_at: Option<DateTime<Utc>>,
46    pub end_at: Option<DateTime<Utc>>,
47    pub grading_standard_id: Option<u64>,
48    pub is_public: Option<bool>,
49    pub license: Option<String>,
50    pub locale: Option<String>,
51    pub time_zone: Option<String>,
52    pub total_students: Option<u64>,
53    pub default_view: Option<String>,
54    pub syllabus_body: Option<String>,
55    pub public_description: Option<String>,
56    pub hide_final_grades: Option<bool>,
57    pub apply_assignment_group_weights: Option<bool>,
58    pub restrict_enrollments_to_course_dates: Option<bool>,
59
60    #[serde(skip)]
61    pub(crate) requester: Option<Arc<Requester>>,
62}
63
64impl Course {
65    fn req(&self) -> &Arc<Requester> {
66        self.requester.as_ref().expect("requester not initialized")
67    }
68
69    /// Stream all assignments in this course.
70    ///
71    /// # Canvas API
72    /// `GET /api/v1/courses/:course_id/assignments`
73    pub fn get_assignments(&self) -> PageStream<Assignment> {
74        PageStream::new(
75            Arc::clone(self.req()),
76            &format!("courses/{}/assignments", self.id),
77            vec![],
78        )
79    }
80
81    /// Fetch a single assignment.
82    ///
83    /// # Canvas API
84    /// `GET /api/v1/courses/:course_id/assignments/:id`
85    pub async fn get_assignment(&self, assignment_id: u64) -> Result<Assignment> {
86        self.req()
87            .get(
88                &format!("courses/{}/assignments/{assignment_id}", self.id),
89                &[],
90            )
91            .await
92    }
93
94    /// Create a new assignment in this course.
95    ///
96    /// # Canvas API
97    /// `POST /api/v1/courses/:id/assignments`
98    pub async fn create_assignment(&self, params: CreateAssignmentParams) -> Result<Assignment> {
99        let form = wrap_params("assignment", &params);
100        self.req()
101            .post(&format!("courses/{}/assignments", self.id), &form)
102            .await
103    }
104
105    /// Stream all sections in this course.
106    ///
107    /// # Canvas API
108    /// `GET /api/v1/courses/:course_id/sections`
109    pub fn get_sections(&self) -> PageStream<Section> {
110        PageStream::new(
111            Arc::clone(self.req()),
112            &format!("courses/{}/sections", self.id),
113            vec![],
114        )
115    }
116
117    /// Fetch a single section by ID.
118    ///
119    /// # Canvas API
120    /// `GET /api/v1/courses/:id/sections/:section_id`
121    pub async fn get_section(&self, section_id: u64) -> Result<Section> {
122        self.req()
123            .get(&format!("courses/{}/sections/{section_id}", self.id), &[])
124            .await
125    }
126
127    /// Stream all enrollments in this course.
128    ///
129    /// # Canvas API
130    /// `GET /api/v1/courses/:course_id/enrollments`
131    pub fn get_enrollments(&self) -> PageStream<Enrollment> {
132        PageStream::new(
133            Arc::clone(self.req()),
134            &format!("courses/{}/enrollments", self.id),
135            vec![],
136        )
137    }
138
139    /// Stream all users in this course.
140    ///
141    /// # Canvas API
142    /// `GET /api/v1/courses/:course_id/users`
143    pub fn get_users(&self) -> PageStream<User> {
144        PageStream::new(
145            Arc::clone(self.req()),
146            &format!("courses/{}/users", self.id),
147            vec![],
148        )
149    }
150
151    /// Update this course.
152    ///
153    /// # Canvas API
154    /// `PUT /api/v1/courses/:id`
155    pub async fn update(&self, params: UpdateCourseParams) -> Result<Course> {
156        let form = wrap_params("course", &params);
157        let mut course: Course = self
158            .req()
159            .put(&format!("courses/{}", self.id), &form)
160            .await?;
161        course.requester = self.requester.clone();
162        Ok(course)
163    }
164
165    /// Delete this course. Canvas returns the deleted course object.
166    ///
167    /// # Canvas API
168    /// `DELETE /api/v1/courses/:id`
169    pub async fn delete(&self) -> Result<Course> {
170        let params = vec![("event".to_string(), "delete".to_string())];
171        let mut course: Course = self
172            .req()
173            .delete(&format!("courses/{}", self.id), &params)
174            .await?;
175        course.requester = self.requester.clone();
176        Ok(course)
177    }
178
179    /// Stream all quizzes in this course.
180    ///
181    /// # Canvas API
182    /// `GET /api/v1/courses/:id/quizzes`
183    pub fn get_quizzes(&self) -> PageStream<Quiz> {
184        PageStream::new(
185            Arc::clone(self.req()),
186            &format!("courses/{}/quizzes", self.id),
187            vec![],
188        )
189    }
190
191    /// Fetch a single quiz.
192    ///
193    /// # Canvas API
194    /// `GET /api/v1/courses/:id/quizzes/:quiz_id`
195    pub async fn get_quiz(&self, quiz_id: u64) -> Result<Quiz> {
196        self.req()
197            .get(&format!("courses/{}/quizzes/{quiz_id}", self.id), &[])
198            .await
199    }
200
201    /// Create a new quiz in this course.
202    ///
203    /// # Canvas API
204    /// `POST /api/v1/courses/:id/quizzes`
205    pub async fn create_quiz(&self, params: CreateQuizParams) -> Result<Quiz> {
206        let form = wrap_params("quiz", &params);
207        self.req()
208            .post(&format!("courses/{}/quizzes", self.id), &form)
209            .await
210    }
211
212    /// Stream all modules in this course.
213    ///
214    /// # Canvas API
215    /// `GET /api/v1/courses/:id/modules`
216    pub fn get_modules(&self) -> PageStream<Module> {
217        PageStream::new(
218            Arc::clone(self.req()),
219            &format!("courses/{}/modules", self.id),
220            vec![],
221        )
222    }
223
224    /// Fetch a single module.
225    ///
226    /// # Canvas API
227    /// `GET /api/v1/courses/:id/modules/:module_id`
228    pub async fn get_module(&self, module_id: u64) -> Result<Module> {
229        self.req()
230            .get(&format!("courses/{}/modules/{module_id}", self.id), &[])
231            .await
232    }
233
234    /// Stream all pages in this course.
235    ///
236    /// # Canvas API
237    /// `GET /api/v1/courses/:id/pages`
238    pub fn get_pages(&self) -> PageStream<Page> {
239        PageStream::new(
240            Arc::clone(self.req()),
241            &format!("courses/{}/pages", self.id),
242            vec![],
243        )
244    }
245
246    /// Fetch a single page by URL slug or ID.
247    ///
248    /// # Canvas API
249    /// `GET /api/v1/courses/:id/pages/:url_or_id`
250    pub async fn get_page(&self, url_or_id: &str) -> Result<Page> {
251        self.req()
252            .get(&format!("courses/{}/pages/{url_or_id}", self.id), &[])
253            .await
254    }
255
256    /// Stream all discussion topics in this course.
257    ///
258    /// # Canvas API
259    /// `GET /api/v1/courses/:id/discussion_topics`
260    pub fn get_discussion_topics(&self) -> PageStream<DiscussionTopic> {
261        PageStream::new(
262            Arc::clone(self.req()),
263            &format!("courses/{}/discussion_topics", self.id),
264            vec![],
265        )
266    }
267
268    /// Fetch a single discussion topic.
269    ///
270    /// # Canvas API
271    /// `GET /api/v1/courses/:id/discussion_topics/:topic_id`
272    pub async fn get_discussion_topic(&self, topic_id: u64) -> Result<DiscussionTopic> {
273        self.req()
274            .get(
275                &format!("courses/{}/discussion_topics/{topic_id}", self.id),
276                &[],
277            )
278            .await
279    }
280
281    /// Stream all files in this course.
282    ///
283    /// # Canvas API
284    /// `GET /api/v1/courses/:id/files`
285    pub fn get_files(&self) -> PageStream<File> {
286        PageStream::new(
287            Arc::clone(self.req()),
288            &format!("courses/{}/files", self.id),
289            vec![],
290        )
291    }
292
293    /// Stream all tabs in this course.
294    ///
295    /// # Canvas API
296    /// `GET /api/v1/courses/:id/tabs`
297    pub fn get_tabs(&self) -> PageStream<Tab> {
298        PageStream::new(
299            Arc::clone(self.req()),
300            &format!("courses/{}/tabs", self.id),
301            vec![],
302        )
303    }
304
305    /// Stream all groups in this course.
306    ///
307    /// # Canvas API
308    /// `GET /api/v1/courses/:id/groups`
309    pub fn get_groups(&self) -> PageStream<Group> {
310        PageStream::new(
311            Arc::clone(self.req()),
312            &format!("courses/{}/groups", self.id),
313            vec![],
314        )
315    }
316
317    /// Upload a file to this course.
318    ///
319    /// Canvas uses a two-step upload: first POSTing metadata to obtain an upload URL,
320    /// then POSTing the file as multipart form data to that URL.
321    ///
322    /// # Canvas API
323    /// `POST /api/v1/courses/:id/files`
324    pub async fn upload_file(
325        &self,
326        request: crate::upload::UploadRequest,
327        data: Vec<u8>,
328    ) -> crate::error::Result<crate::resources::file::File> {
329        crate::upload::initiate_and_upload(
330            self.req(),
331            &format!("courses/{}/files", self.id),
332            request,
333            data,
334        )
335        .await
336    }
337
338    // -------------------------------------------------------------------------
339    // External Tools
340    // -------------------------------------------------------------------------
341
342    /// Fetch a single external tool by ID.
343    ///
344    /// # Canvas API
345    /// `GET /api/v1/courses/:course_id/external_tools/:id`
346    pub async fn get_external_tool(&self, tool_id: u64) -> Result<ExternalTool> {
347        let mut tool: ExternalTool = self
348            .req()
349            .get(
350                &format!("courses/{}/external_tools/{tool_id}", self.id),
351                &[],
352            )
353            .await?;
354        tool.requester = self.requester.clone();
355        Ok(tool)
356    }
357
358    /// Stream all external tools for this course.
359    ///
360    /// # Canvas API
361    /// `GET /api/v1/courses/:course_id/external_tools`
362    pub fn get_external_tools(&self) -> PageStream<ExternalTool> {
363        let course_id = self.id;
364        PageStream::new_with_injector(
365            Arc::clone(self.req()),
366            &format!("courses/{course_id}/external_tools"),
367            vec![],
368            |mut t: ExternalTool, req| {
369                t.requester = Some(Arc::clone(&req));
370                t
371            },
372        )
373    }
374
375    /// Create an external tool on this course.
376    ///
377    /// # Canvas API
378    /// `POST /api/v1/courses/:course_id/external_tools`
379    pub async fn create_external_tool(&self, params: ExternalToolParams) -> Result<ExternalTool> {
380        let form = wrap_params("external_tool", &params);
381        let mut tool: ExternalTool = self
382            .req()
383            .post(&format!("courses/{}/external_tools", self.id), &form)
384            .await?;
385        tool.requester = self.requester.clone();
386        Ok(tool)
387    }
388
389    // -------------------------------------------------------------------------
390    // Rubrics
391    // -------------------------------------------------------------------------
392
393    /// Fetch a single rubric by ID.
394    ///
395    /// # Canvas API
396    /// `GET /api/v1/courses/:course_id/rubrics/:id`
397    pub async fn get_rubric(&self, rubric_id: u64) -> Result<Rubric> {
398        let mut rubric: Rubric = self
399            .req()
400            .get(&format!("courses/{}/rubrics/{rubric_id}", self.id), &[])
401            .await?;
402        rubric.requester = self.requester.clone();
403        Ok(rubric)
404    }
405
406    /// Stream all rubrics for this course.
407    ///
408    /// # Canvas API
409    /// `GET /api/v1/courses/:course_id/rubrics`
410    pub fn get_rubrics(&self) -> PageStream<Rubric> {
411        let course_id = self.id;
412        PageStream::new_with_injector(
413            Arc::clone(self.req()),
414            &format!("courses/{course_id}/rubrics"),
415            vec![],
416            |mut r: Rubric, req| {
417                r.requester = Some(Arc::clone(&req));
418                r
419            },
420        )
421    }
422
423    /// Create a rubric in this course.
424    ///
425    /// # Canvas API
426    /// `POST /api/v1/courses/:course_id/rubrics`
427    pub async fn create_rubric(&self, params: RubricParams) -> Result<Rubric> {
428        let form = wrap_params("rubric", &params);
429        let mut rubric: Rubric = self
430            .req()
431            .post(&format!("courses/{}/rubrics", self.id), &form)
432            .await?;
433        rubric.requester = self.requester.clone();
434        Ok(rubric)
435    }
436
437    /// Fetch a single rubric association by ID.
438    ///
439    /// # Canvas API
440    /// `GET /api/v1/courses/:course_id/rubric_associations/:id`
441    pub async fn get_rubric_association(&self, association_id: u64) -> Result<RubricAssociation> {
442        let mut assoc: RubricAssociation = self
443            .req()
444            .get(
445                &format!("courses/{}/rubric_associations/{association_id}", self.id),
446                &[],
447            )
448            .await?;
449        assoc.requester = self.requester.clone();
450        Ok(assoc)
451    }
452
453    /// Stream all rubric associations for this course.
454    ///
455    /// # Canvas API
456    /// `GET /api/v1/courses/:course_id/rubric_associations`
457    pub fn get_rubric_associations(&self) -> PageStream<RubricAssociation> {
458        let course_id = self.id;
459        PageStream::new_with_injector(
460            Arc::clone(self.req()),
461            &format!("courses/{course_id}/rubric_associations"),
462            vec![],
463            |mut a: RubricAssociation, req| {
464                a.requester = Some(Arc::clone(&req));
465                a
466            },
467        )
468    }
469
470    // -------------------------------------------------------------------------
471    // Blueprint
472    // -------------------------------------------------------------------------
473
474    /// Fetch the blueprint template for this course.
475    ///
476    /// `template_id` is typically `"default"` or a numeric ID.
477    ///
478    /// # Canvas API
479    /// `GET /api/v1/courses/:course_id/blueprint_templates/:template_id`
480    pub async fn get_blueprint(&self, template_id: &str) -> Result<BlueprintTemplate> {
481        let mut tmpl: BlueprintTemplate = self
482            .req()
483            .get(
484                &format!("courses/{}/blueprint_templates/{template_id}", self.id),
485                &[],
486            )
487            .await?;
488        tmpl.requester = self.requester.clone();
489        Ok(tmpl)
490    }
491
492    /// Stream blueprint subscriptions for this (child) course.
493    ///
494    /// # Canvas API
495    /// `GET /api/v1/courses/:course_id/blueprint_subscriptions`
496    pub fn get_blueprint_subscriptions(&self) -> PageStream<BlueprintSubscription> {
497        let course_id = self.id;
498        PageStream::new_with_injector(
499            Arc::clone(self.req()),
500            &format!("courses/{course_id}/blueprint_subscriptions"),
501            vec![],
502            |mut s: BlueprintSubscription, req| {
503                s.requester = Some(Arc::clone(&req));
504                s
505            },
506        )
507    }
508
509    // -------------------------------------------------------------------------
510    // Content Migrations
511    // -------------------------------------------------------------------------
512
513    /// Fetch a single content migration by ID.
514    ///
515    /// # Canvas API
516    /// `GET /api/v1/courses/:course_id/content_migrations/:id`
517    pub async fn get_content_migration(&self, migration_id: u64) -> Result<ContentMigration> {
518        let mut migration: ContentMigration = self
519            .req()
520            .get(
521                &format!("courses/{}/content_migrations/{migration_id}", self.id),
522                &[],
523            )
524            .await?;
525        migration.requester = self.requester.clone();
526        Ok(migration)
527    }
528
529    /// Stream all content migrations for this course.
530    ///
531    /// # Canvas API
532    /// `GET /api/v1/courses/:course_id/content_migrations`
533    pub fn get_content_migrations(&self) -> PageStream<ContentMigration> {
534        let course_id = self.id;
535        PageStream::new_with_injector(
536            Arc::clone(self.req()),
537            &format!("courses/{course_id}/content_migrations"),
538            vec![],
539            |mut m: ContentMigration, req| {
540                m.requester = Some(Arc::clone(&req));
541                m
542            },
543        )
544    }
545
546    /// Create a content migration for this course.
547    ///
548    /// # Canvas API
549    /// `POST /api/v1/courses/:course_id/content_migrations`
550    pub async fn create_content_migration(
551        &self,
552        migration_type: &str,
553        params: &[(String, String)],
554    ) -> Result<ContentMigration> {
555        let mut form = vec![("migration_type".to_string(), migration_type.to_string())];
556        form.extend_from_slice(params);
557        let mut migration: ContentMigration = self
558            .req()
559            .post(&format!("courses/{}/content_migrations", self.id), &form)
560            .await?;
561        migration.requester = self.requester.clone();
562        Ok(migration)
563    }
564
565    /// Stream available content migration types for this course.
566    ///
567    /// # Canvas API
568    /// `GET /api/v1/courses/:course_id/content_migrations/migrators`
569    pub fn get_migrators(&self) -> PageStream<Migrator> {
570        PageStream::new(
571            Arc::clone(self.req()),
572            &format!("courses/{}/content_migrations/migrators", self.id),
573            vec![],
574        )
575    }
576
577    // -------------------------------------------------------------------------
578    // Outcome Groups
579    // -------------------------------------------------------------------------
580
581    /// Stream all outcome group links for this course.
582    ///
583    /// # Canvas API
584    /// `GET /api/v1/courses/:course_id/outcome_group_links`
585    pub fn get_outcome_group_links(&self) -> PageStream<OutcomeLink> {
586        PageStream::new(
587            Arc::clone(self.req()),
588            &format!("courses/{}/outcome_group_links", self.id),
589            vec![],
590        )
591    }
592
593    /// Fetch a single outcome group by ID.
594    ///
595    /// # Canvas API
596    /// `GET /api/v1/courses/:course_id/outcome_groups/:id`
597    pub async fn get_outcome_group(&self, group_id: u64) -> Result<OutcomeGroup> {
598        let mut group: OutcomeGroup = self
599            .req()
600            .get(
601                &format!("courses/{}/outcome_groups/{group_id}", self.id),
602                &[],
603            )
604            .await?;
605        group.requester = self.requester.clone();
606        Ok(group)
607    }
608
609    /// Create a top-level outcome group on this course.
610    ///
611    /// # Canvas API
612    /// `POST /api/v1/courses/:course_id/outcome_groups`
613    pub async fn create_outcome_group(
614        &self,
615        params: UpdateOutcomeGroupParams,
616    ) -> Result<OutcomeGroup> {
617        let form = wrap_params("outcome_group", &params);
618        let mut group: OutcomeGroup = self
619            .req()
620            .post(&format!("courses/{}/outcome_groups", self.id), &form)
621            .await?;
622        group.requester = self.requester.clone();
623        Ok(group)
624    }
625
626    // -------------------------------------------------------------------------
627    // Gradebook History
628    // -------------------------------------------------------------------------
629
630    /// Stream the days for which there is gradebook history in this course.
631    ///
632    /// # Canvas API
633    /// `GET /api/v1/courses/:course_id/gradebook_history/days`
634    pub fn get_gradebook_history_dates(&self) -> PageStream<Day> {
635        PageStream::new(
636            Arc::clone(self.req()),
637            &format!("courses/{}/gradebook_history/days", self.id),
638            vec![],
639        )
640    }
641
642    /// Stream graders who worked in this course on a given date.
643    ///
644    /// `date` should be formatted as `YYYY-MM-DD`.
645    ///
646    /// # Canvas API
647    /// `GET /api/v1/courses/:course_id/gradebook_history/:date`
648    pub fn get_gradebook_history_details(&self, date: &str) -> PageStream<Grader> {
649        PageStream::new(
650            Arc::clone(self.req()),
651            &format!("courses/{}/gradebook_history/{date}", self.id),
652            vec![],
653        )
654    }
655
656    /// Stream submission versions graded by a specific grader on a specific assignment and date.
657    ///
658    /// # Canvas API
659    /// `GET /api/v1/courses/:course_id/gradebook_history/:date/graders/:grader_id/assignments/:assignment_id/submissions`
660    pub fn get_submission_history(
661        &self,
662        date: &str,
663        grader_id: u64,
664        assignment_id: u64,
665    ) -> PageStream<SubmissionHistory> {
666        PageStream::new(
667            Arc::clone(self.req()),
668            &format!(
669                "courses/{}/gradebook_history/{date}/graders/{grader_id}/assignments/{assignment_id}/submissions",
670                self.id
671            ),
672            vec![],
673        )
674    }
675
676    /// Stream all submission versions (uncollated) for this course.
677    ///
678    /// # Canvas API
679    /// `GET /api/v1/courses/:course_id/gradebook_history/feed`
680    pub fn get_uncollated_submissions(&self) -> PageStream<SubmissionVersion> {
681        PageStream::new(
682            Arc::clone(self.req()),
683            &format!("courses/{}/gradebook_history/feed", self.id),
684            vec![],
685        )
686    }
687
688    // -------------------------------------------------------------------------
689    // New Quizzes (feature = "new-quizzes")
690    // -------------------------------------------------------------------------
691
692    /// Fetch a single New Quiz by its assignment ID.
693    ///
694    /// # Canvas API
695    /// `GET /api/quiz/v1/courses/:course_id/quizzes/:assignment_id`
696    #[cfg(feature = "new-quizzes")]
697    pub async fn get_new_quiz(
698        &self,
699        assignment_id: &str,
700    ) -> Result<crate::resources::new_quiz::NewQuiz> {
701        let mut quiz: crate::resources::new_quiz::NewQuiz = self
702            .req()
703            .nq_get(&format!("courses/{}/quizzes/{assignment_id}", self.id), &[])
704            .await?;
705        quiz.requester = self.requester.clone();
706        quiz.course_id = Some(self.id);
707        Ok(quiz)
708    }
709
710    /// Stream all New Quizzes for this course.
711    ///
712    /// # Canvas API
713    /// `GET /api/quiz/v1/courses/:course_id/quizzes`
714    #[cfg(feature = "new-quizzes")]
715    pub fn get_new_quizzes(&self) -> PageStream<crate::resources::new_quiz::NewQuiz> {
716        let course_id = self.id;
717        PageStream::new_with_injector_nq(
718            Arc::clone(self.req()),
719            &format!("courses/{course_id}/quizzes"),
720            vec![],
721            move |mut q: crate::resources::new_quiz::NewQuiz, req| {
722                q.requester = Some(Arc::clone(&req));
723                q.course_id = Some(course_id);
724                q
725            },
726        )
727    }
728
729    /// Create a New Quiz in this course.
730    ///
731    /// # Canvas API
732    /// `POST /api/quiz/v1/courses/:course_id/quizzes`
733    #[cfg(feature = "new-quizzes")]
734    pub async fn create_new_quiz(
735        &self,
736        params: crate::resources::new_quiz::NewQuizParams,
737    ) -> Result<crate::resources::new_quiz::NewQuiz> {
738        let body = serde_json::to_value(&params).unwrap_or_default();
739        let mut quiz: crate::resources::new_quiz::NewQuiz = self
740            .req()
741            .nq_post(&format!("courses/{}/quizzes", self.id), &body)
742            .await?;
743        quiz.requester = self.requester.clone();
744        quiz.course_id = Some(self.id);
745        Ok(quiz)
746    }
747}