diff --git a/Cargo.lock b/Cargo.lock index 525e54d..16fd864 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1355,8 +1355,8 @@ dependencies = [ [[package]] name = "petompp-web-models" -version = "0.4.4" -source = "git+https://github.com/PetoMPP/petompp-web-models.git?branch=0.4.4#ddaf81f74ad42b96175608fc606852a2f94938d3" +version = "0.4.6" +source = "git+https://github.com/PetoMPP/petompp-web-models.git?branch=0.4.6#4b6f47ec1b78978d921567a3bf738f2871ebd1b7" dependencies = [ "azure_core", "azure_storage", diff --git a/Cargo.toml b/Cargo.toml index b0c3ab6..48e2868 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ jwt = "0.16" lazy_static = "1.4" num-traits = "0.2" num-derive = "0.4" -petompp-web-models = { git = "https://github.com/PetoMPP/petompp-web-models.git", branch = "0.4.4", features = [ +petompp-web-models = { git = "https://github.com/PetoMPP/petompp-web-models.git", branch = "0.4.6", features = [ "api-errors", ] } r2d2 = "0.8" diff --git a/src/controllers/blog.rs b/src/controllers/blog.rs index c983a2a..2c8005b 100644 --- a/src/controllers/blog.rs +++ b/src/controllers/blog.rs @@ -8,7 +8,7 @@ use petompp_web_models::{ country::Country, }, }; -use rocket::{get, post, routes, serde::json::Json, State}; +use rocket::{delete, get, post, routes, serde::json::Json, State}; pub struct BlogController; @@ -18,7 +18,7 @@ impl Controller for BlogController { } fn routes(&self) -> Vec { - routes![create_or_update, get_meta, get_meta_all] + routes![create_or_update, delete, get_meta, get_meta_all] } } @@ -41,6 +41,23 @@ async fn create_or_update<'a>( Ok(Json(ApiResponse::ok("ok"))) } +#[delete("//")] +async fn delete<'a>( + _claims: AdminClaims, + name: &'a str, + lang: &'a str, + blob_service: &'a State, +) -> Result>, ApiError<'a>> { + blob_service + .delete_blog_post( + &name.to_string(), + &Country::try_from(lang) + .map_err(|_| ApiError::from(Error::ValidationError(ValidationError::Country)))?, + ) + .await?; + Ok(Json(ApiResponse::ok("ok"))) +} + #[get("/meta//")] async fn get_meta<'a>( name: &'a str, @@ -59,11 +76,12 @@ async fn get_meta<'a>( ))) } -#[get("/meta")] +#[get("/meta?")] async fn get_meta_all<'a>( blob_service: &'a State, + prefix: Option, ) -> Result>>, ApiError<'a>> { Ok(Json(ApiResponse::ok( - blob_service.get_all_blog_meta().await?, + blob_service.get_all_blog_meta(prefix).await?, ))) } diff --git a/src/controllers/resources.rs b/src/controllers/resources.rs index d666f8e..d779c4f 100644 --- a/src/controllers/resources.rs +++ b/src/controllers/resources.rs @@ -5,7 +5,7 @@ use crate::{ }; use petompp_web_models::{ error::{ApiError, Error, ResourceDataValidationError, ValidationError}, - models::{api_response::ApiResponse, resource_data::ResourceData}, + models::{api_response::ApiResponse, country::Country, resource_data::ResourceData}, }; use rocket::{delete, get, post, put, routes, serde::json::Json}; @@ -17,17 +17,17 @@ impl Controller for ResourcesController { } fn routes(&self) -> Vec { - routes![get, get_all_keys, create, update, delete] + routes![get, get_all_keys, create, update, delete, delete_lang] } } #[get("/?")] async fn get<'a>( key: &'a str, - lang: &'a str, + lang: Country, pool: &dyn ResourcesRepo, -) -> Result>, ApiError<'a>> { - Ok(Json(ApiResponse::ok(pool.get(key, lang)?))) +) -> Result>, ApiError<'a>> { + Ok(Json(ApiResponse::ok(pool.get(key, &lang)?))) } #[get("/keys")] @@ -77,11 +77,22 @@ async fn update<'a>( } #[delete("/")] -async fn delete( +async fn delete<'a>( _admin_claims: AdminClaims, - key: &str, + key: &'a str, pool: &dyn ResourcesRepo, -) -> Result<&'static str, ApiError<'static>> { +) -> Result>, ApiError<'a>> { pool.delete(key)?; - Ok("OK") + Ok(Json(ApiResponse::ok("ok"))) +} + +#[delete("/?")] +async fn delete_lang<'a>( + _admin_claims: AdminClaims, + key: &'a str, + lang: Country, + pool: &dyn ResourcesRepo, +) -> Result>, ApiError<'a>> { + pool.delete_lang(key, &lang)?; + Ok(Json(ApiResponse::ok("ok"))) } diff --git a/src/repositories/resources/repo.rs b/src/repositories/resources/repo.rs index 2f99ede..71c851f 100644 --- a/src/repositories/resources/repo.rs +++ b/src/repositories/resources/repo.rs @@ -1,14 +1,18 @@ use crate::{models::resource_data::Resource, schema::resources, PgPool}; use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; -use petompp_web_models::error::{Error, ResourceDataValidationError, ValidationError}; +use petompp_web_models::{ + error::{Error, ResourceDataValidationError, ValidationError}, + models::country::Country, +}; use rocket::{async_trait, http::Status, outcome::Outcome, request::FromRequest, Request}; pub trait ResourcesRepo: Send + Sync { - fn get(&self, key: &str, lang: &str) -> Result; + fn get(&self, key: &str, lang: &Country) -> Result<(Country, String), Error>; fn get_all(&self) -> Result, Error>; fn create(&self, data: &Resource) -> Result; fn update(&self, data: &Resource) -> Result; fn delete(&self, key: &str) -> Result<(), Error>; + fn delete_lang(&self, key: &str, lang: &Country) -> Result<(), Error>; } #[async_trait] @@ -24,19 +28,22 @@ impl<'r> FromRequest<'r> for &'r dyn ResourcesRepo { } impl ResourcesRepo for PgPool { - fn get(&self, key: &str, lang: &str) -> Result { + fn get(&self, key: &str, lang: &Country) -> Result<(Country, String), Error> { let mut conn = self.get()?; let q = resources::dsl::resources.filter(resources::key.eq(key)); - let res = match lang { - "pl" => { - let (pl, en) = q - .select((resources::pl, resources::en)) - .get_result::<(Option, String)>(&mut conn)?; - pl.unwrap_or(en) - } - _ => q.select(resources::en).get_result::(&mut conn)?, - }; - Ok(res) + Ok(match lang { + Country::Poland => q + .select((resources::pl, resources::en)) + .get_result::<(Option, String)>(&mut conn) + .map(|(pl, en)| match pl { + Some(pl) => (Country::Poland, pl), + None => (Country::UnitedKingdom, en), + })?, + _ => q + .select(resources::en) + .get_result::(&mut conn) + .map(|en| (Country::UnitedKingdom, en))?, + }) } fn get_all(&self) -> Result, Error> { @@ -89,4 +96,16 @@ impl ResourcesRepo for PgPool { .execute(&mut conn)?; Ok(()) } + + fn delete_lang(&self, key: &str, lang: &Country) -> Result<(), Error> { + let mut conn = self.get()?; + match lang { + Country::UnitedKingdom => return Err(Error::ValidationError(ValidationError::Country)), + Country::Poland => diesel::update(resources::dsl::resources) + .filter(resources::dsl::key.eq(key)) + .set(resources::dsl::pl.eq::>(None)) + .execute(&mut conn)?, + }; + Ok(()) + } } diff --git a/src/services/azure_blob.rs b/src/services/azure_blob.rs index e0a29b0..f1daecd 100644 --- a/src/services/azure_blob.rs +++ b/src/services/azure_blob.rs @@ -79,30 +79,50 @@ impl AzureBlobService { .map(|_| ())?) } - pub async fn delete_img(&self, pattern: String) -> Result { + async fn delete(&self, container: String, pattern: String) -> Result { Ok(self .client .clone() .blob_service_client() - .container_client(Self::IMAGE_CONTAINER.to_string()) + .container_client(container.clone()) .list_blobs() .prefix(pattern) .into_stream() - .fold(Result::<_, Error>::Ok(0), |acc, resp| async move { - let mut count = acc?; - for blob in resp?.blobs.blobs().cloned() { - self.client - .clone() - .blob_client(Self::IMAGE_CONTAINER.to_string(), blob.name) - .delete() - .await?; - count += 1; + .fold(Result::<_, Error>::Ok(0), |acc, resp| { + let container = container.clone(); + async move { + let mut count = acc?; + for blob in resp?.blobs.blobs().cloned() { + self.client + .clone() + .blob_client(container.clone(), blob.name) + .delete() + .await?; + count += 1; + } + Ok(count) } - Ok(count) }) .await?) } + pub async fn delete_img(&self, pattern: String) -> Result { + Self::delete(self, Self::IMAGE_CONTAINER.to_string(), pattern).await + } + + pub async fn delete_blog_post( + &self, + id: &String, + lang: &Country, + ) -> Result { + Self::delete( + self, + Self::BLOG_CONTAINER.to_string(), + format!("{}/{}.md", id, lang.key()), + ) + .await + } + const BLOG_CONTAINER: &str = "blog"; pub async fn get_blog_meta(&self, id: &String, lang: &Country) -> Result { let mut stream = self @@ -135,8 +155,11 @@ impl AzureBlobService { BlogMetaData::try_from(curr) } - pub async fn get_all_blog_meta(&self) -> Result, Error> { - let mut stream = self + pub async fn get_all_blog_meta( + &self, + prefix: Option, + ) -> Result, Error> { + let mut builder = self .client .clone() .blob_service_client() @@ -144,8 +167,11 @@ impl AzureBlobService { .list_blobs() .include_metadata(true) .include_tags(true) - .include_versions(true) - .into_stream(); + .include_versions(true); + if let Some(prefix) = prefix { + builder = builder.prefix(prefix); + } + let mut stream = builder.into_stream(); let mut result = HashMap::new(); while let Some(resp) = stream.next().await { for blob in resp?.blobs.blobs().cloned() {