Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(index): fix index page #56

Merged
merged 7 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/contest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"algohub-server": patch:feat
---

Support create and list all contests.
5 changes: 5 additions & 0 deletions .changes/create-contest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"algohub-server": patch:feat
---

Support `ContestProblem` model to display submits and acceptations.
5 changes: 5 additions & 0 deletions .changes/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"algohub-server": patch:fix
---

Fixed index pages cannot be displayed correctly.
5 changes: 5 additions & 0 deletions .changes/rank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"algohub-server": patch:feat
---

Support enpoints for getting rank list.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@

# Node.js
/node_modules

# Assets
/dist
2 changes: 1 addition & 1 deletion Cargo.lock

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

9 changes: 9 additions & 0 deletions src/models/contest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,12 @@ pub struct ContestProblem {
pub submitted_count: u32,
pub accepted_count: u32,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ContestRank {
name: String,
problem_id: String,
accepted: bool,
wrongs: u32,
}
21 changes: 20 additions & 1 deletion src/routes/contest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use surrealdb::{engine::remote::ws::Client, sql::Thing, Surreal};

use crate::{
models::{
contest::{AddProblems, ContestProblem, CreateContest, UserContest},
contest::{AddProblems, ContestProblem, ContestRank, CreateContest, UserContest},
error::Error,
response::{Empty, Response},
Credentials, OwnedId,
Expand Down Expand Up @@ -119,6 +119,25 @@ pub async fn get(
}))
}

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

let rank = contest::rank(db, id).await?;

Ok(Json(Response {
success: true,
message: "Contest rank retrieved successfully".into(),
data: Some(rank),
}))
}

pub fn routes() -> Vec<rocket::Route> {
use rocket::routes;
routes![create, get, add_problems, list_problems, list_all]
Expand Down
9 changes: 7 additions & 2 deletions src/routes/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ use rocket::fs::NamedFile;
use surrealdb::engine::remote::ws::Client;
use surrealdb::{engine::remote::ws::Ws, opt::auth::Root, Surreal};

#[get("/")]
async fn index() -> Result<NamedFile, std::io::Error> {
NamedFile::open("dist/index.html").await
}

#[get("/<file..>", rank = 1)]
async fn index(file: PathBuf) -> Option<NamedFile> {
async fn files(file: PathBuf) -> Option<NamedFile> {
NamedFile::open(Path::new("dist/").join(file)).await.ok()
}

Expand All @@ -39,7 +44,7 @@ pub async fn init_db(db_addr: &str) -> Result<Surreal<Client>> {
pub async fn rocket(db: Surreal<Client>) -> rocket::Rocket<rocket::Build> {
rocket::build()
.attach(CORS)
.mount("/", routes![index])
.mount("/", routes![index, files])
.mount("/account", account::routes())
.mount("/asset", asset::routes())
.mount("/problem", problem::routes())
Expand Down
34 changes: 33 additions & 1 deletion src/utils/contest.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::Result;
use surrealdb::{engine::remote::ws::Client, sql::Thing, Surreal};

use crate::models::contest::{Contest, ContestData, ContestProblem};
use crate::models::contest::{Contest, ContestData, ContestProblem, ContestRank};

pub async fn create(
db: &Surreal<Client>,
Expand Down Expand Up @@ -106,3 +106,35 @@ pub async fn remove_problem(
.await?
.take(0)?)
}

const RANK_QUERY: &str = r#"
SELECT VALUE array::map((SELECT VALUE id FROM type::thing("contest", $id).problems), |$problem| {
LET $submissions = SELECT judge_result.status.type AS status, created_at
FROM submission WHERE problem.id == $problem AND $parent.id == creator ORDER BY created_at ASC;
LET $first_accepted = array::find_index($submissions, |$submission| {
RETURN $submission.status == "accepted"
});
RETURN IF $first_accepted {
RETURN {
name: $problem.title,
problem_id: record::id($problem),
accepted: true,
wrongs: count($submissions) - $first_accepted - 1,
}
} ELSE {
RETURN {
name: $problem.title,
problem_id: record::id($problem),
accepted: false,
wrongs: count($submissions),
}
}
}) FROM array::distinct(SELECT VALUE creator FROM submission)
"#;
pub async fn rank(db: &Surreal<Client>, id: &str) -> Result<Vec<ContestRank>> {
Ok(db
.query(RANK_QUERY)
.bind(("id", id.to_string()))
.await?
.take(0)?)
}
Loading