diff --git a/migrations/20231127033035_site.up.sql b/migrations/20231127033035_site.up.sql index fbd69e5..2e02315 100644 --- a/migrations/20231127033035_site.up.sql +++ b/migrations/20231127033035_site.up.sql @@ -5,6 +5,7 @@ CREATE TABLE site url VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, icon VARCHAR(255) NOT NULL, + sort_order INT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); diff --git a/src/bin/server.rs b/src/bin/server.rs index 12686aa..85e4377 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -86,6 +86,7 @@ async fn main() -> Result<(), rocket::Error> { category::delete, category::get_sites, category::sort, + category::sort_sites, ], ) .mount("/api/sites", routes![site::all]) diff --git a/src/handlers/category.rs b/src/handlers/category.rs index bb2e914..a5c24e8 100644 --- a/src/handlers/category.rs +++ b/src/handlers/category.rs @@ -1,3 +1,4 @@ +use log::error; use rocket_db_pools::Connection; use sqlx::{query, query_as, Row}; @@ -200,7 +201,7 @@ pub async fn get_sites( ) -> Result, ServiceError> { let sites = match search { Some(search) => query_as::<_, response::site::Site>( - r#"SELECT site.id, site.name, site.url, site.description, site.icon FROM site INNER JOIN category_site ON site.id = category_site.site_id WHERE category_site.category_id = ? AND (site.name LIKE ? OR site.description LIKE ?)"#, + r#"SELECT site.id, site.name, site.url, site.description, site.icon FROM site INNER JOIN category_site ON site.id = category_site.site_id WHERE category_site.category_id = ? AND (site.name LIKE ? OR site.description LIKE ?) ORDER BY site.sort_order"#, ) .bind(category_id) .bind(format!("%{}%", search)) @@ -208,7 +209,7 @@ pub async fn get_sites( .fetch_all(&mut ***db) .await?, None => query_as::<_, response::site::Site>( - r#"SELECT site.id, site.name, site.url, site.description, site.icon FROM site INNER JOIN category_site ON site.id = category_site.site_id WHERE category_site.category_id = ?"#, + r#"SELECT site.id, site.name, site.url, site.description, site.icon FROM site INNER JOIN category_site ON site.id = category_site.site_id WHERE category_site.category_id = ? ORDER BY site.sort_order"#, ) .bind(category_id) .fetch_all(&mut ***db) @@ -264,3 +265,48 @@ pub async fn sort_categories( Ok(()) } + +pub async fn sort_category_sites( + id: i64, + active_id: i64, + over_id: Option, + db: &mut Connection, +) -> Result<(), ServiceError> { + query(r#" + SELECT site.id as site_id + FROM site + INNER JOIN category + INNER JOIN category_site ON site.id = category_site.site_id AND category.id = category_site.category_id + WHERE site.id = ? AND category.id = ?; + "#) + .bind(active_id) + .bind(id) + .fetch_one(&mut ***db) + .await + .map_err(|e| { + error!("{}", e); + + ServiceError::BadRequest(String::from("Site not found")) + })?; + + let over_id = match over_id { + Some(over_id) => over_id, + None => { + query(r#"SELECT site.id as site_id FROM site INNER JOIN category INNER JOIN category_site ON site.id = category_site.site_id AND category.id = category_site.category_id WHERE category.id = ? ORDER BY site.id DESC LIMIT 1"#) + .bind(id) + .fetch_one(&mut ***db) + .await? + .get::("site_id") + } + }; + + query(r#" + UPDATE site as s1, site as s2 SET s1.sort_order = s2.sort_order, s2.sort_order = s1.sort_order WHERE s1.id = ? AND s2.id = ?; + "#) + .bind(active_id) + .bind(over_id) + .execute(&mut ***db) + .await?; + + Ok(()) +} diff --git a/src/handlers/site.rs b/src/handlers/site.rs index 7427165..c396d29 100644 --- a/src/handlers/site.rs +++ b/src/handlers/site.rs @@ -97,14 +97,29 @@ pub async fn add_site( _ => 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(&mut ***db) - .await? - .last_insert_id(); + let order = match query(r#"SELECT MAX(sort_order) AS sort_order FROM site INNER JOIN category_site ON site.id = category_site.site_id WHERE category_site.category_id = ?"#) + .bind(site.category) + .fetch_one(&mut ***db) + .await + { + Ok(row) => match row.try_get::("sort_order") { + Ok(order) => order + 1, + Err(_) => 0, + }, + Err(_) => 0, + }; + + let id = query( + r#"INSERT INTO site (name, url, description, icon, sort_order) VALUES (?, ?, ?, ?, ?)"#, + ) + .bind(site.name) + .bind(site.url) + .bind(site.description) + .bind(site.icon) + .bind(order) + .execute(&mut ***db) + .await? + .last_insert_id(); query(r#"INSERT INTO category_site (category_id, site_id) VALUES (?, ?)"#) .bind(site.category) @@ -121,7 +136,7 @@ pub async fn update_site( db: &mut Connection, ) -> Result<(), ServiceError> { let record = query_as::<_, Site>( - r#"SELECT id, name, url, description, icon, created_at, updated_at FROM site WHERE id = ?"#, + r#"SELECT id, name, url, description, icon, sort_order, created_at, updated_at FROM site WHERE id = ?"#, ) .bind(site_id) .fetch_one(&mut ***db) @@ -169,6 +184,7 @@ pub async fn update_site( url, description, icon, + sort_order: record.sort_order, created_at: record.created_at, updated_at: record.updated_at, }; @@ -194,6 +210,21 @@ pub async fn update_site( _ => ServiceError::DatabaseError(e), })?; + let order = match query(r#"SELECT MAX(sort_order) AS sort_order FROM site INNER JOIN category_site ON site.id = category_site.site_id WHERE category_site.category_id = ?"#).bind(category).fetch_one(&mut ***db).await + { + Ok(row) => match row.try_get::("sort_order") { + Ok(order) => order + 1, + Err(_) => 0, + }, + Err(_) => 0, + }; + + query(r#"UPDATE site SET sort_order = ? WHERE id = ?"#) + .bind(order) + .bind(record.id) + .execute(&mut ***db) + .await?; + query(r#"UPDATE category_site SET category_id = ? WHERE site_id = ?"#) .bind(category) .bind(record.id) diff --git a/src/models/site.rs b/src/models/site.rs index e0d4171..da62deb 100644 --- a/src/models/site.rs +++ b/src/models/site.rs @@ -9,6 +9,7 @@ pub struct Site { pub url: String, pub description: String, pub icon: String, + pub sort_order: i64, pub created_at: NaiveDateTime, pub updated_at: NaiveDateTime, } diff --git a/src/routes/category.rs b/src/routes/category.rs index aa7a62d..038fafc 100644 --- a/src/routes/category.rs +++ b/src/routes/category.rs @@ -6,7 +6,8 @@ use rocket_db_pools::Connection; use crate::config::Config; use crate::handlers::category::{ - self, add_category, delete_category, get_categories, sort_categories, update_category, + self, add_category, delete_category, get_categories, sort_categories, sort_category_sites, + update_category, }; use crate::middlewares::JwtMiddleware; use crate::request::category::{CreateCategory, SortCategory, UpdateCategory}; @@ -137,3 +138,20 @@ pub async fn sort(data: Json, mut db: Connection) -> Resu Ok(()) } + +#[post("//sites/sort", format = "json", data = "")] +pub async fn sort_sites( + id: i64, + data: Json, + mut db: Connection, +) -> Result<(), Status> { + sort_category_sites(id, data.active, data.over, &mut db) + .await + .map_err(|e| { + error!("{}", e); + + e.status() + })?; + + Ok(()) +}