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

feat: support category #17

Merged
merged 10 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
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.

4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ pub mod utils {
pub mod organization;
pub mod problem;
pub mod session;
pub mod category;
}

pub mod routes {
pub mod account;
pub mod category;
pub mod index;
pub mod problem;
pub mod organization;
pub mod problem;
}

pub mod cors;
Expand Down
20 changes: 20 additions & 0 deletions src/models/category.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::models::UserRecordId;
use serde::{Deserialize, Serialize};
use surrealdb::sql::Thing;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Category {
pub id: Option<Thing>,
pub owner: Thing,
pub name: String,

pub created_at: chrono::NaiveDateTime,
pub updated_at: chrono::NaiveDateTime,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct CreateCategory {
pub name: String,
pub owner: UserRecordId,
}
1 change: 1 addition & 0 deletions src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ pub mod organization;
pub mod problem;
pub mod response;
pub mod shared;
pub mod category;

pub use shared::*;
111 changes: 111 additions & 0 deletions src/routes/category.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use crate::{
models::{
category::{Category, CreateCategory},
error::Error,
response::{Empty, Response},
UserRecordId,
},
utils::{category, session},
Result,
};
use rocket::{post, serde::json::Json, tokio::fs::remove_dir_all, State};
use serde::{Deserialize, Serialize};
use std::path::Path;
use surrealdb::{engine::remote::ws::Client, Surreal};

#[derive(Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct CategoryData<'r> {
pub id: &'r str,
pub token: &'r str,

pub data: CreateCategory,
}

#[derive(Serialize, Deserialize)]
pub struct CreateCatResponse {
pub id: String,
}

#[post("/create", data = "<category>")]
pub async fn create(
db: &State<Surreal<Client>>,
category: Json<CategoryData<'_>>,
) -> Result<CreateCatResponse> {
if !session::verify(db, category.id, category.token).await {
return Err(Error::Unauthorized(Json(
"Failed to grant permission".into(),
)));
}

let data = category::create(db, category.into_inner().data)
.await
.map_err(|e| Error::ServerError(Json(e.to_string().into())))?
.ok_or(Error::ServerError(Json("Failed to create category".into())))?;

Ok(Json(Response {
success: true,
message: "Category created successfully".into(),
data: Some(CreateCatResponse {
id: data.id.unwrap().id.to_string(),
}),
}))
}

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

category::delete(db, id)
.await
.map_err(|e| Error::ServerError(Json(e.to_string().into())))?;

remove_dir_all(Path::new("content/").join(id))
.await
.map_err(|e| Error::ServerError(Json(e.to_string().into())))?;

Ok(Response {
success: true,
message: "Category deleted successfully".into(),
data: None,
}
.into())
}

#[derive(Serialize, Deserialize)]
pub struct ListCategories {
pub owner: UserRecordId,
}

#[post("/list", data = "<data>")]
pub async fn list(
db: &State<Surreal<Client>>,
data: Json<ListCategories>,
) -> Result<Vec<Category>> {
let result = category::list(db, data.into_inner().owner.into())
.await
.map_err(|e| Error::ServerError(Json(e.to_string().into())))?;

if result.is_empty() {
return Err(Error::NotFound(Json("Category not found".into())));
}

Ok(Json(Response {
success: true,
message: "Category found successfully".to_string(),
data: Some(result),
}))
}

pub fn routes() -> Vec<rocket::Route> {
use rocket::routes;
routes![create, delete, list]
}
2 changes: 2 additions & 0 deletions src/routes/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{cors::CORS, routes::account};
use anyhow::Result;
use rocket::fs::NamedFile;
use surrealdb::{engine::remote::ws::Ws, opt::auth::Root, Surreal};
use super::category;
use super::problem;
use super::organization;
#[get("/")]
Expand Down Expand Up @@ -37,6 +38,7 @@ pub async fn rocket() -> rocket::Rocket<rocket::Build> {
.mount("/account", account::routes())
.mount("/problem", problem::routes())
.mount("/org", organization::routes())
.mount("/category", category::routes())
.manage(db)

}
29 changes: 29 additions & 0 deletions src/utils/category.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use anyhow::{Ok, Result};
use surrealdb::{engine::remote::ws::Client, sql::Thing, Surreal};

use crate::models::category::{Category, CreateCategory};

pub async fn create(db: &Surreal<Client>, data: CreateCategory) -> Result<Option<Category>> {
Ok(db
.create("category")
.content(Category {
id: None,
name: data.name,
owner: data.owner.into(),
created_at: chrono::Local::now().naive_local(),
updated_at: chrono::Local::now().naive_local(),
})
.await?)
}

pub async fn delete(db: &Surreal<Client>, id: &str) -> Result<Option<Category>> {
Ok(db.delete(("category", id)).await?)
}

pub async fn list(db: &Surreal<Client>, owner: Thing) -> Result<Vec<Category>> {
Ok(db
.query("SELECT * FROM category WHERE owner = $owner")
.bind(("owner", owner))
.await?
.take(0)?)
}