From cade2f36abc58a807a8abcc75798ed9ba8e949ea Mon Sep 17 00:00:00 2001 From: K0nnyaku Date: Tue, 3 Dec 2024 21:39:21 +0800 Subject: [PATCH] feat: list submission by user or contest or user and contest --- Cargo.lock | 2 +- src/models/submission.rs | 1 + src/routes/submission.rs | 86 +++++++++++++++++++++++++++++++++++----- src/utils/submission.rs | 46 ++++++++++++++++++++- 4 files changed, 124 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 189ccb6..e2f5872 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,7 +71,7 @@ dependencies = [ [[package]] name = "algohub-server" -version = "0.1.8" +version = "0.1.9" dependencies = [ "anyhow", "chrono", diff --git a/src/models/submission.rs b/src/models/submission.rs index d931f62..1f7dbf3 100644 --- a/src/models/submission.rs +++ b/src/models/submission.rs @@ -20,6 +20,7 @@ pub struct Submission { pub status: Status, pub results: Vec, pub creator: Thing, + pub contest_id: Option, pub created_at: chrono::NaiveDateTime, pub updated_at: chrono::NaiveDateTime, diff --git a/src/routes/submission.rs b/src/routes/submission.rs index ee25efb..1bfe9b2 100644 --- a/src/routes/submission.rs +++ b/src/routes/submission.rs @@ -16,6 +16,7 @@ pub struct CreateSubmission { pub auth: OwnedCredentials, pub code: String, pub lang: Language, + pub contest_id: Option, } #[derive(Serialize, Deserialize)] @@ -34,12 +35,18 @@ pub async fn submit( } let data = data.into_inner(); - let submission = submission::create(db, &data.auth.id, id, data.code, data.lang) - .await - .map_err(|e| Error::ServerError(Json(e.to_string().into())))? - .ok_or(Error::ServerError(Json( - "Failed to submit, please try again later.".into(), - )))?; + let submission = submission::create( + db, + &data.auth.id, + id, + data.code, + data.lang, + data.contest_id.as_deref(), + ) + .await? + .ok_or(Error::ServerError(Json( + "Failed to submit, please try again later.".into(), + )))?; Ok(Json(Response { success: true, @@ -57,8 +64,7 @@ pub async fn get( _auth: Json>, ) -> Result { let submission = submission::get_by_id(db, id) - .await - .map_err(|e| Error::ServerError(Json(e.to_string().into())))? + .await? .ok_or(Error::NotFound(Json("Submission not found".into())))?; Ok(Json(Response { @@ -68,7 +74,69 @@ pub async fn get( })) } +#[post("/list/", data = "<_auth>")] +pub async fn list_by_user( + db: &State>, + id: &str, + _auth: Json>, +) -> Result> { + let submissions = submission::list_by_user(db, ("account", id).into()) + .await? + .ok_or(Error::NotFound(Json("Submission not found".into())))?; + + Ok(Json(Response { + success: true, + message: "submission fetched successfully".to_string(), + data: Some(submissions), + })) +} + +#[post("/list/", data = "<_auth>")] +pub async fn list_by_contest( + db: &State>, + id: &str, + _auth: Json>, +) -> Result> { + let submissions = submission::list_by_contest(db, ("contest", id).into()) + .await? + .ok_or(Error::NotFound(Json("Submission not found".into())))?; + + Ok(Json(Response { + success: true, + message: "submission fetched successfully".to_string(), + data: Some(submissions), + })) +} + +#[post("/list//", data = "<_auth>")] +pub async fn list_within_contest( + db: &State>, + contest_id: &str, + user_id: &str, + _auth: Json>, +) -> Result> { + let submissions = submission::list_within_contest( + db, + ("contest", contest_id).into(), + ("contest", user_id).into(), + ) + .await? + .ok_or(Error::NotFound(Json("Submission not found".into())))?; + + Ok(Json(Response { + success: true, + message: "submission fetched successfully".to_string(), + data: Some(submissions), + })) +} + pub fn routes() -> Vec { use rocket::routes; - routes![submit, get] + routes![ + submit, + get, + list_by_user, + list_by_contest, + list_within_contest + ] } diff --git a/src/utils/submission.rs b/src/utils/submission.rs index 90ed59c..2effb8a 100644 --- a/src/utils/submission.rs +++ b/src/utils/submission.rs @@ -1,7 +1,7 @@ use crate::models::submission::Submission; use anyhow::Result; use eval_stack::compile::Language; -use surrealdb::{engine::remote::ws::Client, Surreal}; +use surrealdb::{engine::remote::ws::Client, sql::Thing, Surreal}; pub async fn create( db: &Surreal, @@ -9,6 +9,7 @@ pub async fn create( problem_id: &str, code: String, lang: Language, + contest_id: Option<&str>, ) -> Result> { Ok(db .create("submission") @@ -22,6 +23,12 @@ pub async fn create( creator: ("account", account_id).into(), results: vec![], + contest_id: (if let Some(contest_id) = contest_id { + Some(("contest", contest_id).into()) + } else { + None + }), + created_at: chrono::Local::now().naive_local(), updated_at: chrono::Local::now().naive_local(), }) @@ -31,3 +38,40 @@ pub async fn create( pub async fn get_by_id(db: &Surreal, id: &str) -> Result> { Ok(db.select(("submission", id)).await?) } + +pub async fn list_by_user(db: &Surreal, creator: Thing) -> Result>> { + Ok(db + .query("SELECT * FROM submission WHERE creator = $creator") + .bind(("creator", creator)) + .await? + .take(0)?) +} + +pub async fn list_by_contest( + db: &Surreal, + contest_id: Thing, +) -> Result>> { + Ok(db + .query("SELECT * FROM submission WHERE contest_id = $contest_id") + .bind(("contest_id", contest_id)) + .await? + .take(0)?) +} + +pub async fn list_within_contest( + db: &Surreal, + contest_id: Thing, + user_id: Thing, +) -> Result>> { + let submissions = list_by_contest(db, contest_id).await?; + + match submissions { + Some(submissions) => Ok(Some( + submissions + .into_iter() + .filter(|s| s.creator == user_id) + .collect(), + )), + None => Ok(None), + } +}