From 99fc959383d5b7b26d8e80f6257adf8b98989f41 Mon Sep 17 00:00:00 2001 From: WriterV2 Date: Thu, 7 Nov 2024 17:06:03 +0100 Subject: Feat: Add ability to add tags to story (and product in general) --- src/db/mod.rs | 1 + src/db/product.rs | 24 ++++++++++++++++++++++-- src/db/producttag.rs | 2 +- src/db/story.rs | 3 ++- src/handlers/admin.rs | 11 ++++++++++- 5 files changed, 36 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/db/mod.rs b/src/db/mod.rs index 7050527..e44c9ad 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -21,6 +21,7 @@ pub trait ProductDatabaseHandler { pool: &SqlitePool, name: String, description: String, + tags: Vec, ) -> Result where Self: Sized; diff --git a/src/db/product.rs b/src/db/product.rs index 5b58560..06217c0 100644 --- a/src/db/product.rs +++ b/src/db/product.rs @@ -1,10 +1,12 @@ use std::collections::HashMap; use std::time::SystemTime; -use sqlx::{Sqlite, SqlitePool, Transaction}; +use sqlx::{QueryBuilder, Sqlite, SqlitePool, Transaction}; use crate::error::AppError; +use super::producttag::ProductTag; +use super::tag::Tag; use super::ProductDatabaseHandler; #[derive(Debug, serde::Serialize, sqlx::FromRow)] @@ -17,7 +19,7 @@ pub struct Product { } impl Product { - pub async fn post(tx: &mut Transaction<'static, Sqlite>, name: String, description: String) -> Result { + pub async fn post(tx: &mut Transaction<'static, Sqlite>, name: String, description: String, tags: Vec) -> Result { let now = SystemTime::now().duration_since(std::time::UNIX_EPOCH)?.as_millis() as i64; let product = sqlx::query_as!( Product, @@ -28,6 +30,24 @@ impl Product { now) .fetch_one(&mut **tx) .await?; + + if !tags.is_empty() { + let mut tags_query_builder: QueryBuilder = QueryBuilder::new("INSERT INTO tag (name) "); + tags_query_builder.push_values(tags.iter(), | mut b, tag | { b.push_bind(tag); }); + tags_query_builder.push(" RETURNING id, name;"); + let added_tags: Vec = tags_query_builder + .build_query_as::() + .fetch_all(&mut **tx) + .await?; + + let mut producttags_query_builder: QueryBuilder = QueryBuilder::new("INSERT INTO producttag (pid, tid) "); + producttags_query_builder.push_values(added_tags.iter(), | mut b, added_tag | { + b.push_bind(product.id).push_bind(added_tag.id); + }); + producttags_query_builder + .build().execute(&mut **tx).await?; + + } Ok(product) } } diff --git a/src/db/producttag.rs b/src/db/producttag.rs index b3091c3..160e720 100644 --- a/src/db/producttag.rs +++ b/src/db/producttag.rs @@ -1,5 +1,5 @@ #[derive(Debug, serde::Serialize, sqlx::FromRow)] -pub struct Storytag { +pub struct ProductTag { pub pid: i64, pub tid: i64, } diff --git a/src/db/story.rs b/src/db/story.rs index b77d7a3..137c964 100644 --- a/src/db/story.rs +++ b/src/db/story.rs @@ -78,12 +78,13 @@ impl ProductDatabaseHandler for Story { pool: &SqlitePool, name: String, description: String, + tags: Vec, ) -> Result where Self: Sized, { let mut tx = pool.begin().await?; - let product = Product::post(&mut tx, name, description).await?; + let product = Product::post(&mut tx, name, description, tags).await?; let story = sqlx::query_as!( Story, "INSERT INTO story (language, pdf, epub, pid) VALUES ($1, $2, $3, $4) RETURNING id, language, pdf, epub, pid", diff --git a/src/handlers/admin.rs b/src/handlers/admin.rs index a48be21..7c016dd 100644 --- a/src/handlers/admin.rs +++ b/src/handlers/admin.rs @@ -112,6 +112,13 @@ pub async fn upload_story( return Ok(StatusCode::BAD_REQUEST.into_response()); }; + let mut tags: Vec = Vec::new(); + if let Some(tags_value) = form.get("tag") { + for tag in String::from_utf8(tags_value.to_vec())?.split(",") { + tags.push(tag.trim().to_string()); + } + } + let story_template = Story { id: 0, pid: 0, @@ -120,6 +127,8 @@ pub async fn upload_story( epub, }; - let story = story_template.post(&ctx.pool, name, description).await?; + let story = story_template + .post(&ctx.pool, name, description, tags) + .await?; Ok((StatusCode::CREATED, Json(story)).into_response()) } -- cgit v1.2.3