From 3ee8094e4be72628b6dca3ecede0cb1e54572a0e Mon Sep 17 00:00:00 2001 From: kavos Date: Fri, 10 Jan 2025 16:49:10 +0900 Subject: [PATCH 1/4] impl: get submission --- src/handler.rs | 5 +++ src/handler/submissions.rs | 75 +++++++++++++++++++++++++++++++++++ src/repository.rs | 1 + src/repository/submissions.rs | 49 +++++++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 src/handler/submissions.rs create mode 100644 src/repository/submissions.rs diff --git a/src/handler.rs b/src/handler.rs index 7ff9f7c..55db024 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -7,6 +7,7 @@ use super::Repository; mod authentication; mod users; +mod submissions; pub fn make_router(app_state: Repository) -> Router { let authentication_router = Router::new() @@ -26,8 +27,12 @@ pub fn make_router(app_state: Repository) -> Router { .route("/me/password", put(users::put_me_password)) .route("/:userId", get(users::get_user)); + let submissions_router = Router::new() + .route("/:submissionId", get(submissions::get_submission)); + Router::new() .nest("/", authentication_router) .nest("/users", users_router) + .nest("/submissions", submissions_router) .with_state(app_state) } diff --git a/src/handler/submissions.rs b/src/handler/submissions.rs new file mode 100644 index 0000000..30d3c39 --- /dev/null +++ b/src/handler/submissions.rs @@ -0,0 +1,75 @@ +use axum::{extract::{Path, State}, response::IntoResponse, Json}; +use reqwest::StatusCode; +use serde::Serialize; +use sqlx::types::chrono; + +use super::Repository; + +#[derive(Debug, Serialize)] +struct SubmissionResponse { + id: String, + user_id: i32, + user_name: String, + problem_id: i32, + submitted_at: chrono::DateTime, + language_id: i32, + total_score: i64, + max_time: i32, + max_memory: i32, + code_length: i32, + overall_judge_status: String, + judge_results: Vec, +} + +#[derive(Debug, Serialize)] +struct TestcaseResponse { + testcase_id: i32, + testcase_name: String, + judge_status: String, + score: i64, + time: i32, + memory: i32, +} + +pub async fn get_submission( + State(state): State, + Path(path): Path, +) -> anyhow::Result { + let submission = state + .get_submission_by_id(path) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? + .ok_or(StatusCode::NOT_FOUND)?; + + let testcases = state + .get_testcases_by_submission_id(submission.id) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + let response = SubmissionResponse { + id: submission.id.to_string(), + user_id: submission.user_id, + user_name: submission.user_name, + problem_id: submission.problem_id, + submitted_at: submission.submitted_at, + language_id: submission.language_id, + total_score: submission.total_score, + max_time: submission.max_time, + max_memory: submission.max_memory, + code_length: submission.source.len() as i32, + overall_judge_status: submission.judge_status, + judge_results: testcases + .into_iter() + .map(|testcase| TestcaseResponse { + testcase_id: testcase.testcase_id, + testcase_name: testcase.testcase_name, + judge_status: testcase.judge_status, + score: testcase.score, + time: testcase.time, + memory: testcase.memory, + }) + .collect(), + }; + + Ok(Json(response)) +} \ No newline at end of file diff --git a/src/repository.rs b/src/repository.rs index 9f515ed..a65ce8a 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -7,6 +7,7 @@ mod jwt; mod user_password; pub mod users; mod users_session; +pub mod submissions; impl Repository { pub async fn connect() -> anyhow::Result { diff --git a/src/repository/submissions.rs b/src/repository/submissions.rs new file mode 100644 index 0000000..b3333b6 --- /dev/null +++ b/src/repository/submissions.rs @@ -0,0 +1,49 @@ +use sqlx::{FromRow, types::chrono}; + +use super::Repository; + +#[derive(FromRow)] +pub struct Submission { + pub id: i32, + pub problem_id: i32, + pub user_id: i32, + pub user_name: String, + pub language_id: i32, + pub source: String, + pub judge_status: String, + pub total_score: i64, + pub max_time: i32, + pub max_memory: i32, + pub submitted_at: chrono::DateTime, +} + +#[derive(FromRow)] +pub struct Testcase { + pub submission_id: i32, + pub testcase_id: i32, + pub testcase_name: String, + pub judge_status: String, + pub score: i64, + pub time: i32, + pub memory: i32, +} + +impl Repository { + pub async fn get_submission_by_id(&self, id: i64) -> anyhow::Result> { + let submission = sqlx::query_as::<_, Submission>("SELECT * FROM submissions WHERE id = ?") + .bind(id) + .fetch_optional(&self.pool) + .await?; + + Ok(submission) + } + + pub async fn get_testcases_by_submission_id(&self, submission_id: i32) -> anyhow::Result> { + let testcases = sqlx::query_as::<_, Testcase>("SELECT * FROM testcases WHERE submission_id = ?") + .bind(submission_id) + .fetch_all(&self.pool) + .await?; + + Ok(testcases) + } +} \ No newline at end of file From 938ba068288d3c18847f05165b034d2417e2c703 Mon Sep 17 00:00:00 2001 From: kavos Date: Fri, 10 Jan 2025 17:16:36 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E5=95=8F=E9=A1=8C=E3=81=8C=E5=85=AC?= =?UTF-8?q?=E9=96=8B=E3=81=A7=E3=81=AA=E3=81=84=E3=81=8B=E3=81=A4=E4=BD=9C?= =?UTF-8?q?=E5=95=8F=E8=80=85=E3=81=A7=E3=81=AA=E3=81=84=E3=81=A8=E3=81=8D?= =?UTF-8?q?=E3=81=AB404?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/handler/submissions.rs | 20 ++++++++++++++++++++ src/repository.rs | 3 ++- src/repository/normal_problems.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/repository/normal_problems.rs diff --git a/src/handler/submissions.rs b/src/handler/submissions.rs index 30d3c39..3179aca 100644 --- a/src/handler/submissions.rs +++ b/src/handler/submissions.rs @@ -1,4 +1,5 @@ use axum::{extract::{Path, State}, response::IntoResponse, Json}; +use axum_extra::{headers::Cookie, TypedHeader}; use reqwest::StatusCode; use serde::Serialize; use sqlx::types::chrono; @@ -33,14 +34,33 @@ struct TestcaseResponse { pub async fn get_submission( State(state): State, + TypedHeader(cookie): TypedHeader, Path(path): Path, ) -> anyhow::Result { + let session_id = cookie.get("session_id").ok_or(StatusCode::UNAUTHORIZED)?; + + let display_id = state + .get_display_id_by_session_id(session_id) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? + .ok_or(StatusCode::UNAUTHORIZED)?; + let submission = state .get_submission_by_id(path) .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? .ok_or(StatusCode::NOT_FOUND)?; + let problem = state + .get_normal_problem_by_id(submission.problem_id) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? + .ok_or(StatusCode::NOT_FOUND)?; + + if !problem.is_public && display_id != problem.author_id { + return Err(StatusCode::NOT_FOUND) + } + let testcases = state .get_testcases_by_submission_id(submission.id) .await diff --git a/src/repository.rs b/src/repository.rs index a65ce8a..b09b417 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -7,7 +7,8 @@ mod jwt; mod user_password; pub mod users; mod users_session; -pub mod submissions; +mod submissions; +mod normal_problems; impl Repository { pub async fn connect() -> anyhow::Result { diff --git a/src/repository/normal_problems.rs b/src/repository/normal_problems.rs new file mode 100644 index 0000000..33602bd --- /dev/null +++ b/src/repository/normal_problems.rs @@ -0,0 +1,28 @@ +use super::Repository; +use sqlx::types::chrono; + +#[derive(sqlx::FromRow)] +pub struct NormalProblems { + pub id: i32, + pub author_id: i64, + pub title: String, + pub statement: String, + pub time_limit: i32, + pub memory_limit: i32, + pub difficulty: i32, + pub is_public: bool, + pub judgecode_path: String, + pub created_at: chrono::DateTime, + pub updated_at: chrono::DateTime, +} + +impl Repository { + pub async fn get_normal_problem_by_id(&self, id: i32) -> anyhow::Result> { + let problem = sqlx::query_as::<_, NormalProblems>("SELECT * FROM normal_problems WHERE id = ?") + .bind(id) + .fetch_optional(&self.pool) + .await?; + + Ok(problem) + } +} \ No newline at end of file From b8aaa7a90c6fdf46280192f032f31afc60f15b77 Mon Sep 17 00:00:00 2001 From: kavos Date: Fri, 10 Jan 2025 17:29:41 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=E5=85=AC=E9=96=8B=E6=99=82=E3=81=AB?= =?UTF-8?q?=E3=83=AD=E3=82=B0=E3=82=A4=E3=83=B3=E3=81=97=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=AA=E3=81=8F=E3=81=A6=E3=82=82=E8=A6=8B=E3=82=89=E3=82=8C?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/handler/submissions.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/handler/submissions.rs b/src/handler/submissions.rs index 3179aca..ccb3e32 100644 --- a/src/handler/submissions.rs +++ b/src/handler/submissions.rs @@ -7,6 +7,7 @@ use sqlx::types::chrono; use super::Repository; #[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] struct SubmissionResponse { id: String, user_id: i32, @@ -23,6 +24,7 @@ struct SubmissionResponse { } #[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] struct TestcaseResponse { testcase_id: i32, testcase_name: String, @@ -37,13 +39,6 @@ pub async fn get_submission( TypedHeader(cookie): TypedHeader, Path(path): Path, ) -> anyhow::Result { - let session_id = cookie.get("session_id").ok_or(StatusCode::UNAUTHORIZED)?; - - let display_id = state - .get_display_id_by_session_id(session_id) - .await - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? - .ok_or(StatusCode::UNAUTHORIZED)?; let submission = state .get_submission_by_id(path) @@ -57,8 +52,18 @@ pub async fn get_submission( .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? .ok_or(StatusCode::NOT_FOUND)?; - if !problem.is_public && display_id != problem.author_id { - return Err(StatusCode::NOT_FOUND) + if !problem.is_public { + let session_id = cookie.get("session_id").ok_or(StatusCode::NOT_FOUND)?; + + let display_id = state + .get_display_id_by_session_id(session_id) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? + .ok_or(StatusCode::NOT_FOUND)?; + + if display_id != problem.author_id { + return Err(StatusCode::NOT_FOUND) + } } let testcases = state From 82216f3315b323ee1983b84b5fa7ddc97690648c Mon Sep 17 00:00:00 2001 From: kavos Date: Fri, 10 Jan 2025 17:31:28 +0900 Subject: [PATCH 4/4] fmt --- src/handler.rs | 6 +++--- src/handler/submissions.rs | 11 +++++++---- src/repository.rs | 4 ++-- src/repository/normal_problems.rs | 16 ++++++++++------ src/repository/submissions.rs | 18 +++++++++++------- 5 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/handler.rs b/src/handler.rs index 55db024..7a97c8e 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -6,8 +6,8 @@ use axum::{ use super::Repository; mod authentication; -mod users; mod submissions; +mod users; pub fn make_router(app_state: Repository) -> Router { let authentication_router = Router::new() @@ -27,8 +27,8 @@ pub fn make_router(app_state: Repository) -> Router { .route("/me/password", put(users::put_me_password)) .route("/:userId", get(users::get_user)); - let submissions_router = Router::new() - .route("/:submissionId", get(submissions::get_submission)); + let submissions_router = + Router::new().route("/:submissionId", get(submissions::get_submission)); Router::new() .nest("/", authentication_router) diff --git a/src/handler/submissions.rs b/src/handler/submissions.rs index ccb3e32..0300f7f 100644 --- a/src/handler/submissions.rs +++ b/src/handler/submissions.rs @@ -1,4 +1,8 @@ -use axum::{extract::{Path, State}, response::IntoResponse, Json}; +use axum::{ + extract::{Path, State}, + response::IntoResponse, + Json, +}; use axum_extra::{headers::Cookie, TypedHeader}; use reqwest::StatusCode; use serde::Serialize; @@ -39,7 +43,6 @@ pub async fn get_submission( TypedHeader(cookie): TypedHeader, Path(path): Path, ) -> anyhow::Result { - let submission = state .get_submission_by_id(path) .await @@ -62,7 +65,7 @@ pub async fn get_submission( .ok_or(StatusCode::NOT_FOUND)?; if display_id != problem.author_id { - return Err(StatusCode::NOT_FOUND) + return Err(StatusCode::NOT_FOUND); } } @@ -97,4 +100,4 @@ pub async fn get_submission( }; Ok(Json(response)) -} \ No newline at end of file +} diff --git a/src/repository.rs b/src/repository.rs index b09b417..2de1da8 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -4,11 +4,11 @@ use sqlx::mysql::{MySqlConnectOptions, MySqlPoolOptions}; use super::Repository; mod jwt; +mod normal_problems; +mod submissions; mod user_password; pub mod users; mod users_session; -mod submissions; -mod normal_problems; impl Repository { pub async fn connect() -> anyhow::Result { diff --git a/src/repository/normal_problems.rs b/src/repository/normal_problems.rs index 33602bd..4c2175d 100644 --- a/src/repository/normal_problems.rs +++ b/src/repository/normal_problems.rs @@ -17,12 +17,16 @@ pub struct NormalProblems { } impl Repository { - pub async fn get_normal_problem_by_id(&self, id: i32) -> anyhow::Result> { - let problem = sqlx::query_as::<_, NormalProblems>("SELECT * FROM normal_problems WHERE id = ?") - .bind(id) - .fetch_optional(&self.pool) - .await?; + pub async fn get_normal_problem_by_id( + &self, + id: i32, + ) -> anyhow::Result> { + let problem = + sqlx::query_as::<_, NormalProblems>("SELECT * FROM normal_problems WHERE id = ?") + .bind(id) + .fetch_optional(&self.pool) + .await?; Ok(problem) } -} \ No newline at end of file +} diff --git a/src/repository/submissions.rs b/src/repository/submissions.rs index b3333b6..d63eafb 100644 --- a/src/repository/submissions.rs +++ b/src/repository/submissions.rs @@ -1,4 +1,4 @@ -use sqlx::{FromRow, types::chrono}; +use sqlx::{types::chrono, FromRow}; use super::Repository; @@ -38,12 +38,16 @@ impl Repository { Ok(submission) } - pub async fn get_testcases_by_submission_id(&self, submission_id: i32) -> anyhow::Result> { - let testcases = sqlx::query_as::<_, Testcase>("SELECT * FROM testcases WHERE submission_id = ?") - .bind(submission_id) - .fetch_all(&self.pool) - .await?; + pub async fn get_testcases_by_submission_id( + &self, + submission_id: i32, + ) -> anyhow::Result> { + let testcases = + sqlx::query_as::<_, Testcase>("SELECT * FROM testcases WHERE submission_id = ?") + .bind(submission_id) + .fetch_all(&self.pool) + .await?; Ok(testcases) } -} \ No newline at end of file +}