@@ -47,6 +47,8 @@ pub struct TmcCore {
4747 auth_url : String ,
4848 token : Option < Token > ,
4949 progress_report : Option < UpdateClosure > ,
50+ client_name : String ,
51+ client_version : String ,
5052}
5153
5254// TODO: cache API results?
@@ -61,9 +63,14 @@ impl TmcCore {
6163 /// use tmc_langs_core::TmcCore;
6264 /// use std::path::PathBuf;
6365 ///
64- /// let core = TmcCore::new(PathBuf::from("./config"), "https://tmc.mooc.fi".to_string()).unwrap();
66+ /// let core = TmcCore::new(PathBuf::from("./config"), "https://tmc.mooc.fi".to_string(), "some_client".to_string(), "some_version".to_string() ).unwrap();
6567 /// ```
66- pub fn new ( config_dir : PathBuf , root_url : String ) -> Result < Self > {
68+ pub fn new (
69+ config_dir : PathBuf ,
70+ root_url : String ,
71+ client_name : String ,
72+ client_version : String ,
73+ ) -> Result < Self > {
6774 // guarantee a trailing slash, otherwise join will drop the last component
6875 let root_url = if root_url. ends_with ( '/' ) {
6976 root_url
@@ -83,6 +90,8 @@ impl TmcCore {
8390 auth_url,
8491 token : None ,
8592 progress_report : None ,
93+ client_name,
94+ client_version,
8695 } )
8796 }
8897
@@ -95,11 +104,15 @@ impl TmcCore {
95104 /// ```rust,no_run
96105 /// use tmc_langs_core::TmcCore;
97106 ///
98- /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
107+ /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string(), "some_client".to_string(), "some_ver".to_string() ).unwrap();
99108 /// ```
100- pub fn new_in_config ( root_url : String ) -> Result < Self > {
109+ pub fn new_in_config (
110+ root_url : String ,
111+ client_name : String ,
112+ client_version : String ,
113+ ) -> Result < Self > {
101114 let config_dir = dirs:: cache_dir ( ) . ok_or ( CoreError :: CacheDir ) ?;
102- Self :: new ( config_dir, root_url)
115+ Self :: new ( config_dir, root_url, client_name , client_version )
103116 }
104117
105118 pub fn set_token ( & mut self , token : Token ) {
@@ -145,7 +158,7 @@ impl TmcCore {
145158 /// ```rust,no_run
146159 /// use tmc_langs_core::TmcCore;
147160 ///
148- /// let mut core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
161+ /// let mut core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string(), "some_client".to_string(), "some_version".to_string() ).unwrap();
149162 /// core.authenticate("client", "user".to_string(), "pass".to_string()).unwrap();
150163 /// ```
151164 pub fn authenticate (
@@ -214,7 +227,7 @@ impl TmcCore {
214227 /// use tmc_langs_core::TmcCore;
215228 /// use std::path::Path;
216229 ///
217- /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
230+ /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string(), "some_client".to_string(), "some_version".to_string() ).unwrap();
218231 /// // authenticate
219232 /// core.download_or_update_exercises(vec![
220233 /// (1234, Path::new("./exercises/1234")),
@@ -250,7 +263,7 @@ impl TmcCore {
250263 /// ```rust,no_run
251264 /// use tmc_langs_core::TmcCore;
252265 ///
253- /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
266+ /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string(), "some_client".to_string(), "some_version".to_string() ).unwrap();
254267 /// // authenticate
255268 /// let course_details = core.get_course_details(600).unwrap();
256269 /// ```
@@ -275,7 +288,7 @@ impl TmcCore {
275288 /// ```rust,no_run
276289 /// use tmc_langs_core::TmcCore;
277290 ///
278- /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
291+ /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string(), "some_client".to_string(), "some_version".to_string() ).unwrap();
279292 /// // authenticate
280293 /// let courses = core.list_courses("hy").unwrap();
281294 /// ```
@@ -297,7 +310,7 @@ impl TmcCore {
297310 /// use url::Url;
298311 /// use std::path::Path;
299312 ///
300- /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
313+ /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string(), "some_client".to_string(), "some_version".to_string() ).unwrap();
301314 /// // authenticate
302315 /// let course_details = core.get_course_details(600).unwrap();
303316 /// let submission_url = &course_details.exercises[0].return_url;
@@ -335,7 +348,7 @@ impl TmcCore {
335348 /// use tmc_langs_core::{TmcCore, Language};
336349 /// use std::path::Path;
337350 ///
338- /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
351+ /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string(), "some_client".to_string(), "some_version".to_string() ).unwrap();
339352 /// // authenticate
340353 /// let validation_result = core.run_checkstyle(Path::new("./exercises/python/123"), Language::Eng).unwrap();
341354 /// match validation_result {
@@ -418,10 +431,30 @@ impl TmcCore {
418431 }
419432
420433 pub fn wait_for_submission ( & self , submission_url : & str ) -> Result < SubmissionFinished > {
434+ let mut previous_status = None ;
421435 loop {
422436 match self . check_submission ( submission_url) ? {
423- SubmissionProcessingStatus :: Finished ( f) => return Ok ( * f) ,
424- SubmissionProcessingStatus :: Processing ( _p) => {
437+ SubmissionProcessingStatus :: Finished ( f) => {
438+ self . report_complete ( "Submission finished processing!" ) ;
439+ return Ok ( * f) ;
440+ }
441+ SubmissionProcessingStatus :: Processing ( p) => {
442+ match ( & mut previous_status, p. sandbox_status ) {
443+ ( Some ( previous) , status) if status == * previous => { } // no change, ignore
444+ ( _, status) => {
445+ // new status, update progress
446+ match status {
447+ SandboxStatus :: Created => self . report_progress ( "Created" , 0.25 ) ,
448+ SandboxStatus :: SendingToSandbox => {
449+ self . report_progress ( "Sending to sandbox" , 0.5 )
450+ }
451+ SandboxStatus :: ProcessingOnSandbox => {
452+ self . report_progress ( "Processing on sandbox" , 0.75 )
453+ }
454+ }
455+ previous_status = Some ( status) ;
456+ }
457+ }
425458 thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
426459 }
427460 }
@@ -441,7 +474,7 @@ impl TmcCore {
441474 /// ```rust,no_run
442475 /// use tmc_langs_core::TmcCore;
443476 ///
444- /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string()).unwrap();
477+ /// let core = TmcCore::new_in_config("https://tmc.mooc.fi".to_string(), "some_client".to_string(), "some_version".to_string() ).unwrap();
445478 /// // authenticate
446479 /// let mut checksums = std::collections::HashMap::new();
447480 /// checksums.insert(1234, "exercisechecksum".to_string());
@@ -573,7 +606,12 @@ mod test {
573606 . create ( ) ;
574607 let local_server = mockito:: server_url ( ) ;
575608 log:: debug!( "local {}" , local_server) ;
576- let mut core = TmcCore :: new_in_config ( local_server. to_string ( ) ) . unwrap ( ) ;
609+ let mut core = TmcCore :: new_in_config (
610+ local_server. to_string ( ) ,
611+ "some_client" . to_string ( ) ,
612+ "some_ver" . to_string ( ) ,
613+ )
614+ . unwrap ( ) ;
577615 core. authenticate ( "client_name" , "email" . to_string ( ) , "password" . to_string ( ) )
578616 . unwrap ( ) ;
579617 ( core, local_server)
@@ -583,6 +621,8 @@ mod test {
583621 fn gets_organizations ( ) {
584622 let ( core, _addr) = init ( ) ;
585623 let _m = mock ( "GET" , "/api/v8/org.json" )
624+ . match_header ( "client" , "some_client" )
625+ . match_header ( "client_version" , "some_ver" )
586626 . with_body (
587627 serde_json:: json!( [
588628 {
@@ -604,6 +644,8 @@ mod test {
604644 fn downloads_or_update_exercises ( ) {
605645 let ( core, _addr) = init ( ) ;
606646 let _m = mock ( "GET" , "/api/v8/core/exercises/1234/download" )
647+ . match_header ( "client" , "some_client" )
648+ . match_header ( "client_version" , "some_ver" )
607649 . with_body_from_file ( Path :: new ( "tests/data/81842.zip" ) )
608650 . create ( ) ;
609651
@@ -619,6 +661,8 @@ mod test {
619661 fn gets_course_details ( ) {
620662 let ( core, _addr) = init ( ) ;
621663 let _m = mock ( "GET" , "/api/v8/core/courses/1234" )
664+ . match_header ( "client" , "some_client" )
665+ . match_header ( "client_version" , "some_ver" )
622666 . with_body ( serde_json:: json!( {
623667 "course" : {
624668 "id" : 588 ,
@@ -669,6 +713,8 @@ mod test {
669713 fn lists_courses ( ) {
670714 let ( core, _addr) = init ( ) ;
671715 let _m = mock ( "GET" , "/api/v8/core/org/slug/courses" )
716+ . match_header ( "client" , "some_client" )
717+ . match_header ( "client_version" , "some_ver" )
672718 . with_body ( serde_json:: json!( [
673719 {
674720 "id" : 277 ,
@@ -696,6 +742,8 @@ mod test {
696742 let ( core, url) = init ( ) ;
697743 let submission_url = Url :: parse ( & format ! ( "{}/submission" , url) ) . unwrap ( ) ;
698744 let _m = mock ( "POST" , "/submission" )
745+ . match_header ( "client" , "some_client" )
746+ . match_header ( "client_version" , "some_ver" )
699747 . match_body ( Matcher :: Regex ( "paste" . to_string ( ) ) )
700748 . match_body ( Matcher :: Regex ( "message_for_paste" . to_string ( ) ) )
701749 . match_body ( Matcher :: Regex ( "abcdefg" . to_string ( ) ) )
@@ -738,6 +786,8 @@ mod test {
738786 let ( core, url) = init ( ) ;
739787 let feedback_url = Url :: parse ( & format ! ( "{}/feedback" , url) ) . unwrap ( ) ;
740788 let _m = mock ( "POST" , "/feedback" )
789+ . match_header ( "client" , "some_client" )
790+ . match_header ( "client_version" , "some_ver" )
741791 . match_body ( Matcher :: AllOf ( vec ! [
742792 Matcher :: Regex ( r#"answers\[0\]\[question_id\]"# . to_string( ) ) ,
743793 Matcher :: Regex ( r#"answers\[0\]\[answer\]"# . to_string( ) ) ,
@@ -780,6 +830,8 @@ mod test {
780830 let ( core, url) = init ( ) ;
781831 let submission_url = Url :: parse ( & format ! ( "{}/submission" , url) ) . unwrap ( ) ;
782832 let _m = mock ( "POST" , "/submission" )
833+ . match_header ( "client" , "some_client" )
834+ . match_header ( "client_version" , "some_ver" )
783835 . match_body ( Matcher :: Regex ( r#"submission\[file\]"# . to_string ( ) ) )
784836 . with_body (
785837 serde_json:: json!( {
@@ -808,6 +860,8 @@ mod test {
808860 fn gets_exercise_updates ( ) {
809861 let ( core, _addr) = init ( ) ;
810862 let _m = mock ( "GET" , "/api/v8/core/courses/1234" )
863+ . match_header ( "client" , "some_client" )
864+ . match_header ( "client_version" , "some_ver" )
811865 . with_body ( serde_json:: json!( {
812866 "course" : {
813867 "id" : 588 ,
@@ -924,6 +978,8 @@ mod test {
924978 let ( core, addr) = init ( ) ;
925979 let reviews_url = Url :: parse ( & format ! ( "{}/reviews" , addr) ) . unwrap ( ) ;
926980 let _m = mock ( "GET" , "/reviews" )
981+ . match_header ( "client" , "some_client" )
982+ . match_header ( "client_version" , "some_ver" )
927983 . with_body (
928984 serde_json:: json!( [
929985 {
@@ -955,6 +1011,8 @@ mod test {
9551011 let ( core, url) = init ( ) ;
9561012 let submission_url = Url :: parse ( & format ! ( "{}/submission" , url) ) . unwrap ( ) ;
9571013 let _m = mock ( "POST" , "/submission" )
1014+ . match_header ( "client" , "some_client" )
1015+ . match_header ( "client_version" , "some_ver" )
9581016 . match_body ( Matcher :: Regex ( "request_review" . to_string ( ) ) )
9591017 . match_body ( Matcher :: Regex ( "message_for_reviewer" . to_string ( ) ) )
9601018 . match_body ( Matcher :: Regex ( "abcdefg" . to_string ( ) ) )
@@ -987,6 +1045,8 @@ mod test {
9871045 let ( core, addr) = init ( ) ;
9881046 let solution_url = Url :: parse ( & format ! ( "{}/solution" , addr) ) . unwrap ( ) ;
9891047 let _m = mock ( "GET" , "/solution" )
1048+ . match_header ( "client" , "some_client" )
1049+ . match_header ( "client_version" , "some_ver" )
9901050 . with_body_from_file ( Path :: new ( "tests/data/81842.zip" ) )
9911051 . create ( ) ;
9921052
@@ -1001,6 +1061,8 @@ mod test {
10011061 fn checks_submission_processing ( ) {
10021062 let ( core, addr) = init ( ) ;
10031063 let _m = mock ( "GET" , "/submission-url" )
1064+ . match_header ( "client" , "some_client" )
1065+ . match_header ( "client_version" , "some_ver" )
10041066 . with_body (
10051067 serde_json:: json!( {
10061068 "status" : "processing" ,
@@ -1023,7 +1085,8 @@ mod test {
10231085 #[ test]
10241086 fn checks_submission_finished ( ) {
10251087 let ( core, addr) = init ( ) ;
1026- let _m = mock ( "GET" , "/submission-url" ) . with_body ( serde_json:: json!( {
1088+ let m = mock ( "GET" , "/submission-url" )
1089+ . with_body ( serde_json:: json!( {
10271090 "api_version" : 7 ,
10281091 "all_tests_passed" : true ,
10291092 "user_id" : 3232 ,
0 commit comments