Skip to content

Commit

Permalink
wip: tags in challenge
Browse files Browse the repository at this point in the history
  • Loading branch information
ElaBosak233 committed Jan 27, 2025
1 parent e6cda36 commit a834850
Show file tree
Hide file tree
Showing 9 changed files with 326 additions and 256 deletions.
57 changes: 0 additions & 57 deletions crates/db/src/transfer/challenge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,63 +75,6 @@ impl Challenge {
}
}

pub async fn find(
id: Option<uuid::Uuid>, title: Option<String>, category: Option<i32>, is_public: Option<bool>,
is_dynamic: Option<bool>, sorts: Option<String>, page: Option<u64>, size: Option<u64>,
) -> Result<(Vec<Challenge>, u64), DbErr> {
let mut sql = entity::challenge::Entity::find();

if let Some(id) = id {
sql = sql.filter(entity::challenge::Column::Id.eq(id));
}

if let Some(title) = title {
sql = sql.filter(entity::challenge::Column::Title.contains(title));
}

if let Some(category) = category {
sql = sql.filter(entity::challenge::Column::Category.eq(category));
}

if let Some(is_public) = is_public {
sql = sql.filter(entity::challenge::Column::IsPublic.eq(is_public));
}

if let Some(is_dynamic) = is_dynamic {
sql = sql.filter(entity::challenge::Column::IsDynamic.eq(is_dynamic));
}

sql = sql.filter(entity::challenge::Column::DeletedAt.is_null());

let total = sql.clone().count(get_db()).await?;

if let Some(sorts) = sorts {
let sorts = sorts.split(",").collect::<Vec<&str>>();
for sort in sorts {
let col =
match crate::entity::challenge::Column::from_str(sort.replace("-", "").as_str()) {
Ok(col) => col,
Err(_) => continue,
};
if sort.starts_with("-") {
sql = sql.order_by(col, Order::Desc);
} else {
sql = sql.order_by(col, Order::Asc);
}
}
}

if let (Some(page), Some(size)) = (page, size) {
let offset = (page - 1) * size;
sql = sql.offset(offset).limit(size);
}

let models = sql.all(get_db()).await?;
let challenges = models.into_iter().map(Challenge::from).collect();

Ok((challenges, total))
}

pub async fn find_by_ids(ids: Vec<i64>) -> Result<Vec<Challenge>, DbErr> {
let models = entity::challenge::Entity::find()
.filter(entity::challenge::Column::Id.is_in(ids))
Expand Down
45 changes: 0 additions & 45 deletions crates/db/src/transfer/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,48 +64,3 @@ impl From<Game> for entity::game::Model {
}
}
}

pub async fn find(
id: Option<i64>, title: Option<String>, is_enabled: Option<bool>, sorts: Option<String>,
page: Option<u64>, size: Option<u64>,
) -> Result<(Vec<entity::game::Model>, u64), DbErr> {
let mut sql = entity::game::Entity::find();

if let Some(id) = id {
sql = sql.filter(entity::game::Column::Id.eq(id));
}

if let Some(title) = title {
sql = sql.filter(entity::game::Column::Title.contains(title));
}

if let Some(is_enabled) = is_enabled {
sql = sql.filter(entity::game::Column::IsEnabled.eq(is_enabled));
}

if let Some(sorts) = sorts {
let sorts = sorts.split(",").collect::<Vec<&str>>();
for sort in sorts {
let col = match crate::entity::game::Column::from_str(sort.replace("-", "").as_str()) {
Ok(col) => col,
Err(_) => continue,
};
if sort.starts_with("-") {
sql = sql.order_by(col, Order::Desc);
} else {
sql = sql.order_by(col, Order::Asc);
}
}
}

let total = sql.clone().count(get_db()).await?;

if let (Some(page), Some(size)) = (page, size) {
let offset = (page - 1) * size;
sql = sql.offset(offset).limit(size);
}

let games = sql.all(get_db()).await?;

Ok((games, total))
}
15 changes: 12 additions & 3 deletions crates/db/src/transfer/game_challenge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ impl From<entity::game_challenge::Model> for GameChallenge {
}
}

async fn preload(models: Vec<entity::game_challenge::Model>) -> Result<Vec<GameChallenge>, DbErr> {
pub async fn preload(
models: Vec<entity::game_challenge::Model>,
) -> Result<Vec<GameChallenge>, DbErr> {
let challenges = models
.load_one(entity::challenge::Entity, get_db())
.await?
Expand All @@ -60,9 +62,12 @@ async fn preload(models: Vec<entity::game_challenge::Model>) -> Result<Vec<GameC
}

pub async fn find(
game_id: Option<i64>, challenge_id: Option<i64>, is_enabled: Option<bool>,
game_id: Option<i64>, challenge_id: Option<i64>, category: Option<i32>,
is_enabled: Option<bool>,
) -> Result<(Vec<GameChallenge>, u64), DbErr> {
let mut sql = entity::game_challenge::Entity::find();
let mut sql = entity::game_challenge::Entity::find()
.inner_join(entity::challenge::Entity)
.inner_join(entity::game::Entity);

if let Some(game_id) = game_id {
sql = sql.filter(entity::game_challenge::Column::GameId.eq(game_id));
Expand All @@ -76,6 +81,10 @@ pub async fn find(
sql = sql.filter(entity::game_challenge::Column::IsEnabled.eq(is_enabled));
}

if let Some(category) = category {
sql = sql.filter(entity::challenge::Column::Category.eq(category));
}

let total = sql.clone().count(get_db()).await?;

let models = sql.all(get_db()).await?;
Expand Down
2 changes: 2 additions & 0 deletions crates/db/src/transfer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Transfer module is used to store structures with additional fields and
//! preload functions.
pub mod challenge;
pub mod game;
pub mod game_challenge;
Expand Down
50 changes: 1 addition & 49 deletions crates/db/src/transfer/submission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl From<Submission> for entity::submission::Model {
}
}

async fn preload(mut submissions: Vec<Submission>) -> Result<Vec<Submission>, DbErr> {
pub async fn preload(mut submissions: Vec<Submission>) -> Result<Vec<Submission>, DbErr> {
let models = submissions
.clone()
.into_iter()
Expand Down Expand Up @@ -121,54 +121,6 @@ async fn preload(mut submissions: Vec<Submission>) -> Result<Vec<Submission>, Db
Ok(submissions)
}

pub async fn find(
id: Option<i64>, user_id: Option<i64>, team_id: Option<i64>, game_id: Option<i64>,
challenge_id: Option<i64>, status: Option<Status>, page: Option<u64>, size: Option<u64>,
) -> Result<(Vec<Submission>, u64), DbErr> {
let mut sql = entity::submission::Entity::find();

if let Some(id) = id {
sql = sql.filter(entity::submission::Column::Id.eq(id));
}

if let Some(user_id) = user_id {
sql = sql.filter(entity::submission::Column::UserId.eq(user_id));
}

if let Some(team_id) = team_id {
sql = sql.filter(entity::submission::Column::TeamId.eq(team_id));
}

if let Some(game_id) = game_id {
sql = sql.filter(entity::submission::Column::GameId.eq(game_id));
}

if let Some(challenge_id) = challenge_id {
sql = sql.filter(entity::submission::Column::ChallengeId.eq(challenge_id));
}

if let Some(status) = status {
sql = sql.filter(entity::submission::Column::Status.eq(status));
}

let total = sql.clone().count(get_db()).await?;

if let (Some(page), Some(size)) = (page, size) {
let offset = (page - 1) * size;
sql = sql.offset(offset).limit(size);
}

let submissions = sql.all(get_db()).await?;
let mut submissions = submissions
.into_iter()
.map(Submission::from)
.collect::<Vec<Submission>>();

submissions = preload(submissions).await?;

Ok((submissions, total))
}

pub async fn get_by_challenge_ids(challenge_ids: Vec<Uuid>) -> Result<Vec<Submission>, DbErr> {
let submissions = entity::submission::Entity::find()
.filter(entity::submission::Column::ChallengeId.is_in(challenge_ids))
Expand Down
107 changes: 86 additions & 21 deletions crates/web/src/router/api/challenge/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::{collections::HashMap, str::FromStr};

use axum::{
Router,
Expand All @@ -10,11 +10,14 @@ use axum::{
use cds_db::{
entity::{submission::Status, user::Group},
get_db,
transfer::Challenge,
};
use sea_orm::{
ActiveModelTrait,
ActiveValue::{NotSet, Set, Unchanged},
ColumnTrait, EntityTrait, QueryFilter,
ColumnTrait, EntityName, EntityTrait, Iden, IdenStatic, Order, PaginatorTrait, QueryFilter,
QueryOrder, QuerySelect,
sea_query::Expr,
};
use serde::{Deserialize, Serialize};
use serde_json::json;
Expand Down Expand Up @@ -51,7 +54,7 @@ pub struct GetRequest {
pub id: Option<uuid::Uuid>,
pub title: Option<String>,
pub category: Option<i32>,
pub tags: Option<Vec<String>>,
pub tags: Option<String>,
pub is_public: Option<bool>,
pub is_dynamic: Option<bool>,
pub is_detailed: Option<bool>,
Expand All @@ -62,23 +65,82 @@ pub struct GetRequest {

pub async fn get(
Extension(ext): Extension<Ext>, Query(params): Query<GetRequest>,
) -> Result<WebResponse<Vec<cds_db::transfer::Challenge>>, WebError> {
) -> Result<WebResponse<Vec<Challenge>>, WebError> {
let operator = ext.operator.ok_or(WebError::Unauthorized(json!("")))?;
if operator.group != Group::Admin && params.is_detailed.unwrap_or(false) {
return Err(WebError::Forbidden(json!("")));
}

let (mut challenges, total) = cds_db::transfer::challenge::find(
params.id,
params.title,
params.category,
params.is_public,
params.is_dynamic,
params.sorts,
params.page,
params.size,
)
.await?;
let mut sql = cds_db::entity::challenge::Entity::find();

if let Some(id) = params.id {
sql = sql.filter(cds_db::entity::challenge::Column::Id.eq(id));
}

if let Some(title) = params.title {
sql = sql.filter(cds_db::entity::challenge::Column::Title.contains(title));
}

if let Some(category) = params.category {
sql = sql.filter(cds_db::entity::challenge::Column::Category.eq(category));
}

if let Some(tags) = params.tags {
let tags = tags
.split(",")
.map(|s| s.to_owned())
.collect::<Vec<String>>();

sql = sql.filter(Expr::cust_with_expr(
format!(
"\"{}\".\"{}\" @> $1::varchar[]",
cds_db::entity::challenge::Entity.table_name(),
cds_db::entity::challenge::Column::Tags.to_string()
)
.as_str(),
tags,
))
}

if let Some(is_public) = params.is_public {
sql = sql.filter(cds_db::entity::challenge::Column::IsPublic.eq(is_public));
}

if let Some(is_dynamic) = params.is_dynamic {
sql = sql.filter(cds_db::entity::challenge::Column::IsDynamic.eq(is_dynamic));
}

sql = sql.filter(cds_db::entity::challenge::Column::DeletedAt.is_null());

let total = sql.clone().count(get_db()).await?;

if let Some(sorts) = params.sorts {
let sorts = sorts.split(",").collect::<Vec<&str>>();
for sort in sorts {
let col =
match cds_db::entity::challenge::Column::from_str(sort.replace("-", "").as_str()) {
Ok(col) => col,
Err(_) => continue,
};
if sort.starts_with("-") {
sql = sql.order_by(col, Order::Desc);
} else {
sql = sql.order_by(col, Order::Asc);
}
}
}

if let (Some(page), Some(size)) = (params.page, params.size) {
let offset = (page - 1) * size;
sql = sql.offset(offset).limit(size);
}

let mut challenges = sql
.all(get_db())
.await?
.into_iter()
.map(Challenge::from)
.collect::<Vec<Challenge>>();

for challenge in challenges.iter_mut() {
let is_detailed = params.is_detailed.unwrap_or(false);
Expand Down Expand Up @@ -171,12 +233,15 @@ pub async fn get_status(
}

if let Some(game_id) = body.game_id {
let (game_challenges, _) =
cds_db::transfer::game_challenge::find(Some(game_id), None, None).await?;
let game_challenges = cds_db::entity::game_challenge::Entity::find()
.filter(cds_db::entity::game_challenge::Column::GameId.eq(game_id))
.all(get_db())
.await?;

for game_challenge in game_challenges {
let status_response = result.get_mut(&game_challenge.challenge_id).unwrap();
status_response.pts = game_challenge.pts;
if let Some(status_response) = result.get_mut(&game_challenge.challenge_id) {
status_response.pts = game_challenge.pts;
}
}
}

Expand All @@ -203,7 +268,7 @@ pub struct CreateRequest {

pub async fn create(
Extension(ext): Extension<Ext>, Json(body): Json<CreateRequest>,
) -> Result<WebResponse<cds_db::transfer::Challenge>, WebError> {
) -> Result<WebResponse<Challenge>, WebError> {
let operator = ext.operator.ok_or(WebError::Unauthorized(json!("")))?;
if operator.group != Group::Admin {
return Err(WebError::Forbidden(json!("")));
Expand Down Expand Up @@ -249,7 +314,7 @@ pub struct UpdateRequest {
pub async fn update(
Extension(ext): Extension<Ext>, Path(id): Path<uuid::Uuid>,
VJson(mut body): VJson<UpdateRequest>,
) -> Result<WebResponse<cds_db::transfer::Challenge>, WebError> {
) -> Result<WebResponse<Challenge>, WebError> {
let operator = ext.operator.ok_or(WebError::Unauthorized(json!("")))?;
if operator.group != Group::Admin {
return Err(WebError::Forbidden(json!("")));
Expand Down
Loading

0 comments on commit a834850

Please sign in to comment.