Skip to content

Commit 12f021b

Browse files
authored
Merge pull request #178 from rage/reintroduce-urls
Reintroduce urls
2 parents 792d36e + 0f27f61 commit 12f021b

File tree

10 files changed

+200
-119
lines changed

10 files changed

+200
-119
lines changed

tmc-client/src/error.rs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@ type TokenError = oauth2::RequestTokenError<
1313
/// The main error type for tmc-client.
1414
#[derive(Debug, Error)]
1515
pub enum ClientError {
16-
// Arc
17-
#[error("Tried to mutate client while it was borrowed")]
18-
ArcBorrowed,
19-
20-
// file IO
21-
#[error("Failed to create temporary file")]
22-
TempFile(#[source] std::io::Error),
23-
24-
// network
2516
#[error("HTTP error {status} for {url}: {error}. Obsolete client: {obsolete_client}")]
2617
HttpError {
2718
url: Url,
@@ -33,37 +24,23 @@ pub enum ClientError {
3324
ConnectionError(Method, Url, #[source] reqwest::Error),
3425
#[error("OAuth2 password exchange error")]
3526
Token(#[source] Box<TokenError>),
36-
#[error("OAuth2 unexpected token response: {0}")]
37-
TokenParse(String, #[source] serde_json::error::Error),
3827
#[error("Failed to parse as URL: {0}")]
3928
UrlParse(String, #[source] url::ParseError),
4029
#[error("Failed to write response")]
4130
HttpWriteResponse(#[source] reqwest::Error),
4231
#[error("Failed to deserialize response from {0} as JSON")]
4332
HttpJsonResponse(Url, #[source] reqwest::Error),
4433

45-
#[error("Failed to download some exercises")]
46-
IncompleteDownloadResult {
47-
downloaded: Vec<u32>,
48-
failed: Vec<(u32, Box<ClientError>)>,
49-
},
50-
5134
#[error("Already authenticated")]
5235
AlreadyAuthenticated,
5336
#[error("Authentication required")]
54-
NotLoggedIn,
55-
#[error("Failed to find cache directory")]
56-
CacheDir,
57-
#[error("No values found in exercise details map returned by server")]
58-
MissingDetailsValue,
59-
#[error("List of exercises given was empty")]
60-
NoExercisesGiven,
37+
NotAuthenticated,
6138

6239
#[error(transparent)]
6340
SystemTime(#[from] std::time::SystemTimeError),
6441
#[error(transparent)]
6542
WalkDir(#[from] walkdir::Error),
66-
#[error("File IO error")]
43+
#[error(transparent)]
6744
FileError(#[from] FileError),
6845
#[error(transparent)]
6946
Plugin(#[from] tmc_langs_plugins::PluginError),

tmc-client/src/lib.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,13 @@
1212
//!
1313
1414
mod error;
15-
mod request;
16-
mod response;
15+
pub mod request;
16+
pub mod response;
1717
mod tmc_client;
1818

1919
pub use self::error::ClientError;
20-
pub use self::request::FeedbackAnswer;
21-
pub use self::response::{
22-
Course, CourseData, CourseDataExercise, CourseDataExercisePoint, CourseDetails, CourseExercise,
23-
Exercise, ExerciseDetails, ExercisesDetails, NewSubmission, Organization, Review, Submission,
24-
SubmissionFeedbackResponse, SubmissionFinished, SubmissionProcessingStatus, SubmissionStatus,
25-
UpdateResult, User,
26-
};
27-
pub use self::tmc_client::{api_v8, ClientUpdateData, TmcClient, Token};
20+
pub use self::tmc_client::{api_v8, ClientUpdateData, TmcClient, Token, UpdateResult};
21+
22+
// these types are part of tmc-client's API and thus re-exported
2823
pub use oauth2;
29-
pub use tmc_langs_plugins::{Language, RunResult, StyleValidationResult, StyleValidationStrategy};
24+
pub use tmc_langs_plugins::Language;

tmc-client/src/response.rs

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,18 @@ pub struct ErrorResponse {
2525
pub obsolete_client: bool,
2626
}
2727

28-
/// OAuth2 credentials
28+
/// OAuth2 credentials.
29+
/// get /api/v8/application/{client_name}/credentials
2930
#[derive(Debug, Deserialize)]
3031
pub struct Credentials {
3132
pub application_id: String,
3233
pub secret: String,
3334
}
3435

36+
/// get /api/v8/users/{user_id}
37+
/// get /api/v8/users/current
38+
/// post /api/v8/users/basic_info_by_usernames
39+
/// post /api/v8/users/basic_info_by_emails
3540
#[derive(Debug, Deserialize)]
3641
pub struct User {
3742
pub id: u32,
@@ -40,7 +45,8 @@ pub struct User {
4045
pub administrator: bool,
4146
}
4247

43-
/// Organization information.
48+
/// get /api/v8/org.json
49+
/// get /api/v8/org/{organization_slug}.json
4450
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
4551
pub struct Organization {
4652
pub name: String,
@@ -50,21 +56,26 @@ pub struct Organization {
5056
pub pinned: bool,
5157
}
5258

53-
/// Information for a course.
59+
/// get /api/v8/core/org/{organization_slug}/courses
5460
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
5561
pub struct Course {
5662
pub id: u32,
5763
pub name: String,
5864
pub title: String,
5965
pub description: Option<String>,
66+
/// /api/v8/core/courses/{course_id}
6067
pub details_url: String,
68+
/// /api/v8/core/courses/{course_id}/unlock
6169
pub unlock_url: String,
70+
/// /api/v8/core/courses/{course_id}/reviews
6271
pub reviews_url: String,
72+
/// Typically empty.
6373
pub comet_url: String,
6474
pub spyware_urls: Vec<String>,
6575
}
6676

67-
/// Data for a course.
77+
/// get /api/v8/courses/{course_id}
78+
/// get /api/v8/org/{organization_slug}/courses/{course_name}
6879
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
6980
pub struct CourseData {
7081
pub name: String,
@@ -83,9 +94,11 @@ pub struct CourseData {
8394
pub organization_id: Option<u32>,
8495
pub disabled_status: Option<String>,
8596
pub title: Option<String>,
97+
/// Typically empty.
8698
pub material_url: Option<String>,
8799
pub course_template_id: Option<u32>,
88100
pub hide_submission_results: bool,
101+
/// Typically empty.
89102
pub external_scoreboard_url: Option<String>,
90103
pub organization_slug: Option<String>,
91104
}
@@ -106,7 +119,7 @@ struct CourseDetailsInner {
106119
pub exercises: Vec<Exercise>,
107120
}
108121

109-
/// Details for a course.
122+
/// get /api/v8/core/courses/{course_id}
110123
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
111124
#[serde(from = "CourseDetailsWrapper")]
112125
pub struct CourseDetails {
@@ -136,7 +149,9 @@ pub struct Exercise {
136149
pub soft_deadline: Option<String>,
137150
pub soft_deadline_description: Option<String>,
138151
pub checksum: String,
152+
/// /api/v8/core/exercises/{exercise_id}/submissions
139153
pub return_url: String,
154+
/// /api/v8/core/exercises/{exercise_id}/download
140155
pub zip_url: String,
141156
pub returnable: bool,
142157
pub requires_review: bool,
@@ -149,12 +164,14 @@ pub struct Exercise {
149164
pub valgrind_strategy: String,
150165
pub code_review_requests_enabled: bool,
151166
pub run_tests_locally_action_enabled: bool,
167+
/// Typically null.
152168
pub latest_submission_url: Option<String>,
153169
pub latest_submission_id: Option<u32>,
170+
/// /api/v8/core/exercises/{exercise_id}/solution/download
154171
pub solution_zip_url: Option<String>,
155172
}
156173

157-
/// Exercise for a course.
174+
/// get /api/v8/courses/{course_id}/exercises
158175
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
159176
pub struct CourseExercise {
160177
pub id: u32,
@@ -169,6 +186,7 @@ pub struct CourseExercise {
169186
pub unlocked: bool,
170187
}
171188

189+
/// get /api/v8/org/{organization_slug}/courses/{course_name}/exercises
172190
#[derive(Debug, Deserialize)]
173191
pub struct CourseDataExercise {
174192
pub id: u32,
@@ -188,6 +206,16 @@ pub struct ExercisePoint {
188206
pub requires_review: bool,
189207
}
190208

209+
/// get /api/v8/courses/{course_id}/points
210+
/// get /api/v8/courses/{course_id}/exercises/{exercise_name}/points
211+
/// get /api/v8/courses/{course_id}/exercises/{exercise_name}/users/{user_id}/
212+
/// get /api/v8/courses/{course_id}/exercises/{exercise_name}/users/current/points
213+
/// get /api/v8/courses/{course_id}/users/{user_id}/points
214+
/// get /api/v8/courses/{course_id}/users/current/points
215+
/// get /api/v8/org/{organization_slug}/courses/{course_name}/points
216+
/// get /api/v8/org/{organization_slug}/courses/{course_name}/exercises/{exercise_name}/points
217+
/// get /api/v8/org/{organization_slug}/courses/{course_name}/users/{user_id}/points
218+
/// get /api/v8/org/{organization_slug}/courses/{course_name}/users/current/points
191219
#[derive(Debug, Deserialize)]
192220
pub struct CourseDataExercisePoint {
193221
awarded_point: AwardedPoint,
@@ -204,7 +232,7 @@ pub struct AwardedPoint {
204232
created_at: DateTime<FixedOffset>,
205233
}
206234

207-
/// Details for an exercise.
235+
/// get /api/v8/core/exercises/{exercise_id}
208236
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
209237
pub struct ExerciseDetails {
210238
pub course_name: String,
@@ -218,6 +246,12 @@ pub struct ExerciseDetails {
218246
pub submissions: Vec<ExerciseSubmission>,
219247
}
220248

249+
/// get /api/v8/core/exercises/details
250+
#[derive(Debug, Deserialize)]
251+
pub(crate) struct ExercisesDetailsWrapper {
252+
pub exercises: Vec<ExercisesDetails>,
253+
}
254+
221255
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
222256
pub struct ExercisesDetails {
223257
pub id: u32,
@@ -226,7 +260,16 @@ pub struct ExercisesDetails {
226260
pub checksum: String,
227261
}
228262

229-
/// Exercise submission.
263+
/// get /api/v8/courses/{course_id}/submissions
264+
/// get /api/v8/courses/{course_id}/users/{user_id}/submissions
265+
/// get /api/v8/courses/{course_id}/users/current/submissions
266+
/// get api/v8/exercises/{exercise_id}/users/{user_id}/submissions
267+
/// get api/v8/exercises/{exercise_id}/users/current/submissions
268+
/// get /api/v8/org/{organization_slug}/courses/{course_name}/submissions
269+
/// get /api/v8/org/{organization_slug}/courses/{course_name}/users/{user_id}/submissions
270+
/// get /api/v8/org/{organization_slug}/courses/{course_name}/users/current/submissions
271+
/// get api/v8/exercises/{exercise_id}/users/{user_id}/submissions
272+
/// get api/v8/exercises/{exercise_id}/users/current/submissions
230273
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
231274
pub struct Submission {
232275
pub id: u32,
@@ -264,21 +307,27 @@ pub struct ExerciseSubmission {
264307
pub created_at: DateTime<FixedOffset>,
265308
pub all_tests_passed: bool,
266309
pub points: Option<String>,
310+
/// /api/v8/core/submissions/{submission_id}/download
267311
pub submitted_zip_url: String,
312+
/// https://tmc.mooc.fi/paste/{paste_code}
268313
pub paste_url: Option<String>,
269314
pub processing_time: Option<u32>,
270315
pub reviewed: bool,
271316
pub requests_review: bool,
272317
}
273318

274-
/// Exercise submission.
319+
/// post /api/v8/core/exercises/{exercise_id}/submissions
275320
#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone)]
276321
pub struct NewSubmission {
322+
/// https://tmc.mooc.fi/api/v8/core/submissions/{submission_id}
277323
pub show_submission_url: String,
324+
/// https://tmc.mooc.fi/paste/{paste_code}
278325
pub paste_url: String, // use Option and serde_with::string_empty_as_none ?
326+
/// https://tmc.mooc.fi/submissions/{submission_id}
279327
pub submission_url: String,
280328
}
281329

330+
/// get /api/v8/core/submission/{submission_id}
282331
#[derive(Debug, Deserialize, Serialize)]
283332
#[serde(untagged)] // TODO: tag
284333
pub enum SubmissionProcessingStatus {
@@ -300,7 +349,6 @@ pub enum SandboxStatus {
300349
ProcessingOnSandbox,
301350
}
302351

303-
/// Finished submission.
304352
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
305353
pub struct SubmissionFinished {
306354
pub api_version: u32,
@@ -312,17 +360,21 @@ pub struct SubmissionFinished {
312360
pub status: SubmissionStatus,
313361
pub points: Vec<String>,
314362
pub valgrind: Option<String>,
363+
/// https://tmc.mooc.fi/submissions/{submission_id}}
315364
pub submission_url: String,
365+
/// https://tmc.mooc.fi/exercises/{exercise_id}/solution
316366
pub solution_url: Option<String>,
317367
pub submitted_at: String,
318368
pub processing_time: Option<u32>,
319369
pub reviewed: bool,
320370
pub requests_review: bool,
371+
/// https://tmc.mooc.fi/paste/{paste_code}
321372
pub paste_url: Option<String>,
322373
pub message_for_paste: Option<String>,
323374
pub missing_review_points: Vec<String>,
324375
pub test_cases: Option<Vec<TestCase>>,
325376
pub feedback_questions: Option<Vec<SubmissionFeedbackQuestion>>,
377+
/// /api/v8/core/submissions/{submission_id}/feedback
326378
pub feedback_answer_url: Option<String>,
327379
pub error: Option<String>,
328380
pub validations: Option<StyleValidationResult>,
@@ -338,7 +390,7 @@ pub enum SubmissionStatus {
338390
Hidden,
339391
}
340392

341-
/// Response to feedback.
393+
/// post /api/v8/core/submissions/{submission_id}/feedback
342394
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
343395
pub struct SubmissionFeedbackResponse {
344396
pub api_version: u32,
@@ -431,7 +483,7 @@ impl<'de> Visitor<'de> for SubmissionFeedbackKindVisitor {
431483
}
432484
}
433485

434-
/// Code review.
486+
/// get /api/v8/core/courses/{course_id}/reviews
435487
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
436488
pub struct Review {
437489
pub submission_id: u32,
@@ -442,19 +494,14 @@ pub struct Review {
442494
pub review_body: String,
443495
pub points: Vec<String>,
444496
pub points_not_awarded: Vec<String>,
497+
/// https://tmc.mooc.fi/submissions/{submission_id}/reviews
445498
pub url: String,
499+
/// /api/v8/core/courses/{course_id}/reviews/{review_id}
446500
pub update_url: String,
447501
pub created_at: DateTime<FixedOffset>,
448502
pub updated_at: DateTime<FixedOffset>,
449503
}
450504

451-
/// Updated exercises.
452-
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
453-
pub struct UpdateResult {
454-
pub created: Vec<Exercise>,
455-
pub updated: Vec<Exercise>,
456-
}
457-
458505
#[cfg(test)]
459506
#[allow(clippy::clippy::unwrap_used)]
460507
mod test {

0 commit comments

Comments
 (0)