Skip to content

Commit

Permalink
add the handler to fetch all sites for a specific category
Browse files Browse the repository at this point in the history
  • Loading branch information
huangcheng committed Nov 27, 2023
1 parent 0d3885f commit 8f17f52
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 9 deletions.
2 changes: 1 addition & 1 deletion migrations/20231127033035_site.up.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CREATE TABLE site
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
url VARCHAR(255) NOT NULL,
description VARCHAR(255) NOT NULL,
Expand Down
8 changes: 7 additions & 1 deletion src/bin/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,13 @@ async fn main() -> Result<(), rocket::Error> {
.mount("/api/categories", routes![category::all])
.mount(
"/api/category",
routes![category::update, category::add, category::delete],
routes![
category::update,
category::add,
category::delete,
category::add_site,
category::get_sites,
],
)
.launch()
.await?;
Expand Down
4 changes: 4 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub enum ServiceError {

#[display(fmt = "Internal server error")]
InternalServerError,

#[display(fmt = "Bad request: {}", _0)]
BadRequest(String),
}

impl From<sqlx::Error> for ServiceError {
Expand Down Expand Up @@ -46,6 +49,7 @@ impl ServiceError {
ServiceError::NotFound => Status::NotFound,
ServiceError::Unauthorized => Status::Unauthorized,
ServiceError::InternalServerError => Status::InternalServerError,
ServiceError::BadRequest(_) => Status::BadRequest,
}
}
}
1 change: 0 additions & 1 deletion src/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
pub mod auth;
pub mod category;
pub mod site;
pub mod user;
63 changes: 62 additions & 1 deletion src/handlers/category.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use rocket::State;
use sqlx::{query, query_as};
use sqlx::{query, query_as, Row};

use crate::errors::ServiceError;
use crate::models::category::Category;
use crate::models::site::Site;
use crate::request::category::{CreateCategory, UpdateCategory};
use crate::request::site::CreateSite;
use crate::response;
use crate::state::AppState;

Expand Down Expand Up @@ -80,10 +82,69 @@ pub async fn add_category(
}

pub async fn delete_category(id: &str, state: &State<AppState>) -> Result<(), ServiceError> {
let sites_count =
query(r#"SELECT COUNT(site_id) AS count FROM category_site WHERE category_id = ?"#)
.bind(id)
.fetch_one(&state.pool)
.await?
.get::<i64, &str>("count");

if sites_count > 0 {
return Err(ServiceError::BadRequest(String::from("Category is in use")));
}

query(r#"DELETE FROM category WHERE id = ?"#)
.bind(id)
.execute(&state.pool)
.await?;

Ok(())
}

pub async fn add_site(
category_id: &str,
site: &CreateSite<'_>,
state: &State<AppState>,
) -> Result<(), ServiceError> {
query_as::<_, Category>(
r#"SELECT id, name, description, created_at, updated_at FROM category WHERE id = ?"#,
)
.bind(category_id)
.fetch_one(&state.pool)
.await
.map_err(|e| match e {
sqlx::Error::RowNotFound => ServiceError::NotFound,
_ => ServiceError::DatabaseError(e),
})?;

let id = query(r#"INSERT INTO site (name, url, description, icon) VALUES (?, ?, ?, ?)"#)
.bind(site.name)
.bind(site.url)
.bind(site.description)
.bind(site.icon)
.execute(&state.pool)
.await?
.last_insert_id();

query(r#"INSERT INTO category_site (category_id, site_id) VALUES (?, ?)"#)
.bind(category_id)
.bind(id)
.execute(&state.pool)
.await?;

Ok(())
}

pub async fn get_sites(
category_id: &str,
state: &State<AppState>,
) -> Result<Vec<response::site::Site>, ServiceError> {
let sites = query_as::<_, Site>(
r#"SELECT id, name, url, description, icon, created_at, updated_at FROM site WHERE id IN (SELECT site_id FROM category_site WHERE category_id = ?)"#,
)
.bind(category_id)
.fetch_all(&state.pool)
.await?;

Ok(sites.into_iter().map(|site| site.into()).collect())
}
1 change: 0 additions & 1 deletion src/handlers/site.rs

This file was deleted.

4 changes: 3 additions & 1 deletion src/request/site.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct CreateCategory<'r> {
pub struct CreateSite<'r> {
pub name: &'r str,
pub url: &'r str,
pub description: &'r str,
pub icon: &'r str,
}
23 changes: 23 additions & 0 deletions src/response/site.rs
Original file line number Diff line number Diff line change
@@ -1 +1,24 @@
use serde::Serialize;

use crate::models::site;

#[derive(Debug, Serialize)]
pub struct Site {
pub id: i64,
pub name: String,
pub url: String,
pub description: String,
pub icon: String,
}

impl From<site::Site> for Site {
fn from(site: site::Site) -> Self {
Self {
id: site.id,
name: site.name,
url: site.url,
description: site.description,
icon: site.icon,
}
}
}
1 change: 0 additions & 1 deletion src/routes.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
pub mod auth;
pub mod category;
pub mod site;
pub mod user;
33 changes: 32 additions & 1 deletion src/routes/category.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ use rocket::State;
use rocket::{delete, get, post, put};

use crate::handlers::category::{
add_category, delete_category, get_all_categories, update_category,
self, add_category, delete_category, get_all_categories, update_category,
};
use crate::middlewares::JwtMiddleware;
use crate::request::category::{CreateCategory, UpdateCategory};
use crate::request::site::CreateSite;
use crate::response::category::Category;
use crate::response::site::Site;
use crate::state::AppState;

#[get("/")]
Expand Down Expand Up @@ -72,3 +74,32 @@ pub async fn delete<'r>(

Ok(())
}

#[post("/<id>/site", format = "json", data = "<site>")]
pub async fn add_site(
id: &str,
site: Json<CreateSite<'_>>,
state: &State<AppState>,
_jwt: JwtMiddleware,
) -> Result<(), Status> {
category::add_site(id, site.deref(), state)
.await
.map_err(|e| {
error!("{}", e);

e.status()
})?;

Ok(())
}

#[get("/<id>/sites")]
pub async fn get_sites(id: &str, state: &State<AppState>) -> Result<Json<Vec<Site>>, Status> {
let sites = category::get_sites(id, state).await.map_err(|e| {
error!("{}", e);

e.status()
})?;

Ok(Json(sites))
}
1 change: 0 additions & 1 deletion src/routes/site.rs

This file was deleted.

0 comments on commit 8f17f52

Please sign in to comment.