@@ -10,8 +10,9 @@ pub use self::exercise::{
1010} ;
1111use crate :: error:: { MoocClientError , MoocClientResult } ;
1212use bytes:: Bytes ;
13+ use chrono:: { DateTime , Utc } ;
1314use exercise:: UserAnswer ;
14- pub use mooc_langs_api:: * ;
15+ pub use mooc_langs_api as api ;
1516use oauth2:: TokenResponse ;
1617use reqwest:: {
1718 blocking:: {
@@ -23,6 +24,8 @@ use reqwest::{
2324use serde:: { de:: DeserializeOwned , Serialize } ;
2425use std:: { borrow:: Cow , path:: Path , sync:: Arc } ;
2526use tmc_langs_util:: { serialize, JsonError } ;
27+ #[ cfg( feature = "ts-rs" ) ]
28+ use ts_rs:: TS ;
2629use uuid:: Uuid ;
2730
2831/// Client for accessing the Courses MOOC API.
@@ -33,7 +36,7 @@ pub struct MoocClient(Arc<MoocClientInner>);
3336struct MoocClientInner {
3437 client : Client ,
3538 root_addr : Cow < ' static , str > ,
36- token : Option < Token > ,
39+ token : Option < api :: Token > ,
3740}
3841
3942/// Non-API methods.
@@ -78,7 +81,7 @@ impl MoocClient {
7881 }
7982 }
8083
81- pub fn set_token ( & mut self , token : Token ) {
84+ pub fn set_token ( & mut self , token : api :: Token ) {
8285 Arc :: get_mut ( & mut self . 0 )
8386 . expect ( "called when multiple clones exist" )
8487 . token = Some ( token) ;
@@ -90,8 +93,8 @@ impl MoocClient {
9093 pub fn course_instances ( & self ) -> MoocClientResult < Vec < CourseInstance > > {
9194 let res = self
9295 . request ( Method :: GET , "course-instances" )
93- . send_expect_json ( ) ?;
94- Ok ( res)
96+ . send_expect_json :: < Vec < api :: CourseInstance > > ( ) ?;
97+ Ok ( res. into_iter ( ) . map ( Into :: into ) . collect ( ) )
9598 }
9699
97100 pub fn course_instance_exercise_slides (
@@ -101,7 +104,7 @@ impl MoocClient {
101104 let url = format ! ( "course-instances/{course_instance}/exercises" ) ;
102105 let res = self
103106 . request ( Method :: GET , & url)
104- . send_expect_json :: < Vec < ExerciseSlide > > ( ) ?
107+ . send_expect_json :: < Vec < api :: ExerciseSlide > > ( ) ?
105108 . into_iter ( )
106109 . map ( TryFrom :: try_from)
107110 . collect :: < Result < _ , JsonError > > ( )
@@ -116,7 +119,7 @@ impl MoocClient {
116119 let url = format ! ( "exercises/{exercise}" ) ;
117120 let res = self
118121 . request ( Method :: GET , & url)
119- . send_expect_json :: < ExerciseSlide > ( ) ?
122+ . send_expect_json :: < api :: ExerciseSlide > ( ) ?
120123 . try_into ( )
121124 . map_err ( |err : JsonError | MoocClientError :: DeserializingResponse {
122125 url,
@@ -145,7 +148,7 @@ impl MoocClient {
145148 archive : & Path ,
146149 ) -> MoocClientResult < ExerciseTaskSubmissionResult > {
147150 // upload archive
148- let metadata = UploadMetadata { slide_id, task_id } ;
151+ let metadata = api :: UploadMetadata { slide_id, task_id } ;
149152 let metadata = serialize:: to_json_vec ( & metadata) ?;
150153 let form = Form :: new ( )
151154 . part (
@@ -159,23 +162,23 @@ impl MoocClient {
159162 let res = self
160163 . request ( Method :: POST , & format ! ( "exercises/{exercise_id}/upload" ) )
161164 . multipart ( form)
162- . send_expect_json :: < UploadResult > ( ) ?;
165+ . send_expect_json :: < api :: UploadResult > ( ) ?;
163166
164167 // send submission
165168 let user_answer = UserAnswer :: Editor {
166169 download_url : res. download_url ,
167170 } ;
168171 let data_json = serialize:: to_json_value ( & user_answer) ?;
169- let exercise_slide_submission = ExerciseSlideSubmission {
172+ let exercise_slide_submission = api :: ExerciseSlideSubmission {
170173 exercise_slide_id : slide_id,
171174 exercise_task_id : task_id,
172175 data_json,
173176 } ;
174177 let res = self
175178 . request ( Method :: POST , & format ! ( "exercises/{exercise_id}/submit" ) )
176179 . json ( & exercise_slide_submission)
177- . send_expect_json ( ) ?;
178- Ok ( res)
180+ . send_expect_json :: < api :: ExerciseTaskSubmissionResult > ( ) ?;
181+ Ok ( res. into ( ) )
179182 }
180183
181184 pub fn get_submission_grading (
@@ -184,8 +187,8 @@ impl MoocClient {
184187 ) -> MoocClientResult < ExerciseTaskSubmissionStatus > {
185188 let res = self
186189 . request ( Method :: GET , & format ! ( "submissions/{submission_id}/grading" ) )
187- . send_expect_json ( ) ?;
188- Ok ( res)
190+ . send_expect_json :: < api :: ExerciseTaskSubmissionStatus > ( ) ?;
191+ Ok ( res. into ( ) )
189192 }
190193}
191194
@@ -272,3 +275,107 @@ impl MoocRequest {
272275 Ok ( json)
273276 }
274277}
278+
279+ #[ derive( Debug , Serialize ) ]
280+ #[ cfg_attr( feature = "ts-rs" , derive( TS ) ) ]
281+ pub struct CourseInstance {
282+ pub id : Uuid ,
283+ pub course_id : Uuid ,
284+ pub course_slug : String ,
285+ pub course_name : String ,
286+ pub course_description : Option < String > ,
287+ pub instance_name : Option < String > ,
288+ pub instance_description : Option < String > ,
289+ }
290+
291+ impl From < api:: CourseInstance > for CourseInstance {
292+ fn from ( value : api:: CourseInstance ) -> Self {
293+ Self {
294+ id : value. id ,
295+ course_id : value. course_id ,
296+ course_slug : value. course_slug ,
297+ course_name : value. course_name ,
298+ course_description : value. course_description ,
299+ instance_name : value. instance_name ,
300+ instance_description : value. instance_description ,
301+ }
302+ }
303+ }
304+
305+ #[ derive( Debug , Serialize ) ]
306+ #[ cfg_attr( feature = "ts-rs" , derive( TS ) ) ]
307+ pub struct ExerciseTaskSubmissionResult {
308+ pub submission_id : Uuid ,
309+ }
310+
311+ impl From < api:: ExerciseTaskSubmissionResult > for ExerciseTaskSubmissionResult {
312+ fn from ( value : api:: ExerciseTaskSubmissionResult ) -> Self {
313+ Self {
314+ submission_id : value. submission_id ,
315+ }
316+ }
317+ }
318+
319+ #[ derive( Debug , Serialize ) ]
320+ #[ cfg_attr( feature = "ts-rs" , derive( TS ) ) ]
321+ pub enum ExerciseTaskSubmissionStatus {
322+ NoGradingYet ,
323+ Grading {
324+ grading_progress : GradingProgress ,
325+ score_given : Option < f32 > ,
326+ grading_started_at : Option < DateTime < Utc > > ,
327+ grading_completed_at : Option < DateTime < Utc > > ,
328+ feedback_json : Option < serde_json:: Value > ,
329+ feedback_text : Option < String > ,
330+ } ,
331+ }
332+
333+ impl From < api:: ExerciseTaskSubmissionStatus > for ExerciseTaskSubmissionStatus {
334+ fn from ( value : api:: ExerciseTaskSubmissionStatus ) -> Self {
335+ match value {
336+ api:: ExerciseTaskSubmissionStatus :: NoGradingYet => Self :: NoGradingYet ,
337+ api:: ExerciseTaskSubmissionStatus :: Grading {
338+ grading_progress,
339+ score_given,
340+ grading_started_at,
341+ grading_completed_at,
342+ feedback_json,
343+ feedback_text,
344+ } => Self :: Grading {
345+ grading_progress : grading_progress. into ( ) ,
346+ score_given,
347+ grading_started_at,
348+ grading_completed_at,
349+ feedback_json,
350+ feedback_text,
351+ } ,
352+ }
353+ }
354+ }
355+
356+ #[ derive( Debug , Clone , Copy , Serialize ) ]
357+ #[ cfg_attr( feature = "ts-rs" , derive( TS ) ) ]
358+ pub enum GradingProgress {
359+ /// The grading could not complete.
360+ Failed ,
361+ /// There is no grading process occurring; for example, the student has not yet made any submission.
362+ NotReady ,
363+ /// Final Grade is pending, and it does require human intervention; if a Score value is present, it indicates the current value is partial and may be updated during the manual grading.
364+ PendingManual ,
365+ /// Final Grade is pending, but does not require manual intervention; if a Score value is present, it indicates the current value is partial and may be updated.
366+ Pending ,
367+ /// The grading process is completed; the score value, if any, represents the current Final Grade;
368+ FullyGraded ,
369+ }
370+
371+ impl From < api:: GradingProgress > for GradingProgress {
372+ fn from ( value : api:: GradingProgress ) -> Self {
373+ match value {
374+ api:: GradingProgress :: Failed => Self :: Failed ,
375+ api:: GradingProgress :: NotReady => Self :: NotReady ,
376+ api:: GradingProgress :: PendingManual => Self :: PendingManual ,
377+ api:: GradingProgress :: Pending => Self :: Pending ,
378+ api:: GradingProgress :: FullyGraded => Self :: FullyGraded ,
379+ }
380+ }
381+ }
0 commit comments