diff --git a/crates/app/src/public/html/profile/settings.lisp b/crates/app/src/public/html/profile/settings.lisp index c5566c7..e3d775b 100644 --- a/crates/app/src/public/html/profile/settings.lisp +++ b/crates/app/src/public/html/profile/settings.lisp @@ -1537,7 +1537,7 @@ ], [ [\"auto_full_unlist\", \"Only publish my posts to my profile\"], - \"{{ profile.settings.auto_unlist }}\", + \"{{ profile.settings.auto_full_unlist }}\", \"checkbox\", ], [ diff --git a/crates/app/src/routes/api/v1/auth/profile.rs b/crates/app/src/routes/api/v1/auth/profile.rs index 8104c71..bb874fe 100644 --- a/crates/app/src/routes/api/v1/auth/profile.rs +++ b/crates/app/src/routes/api/v1/auth/profile.rs @@ -1,4 +1,4 @@ -use std::time::Duration; +use std::{str::FromStr, time::Duration}; use crate::{ get_user_from_token, model::{ApiReturn, Error}, @@ -451,8 +451,8 @@ pub async fn delete_user_request( Extension(data): Extension, Json(req): Json, ) -> impl IntoResponse { - let data = &(data.read().await).0; - let user = match get_user_from_token!(jar, data) { + let data = &(data.read().await); + let user = match get_user_from_token!(jar, data.0) { Some(ua) => ua, None => return Json(Error::NotAllowed.into()), }; @@ -461,6 +461,7 @@ pub async fn delete_user_request( return Json(Error::NotAllowed.into()); } else if user.permissions.check(FinePermission::MANAGE_USERS) { if let Err(e) = data + .0 .create_audit_log_entry(AuditLogEntry::new( user.id, format!("invoked `delete_user` with x value `{id}`"), @@ -472,14 +473,32 @@ pub async fn delete_user_request( } match data + .0 .delete_user(id, &req.password, user.permissions.check_manager()) .await { - Ok(_) => Json(ApiReturn { - ok: true, - message: "User deleted".to_string(), - payload: (), - }), + Ok(ua) => { + // delete stripe user + if let Some(stripe_id) = ua.seller_data.account_id + && let Some(ref client) = data.3 + { + if let Err(e) = stripe::Account::delete( + &client, + &stripe::AccountId::from_str(&stripe_id).unwrap(), + ) + .await + { + return Json(Error::MiscError(e.to_string()).into()); + } + } + + // ... + Json(ApiReturn { + ok: true, + message: "User deleted".to_string(), + payload: (), + }) + } Err(e) => Json(e.into()), } } diff --git a/crates/core/src/database/auth.rs b/crates/core/src/database/auth.rs index 9bfdd36..b8651ca 100644 --- a/crates/core/src/database/auth.rs +++ b/crates/core/src/database/auth.rs @@ -321,7 +321,7 @@ impl DataManager { /// * `id` - the ID of the user /// * `password` - the current password of the user /// * `force` - if we should delete even if the given password is incorrect - pub async fn delete_user(&self, id: usize, password: &str, force: bool) -> Result<()> { + pub async fn delete_user(&self, id: usize, password: &str, force: bool) -> Result { let user = self.get_user_by_id(id).await?; if (hash_salted(password.to_string(), user.salt.clone()) != user.password) && !force { @@ -581,7 +581,7 @@ impl DataManager { } // ... - Ok(()) + Ok(user) } pub async fn update_user_verified_status(&self, id: usize, x: bool, user: User) -> Result<()> { diff --git a/crates/core/src/model/mod.rs b/crates/core/src/model/mod.rs index 2cd4955..b86ebfa 100644 --- a/crates/core/src/model/mod.rs +++ b/crates/core/src/model/mod.rs @@ -10,6 +10,7 @@ pub mod littleweb; pub mod moderation; pub mod oauth; pub mod permissions; +pub mod products; pub mod reactions; pub mod requests; pub mod socket; diff --git a/crates/core/src/model/products.rs b/crates/core/src/model/products.rs new file mode 100644 index 0000000..e7b5b41 --- /dev/null +++ b/crates/core/src/model/products.rs @@ -0,0 +1,58 @@ +use serde::{Serialize, Deserialize}; +use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Product { + pub id: usize, + pub created: usize, + pub owner: usize, + pub title: String, + pub description: String, + pub likes: usize, + pub dislikes: usize, + pub r#type: ProductType, + pub stripe_id: String, + pub price: ProductPrice, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum ProductType { + /// Text + images. + Message, + /// When a commission product is purchased, the creator will receive a request + /// prompting them to respond with text + images. + /// + /// This is the only product type which does not immediately return data to the + /// customer, as seller input is required. + /// + /// If the request is deleted, the purchase should be immediately refunded. + Commission, +} + +/// Price in USD. `(dollars, cents)`. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ProductPrice(u64, u64); + +impl Product { + /// Create a new [`Product`]. + pub fn new( + owner: usize, + title: String, + description: String, + price: ProductPrice, + r#type: ProductType, + ) -> Self { + Self { + id: Snowflake::new().to_string().parse::().unwrap(), + created: unix_epoch_timestamp(), + owner, + title, + description, + likes: 0, + dislikes: 0, + r#type, + stripe_id: String::new(), + price, + } + } +}