add: product types

This commit is contained in:
trisua 2025-07-13 00:05:28 -04:00
parent aea764948c
commit 2705608903
5 changed files with 89 additions and 11 deletions

View file

@ -1537,7 +1537,7 @@
], ],
[ [
[\"auto_full_unlist\", \"Only publish my posts to my profile\"], [\"auto_full_unlist\", \"Only publish my posts to my profile\"],
\"{{ profile.settings.auto_unlist }}\", \"{{ profile.settings.auto_full_unlist }}\",
\"checkbox\", \"checkbox\",
], ],
[ [

View file

@ -1,4 +1,4 @@
use std::time::Duration; use std::{str::FromStr, time::Duration};
use crate::{ use crate::{
get_user_from_token, get_user_from_token,
model::{ApiReturn, Error}, model::{ApiReturn, Error},
@ -451,8 +451,8 @@ pub async fn delete_user_request(
Extension(data): Extension<State>, Extension(data): Extension<State>,
Json(req): Json<DeleteUser>, Json(req): Json<DeleteUser>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let data = &(data.read().await).0; let data = &(data.read().await);
let user = match get_user_from_token!(jar, data) { let user = match get_user_from_token!(jar, data.0) {
Some(ua) => ua, Some(ua) => ua,
None => return Json(Error::NotAllowed.into()), None => return Json(Error::NotAllowed.into()),
}; };
@ -461,6 +461,7 @@ pub async fn delete_user_request(
return Json(Error::NotAllowed.into()); return Json(Error::NotAllowed.into());
} else if user.permissions.check(FinePermission::MANAGE_USERS) { } else if user.permissions.check(FinePermission::MANAGE_USERS) {
if let Err(e) = data if let Err(e) = data
.0
.create_audit_log_entry(AuditLogEntry::new( .create_audit_log_entry(AuditLogEntry::new(
user.id, user.id,
format!("invoked `delete_user` with x value `{id}`"), format!("invoked `delete_user` with x value `{id}`"),
@ -472,14 +473,32 @@ pub async fn delete_user_request(
} }
match data match data
.0
.delete_user(id, &req.password, user.permissions.check_manager()) .delete_user(id, &req.password, user.permissions.check_manager())
.await .await
{ {
Ok(_) => Json(ApiReturn { Ok(ua) => {
ok: true, // delete stripe user
message: "User deleted".to_string(), if let Some(stripe_id) = ua.seller_data.account_id
payload: (), && 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()), Err(e) => Json(e.into()),
} }
} }

View file

@ -321,7 +321,7 @@ impl DataManager {
/// * `id` - the ID of the user /// * `id` - the ID of the user
/// * `password` - the current password of the user /// * `password` - the current password of the user
/// * `force` - if we should delete even if the given password is incorrect /// * `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<User> {
let user = self.get_user_by_id(id).await?; let user = self.get_user_by_id(id).await?;
if (hash_salted(password.to_string(), user.salt.clone()) != user.password) && !force { 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<()> { pub async fn update_user_verified_status(&self, id: usize, x: bool, user: User) -> Result<()> {

View file

@ -10,6 +10,7 @@ pub mod littleweb;
pub mod moderation; pub mod moderation;
pub mod oauth; pub mod oauth;
pub mod permissions; pub mod permissions;
pub mod products;
pub mod reactions; pub mod reactions;
pub mod requests; pub mod requests;
pub mod socket; pub mod socket;

View file

@ -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::<usize>().unwrap(),
created: unix_epoch_timestamp(),
owner,
title,
description,
likes: 0,
dislikes: 0,
r#type,
stripe_id: String::new(),
price,
}
}
}