Skip to content

Commit

Permalink
feat(problem): optimize endpoints (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
fu050409 authored Dec 4, 2024
1 parent 0d8ed2b commit b27e575
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 65 deletions.
5 changes: 5 additions & 0 deletions .changes/problem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"algohub-server": patch:feat
---

Optimize endpoints for problem updates.
54 changes: 27 additions & 27 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ license = "AGPL-3.0-only"
[dependencies]
anyhow = "1.0.92"
chrono = { version = "0.4.38", features = ["serde"] }
eval-stack = { version = "0.2.0", features = ["serde"] }
eval-stack = { version = "0.3.1", default-features = false, features = [
"serde",
] }
rocket = { version = "0.5.1", features = ["json"] }
serde = { version = "1.0.214", features = ["derive"] }
surrealdb = "2.1.0"
surrealdb = "2.1.2"
uuid = { version = "1.11.0", features = ["v4"] }
1 change: 1 addition & 0 deletions src/models/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub struct CreateAsset<'a> {
#[derive(Serialize, Deserialize)]
pub struct UserContent {
pub id: String,
pub name: String,
}

pub struct AssetFile(pub(crate) NamedFile);
Expand Down
17 changes: 17 additions & 0 deletions src/models/problem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,21 @@ impl From<CreateProblem<'_>> for Problem {
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OwnedUserTestCase {
pub input: String,
pub output: String,
}

impl From<TestCase> for OwnedUserTestCase {
fn from(value: TestCase) -> Self {
OwnedUserTestCase {
input: value.input.id.to_string(),
output: value.output.id.to_string(),
}
}
}

#[derive(Debug, Deserialize, Serialize)]
pub struct UserProblem {
pub id: String,
Expand All @@ -129,6 +144,7 @@ pub struct UserProblem {

pub time_limit: u64,
pub memory_limit: u64,
pub test_cases: Vec<OwnedUserTestCase>,

pub creator: String,
pub owner: UserRecordId,
Expand All @@ -153,6 +169,7 @@ impl From<Problem> for UserProblem {
hint: value.hint,
time_limit: value.time_limit,
memory_limit: value.memory_limit,
test_cases: value.test_cases.into_iter().map(Into::into).collect(),
creator: value.creator.id.to_string(),
owner: value.owner.into(),
categories: value.categories,
Expand Down
3 changes: 2 additions & 1 deletion src/models/submission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ pub struct Submission {
pub problem: Thing,
pub code: String,
pub status: Status,
pub results: Vec<JudgeResult>,
pub judge_details: Vec<JudgeResult>,
pub judge_result: Option<JudgeResult>,
pub creator: Thing,
pub contest: Option<Thing>,

Expand Down
47 changes: 20 additions & 27 deletions src/routes/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ pub async fn upload(
data: Form<CreateAsset<'_>>,
) -> Result<UserContent> {
if !session::verify(db, data.auth.id, data.auth.token).await {
return Err(Error::Unauthorized(Json(
"Failed to grant access permission".into(),
)));
return Err(Error::Unauthorized(Json("Invalid credentials".into())));
}

let file_extension = data
Expand All @@ -41,9 +39,7 @@ pub async fn upload(
.join(data.auth.id);

if !user_path.exists() {
create_dir_all(&user_path)
.await
.map_err(|e| Error::ServerError(Json(e.to_string().into())))?;
create_dir_all(&user_path).await?;
}
let file_name = format!("{}.{}", uuid::Uuid::new_v4(), file_extension);
let file_path = user_path.join(&file_name);
Expand All @@ -61,22 +57,22 @@ pub async fn upload(
.await
.map_err(|e| Error::ServerError(Json(format!("Failed to save file: {}", e).into())))?;

let asset = asset::create(
db,
data.owner.clone(),
data.file
.name()
.unwrap_or(&uuid::Uuid::new_v4().to_string()),
file_path,
)
.await
.map_err(|e| Error::ServerError(Json(e.into())))?
.ok_or(Error::ServerError(Json("Failed to create asset".into())))?;
let asset_name = data
.file
.name()
.map(|name| name.to_string())
.unwrap_or(uuid::Uuid::new_v4().to_string());

let asset = asset::create(db, data.owner.clone(), &asset_name, file_path)
.await?
.ok_or(Error::ServerError(Json("Failed to create asset".into())))?;

Ok(Json(Response {
success: true,
message: "Content updated successfully".into(),
data: Some(UserContent {
id: asset.id.unwrap().id.to_string(),
name: asset_name,
}),
}))
}
Expand All @@ -88,26 +84,23 @@ pub async fn get(db: &State<Surreal<Client>>, id: &str) -> Option<AssetFile> {
Some(AssetFile(NamedFile::open(&asset.path).await.ok()?))
}

#[post("/delete/<id>", data = "<auth>")]
#[delete("/delete/<id>", data = "<auth>")]
pub async fn delete(
db: &State<Surreal<Client>>,
id: &str,
auth: Form<Credentials<'_>>,
auth: Json<Credentials<'_>>,
) -> Result<Empty> {
if !session::verify(db, auth.id, auth.token).await {
return Err(Error::Unauthorized(Json(
"Failed to grant access permission".into(),
)));
return Err(Error::Unauthorized(Json("Invalid credentials".into())));
}

let asset = asset::get_by_id(db, id)
.await
.map_err(Error::from)?
.await?
.ok_or(Error::NotFound(Json("Asset not found".into())))?;

rocket::tokio::fs::remove_file(&asset.path)
.await
.map_err(|e| Error::ServerError(Json(format!("Failed to delete file: {}", e).into())))?;
let _ = rocket::tokio::fs::remove_file(&asset.path).await;

asset::delete(db, id).await?;

Ok(Json(Response {
success: true,
Expand Down
26 changes: 25 additions & 1 deletion src/routes/problem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,30 @@ pub async fn list(
}))
}

#[post("/update/<id>", data = "<problem>")]
pub async fn update(
db: &State<Surreal<Client>>,
id: &str,
problem: Json<CreateProblem<'_>>,
) -> Result<Empty> {
if !session::verify(db, problem.id, problem.token).await {
return Err(Error::Unauthorized(Json("Invalid credentials".into())));
}

problem::update(db, id, problem.into_inner())
.await
.map_err(|e| Error::ServerError(Json(e.to_string().into())))?
.ok_or(Error::ServerError(Json(
"Failed to update problem, please try again later.".into(),
)))?;

Ok(Json(Response {
success: true,
message: "Problem updated successfully".to_string(),
data: None,
}))
}

#[delete("/delete/<id>", data = "<auth>")]
pub async fn delete(
db: &State<Surreal<Client>>,
Expand Down Expand Up @@ -177,5 +201,5 @@ pub async fn delete(

pub fn routes() -> Vec<rocket::Route> {
use rocket::routes;
routes![create, get, list, delete]
routes![create, get, update, list, delete]
}
Loading

0 comments on commit b27e575

Please sign in to comment.