-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
…onid Feat #71 GET /submissions/{submissionId} を実装する
- Loading branch information
Showing
5 changed files
with
195 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
use axum::{ | ||
extract::{Path, State}, | ||
response::IntoResponse, | ||
Json, | ||
}; | ||
use axum_extra::{headers::Cookie, TypedHeader}; | ||
use reqwest::StatusCode; | ||
use serde::Serialize; | ||
use sqlx::types::chrono; | ||
|
||
use super::Repository; | ||
|
||
#[derive(Debug, Serialize)] | ||
#[serde(rename_all = "camelCase")] | ||
struct SubmissionResponse { | ||
id: String, | ||
user_id: i32, | ||
user_name: String, | ||
problem_id: i32, | ||
submitted_at: chrono::DateTime<chrono::Utc>, | ||
language_id: i32, | ||
total_score: i64, | ||
max_time: i32, | ||
max_memory: i32, | ||
code_length: i32, | ||
overall_judge_status: String, | ||
judge_results: Vec<TestcaseResponse>, | ||
} | ||
|
||
#[derive(Debug, Serialize)] | ||
#[serde(rename_all = "camelCase")] | ||
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<Repository>, | ||
TypedHeader(cookie): TypedHeader<Cookie>, | ||
Path(path): Path<i64>, | ||
) -> anyhow::Result<impl IntoResponse, StatusCode> { | ||
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 { | ||
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 | ||
.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)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
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<chrono::Utc>, | ||
pub updated_at: chrono::DateTime<chrono::Utc>, | ||
} | ||
|
||
impl Repository { | ||
pub async fn get_normal_problem_by_id( | ||
&self, | ||
id: i32, | ||
) -> anyhow::Result<Option<NormalProblems>> { | ||
let problem = | ||
sqlx::query_as::<_, NormalProblems>("SELECT * FROM normal_problems WHERE id = ?") | ||
.bind(id) | ||
.fetch_optional(&self.pool) | ||
.await?; | ||
|
||
Ok(problem) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
use sqlx::{types::chrono, FromRow}; | ||
|
||
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<chrono::Utc>, | ||
} | ||
|
||
#[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<Option<Submission>> { | ||
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<Vec<Testcase>> { | ||
let testcases = | ||
sqlx::query_as::<_, Testcase>("SELECT * FROM testcases WHERE submission_id = ?") | ||
.bind(submission_id) | ||
.fetch_all(&self.pool) | ||
.await?; | ||
|
||
Ok(testcases) | ||
} | ||
} |