add: products api

This commit is contained in:
trisua 2025-08-07 13:52:48 -04:00
parent 3c4ce1fae5
commit df5eaf24f7
29 changed files with 1022 additions and 110 deletions

View file

@ -1,8 +1,60 @@
use serde::{Serialize, Deserialize};
use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp};
use super::auth::User;
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ProductFulfillmentMethod {
/// Automatically send a letter to the customer with the specified content.
AutoMail(String),
/// Manually send a letter to the customer with the specified content.
///
/// This will leave the [`CoinTransfer`] pending until you send this mail.
ManualMail,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct Product {
pub id: usize,
pub created: usize,
pub owner: usize,
pub title: String,
pub description: String,
/// How this product will be delivered.
pub method: ProductFulfillmentMethod,
/// If this product is actually for sale.
pub on_sale: bool,
/// The price of this product.
pub price: i32,
/// The number of times this product can be purchased.
///
/// A negative stock means the product has unlimited stock.
pub stock: i32,
}
impl Product {
/// Create a new [`Product`].
pub fn new(owner: usize, title: String, description: String) -> Self {
Self {
id: Snowflake::new().to_string().parse::<usize>().unwrap(),
created: unix_epoch_timestamp(),
owner,
title,
description,
method: ProductFulfillmentMethod::ManualMail,
on_sale: false,
price: 0,
stock: 0,
}
}
}
#[derive(Serialize, Deserialize)]
pub enum CoinTransferMethod {
Transfer,
/// A [`Product`] purchase with the product's ID.
Purchase(usize),
}
#[derive(Serialize, Deserialize)]
pub struct CoinTransfer {
pub id: usize,
@ -10,17 +62,21 @@ pub struct CoinTransfer {
pub sender: usize,
pub receiver: usize,
pub amount: i32,
pub is_pending: bool,
pub method: CoinTransferMethod,
}
impl CoinTransfer {
/// Create a new [`CoinTransfer`].
pub fn new(sender: usize, receiver: usize, amount: i32) -> Self {
pub fn new(sender: usize, receiver: usize, amount: i32, method: CoinTransferMethod) -> Self {
Self {
id: Snowflake::new().to_string().parse::<usize>().unwrap(),
created: unix_epoch_timestamp(),
sender,
receiver,
amount,
is_pending: false,
method,
}
}

View file

@ -74,10 +74,10 @@ pub enum AppScope {
UserReadDomains,
/// Read the user's services.
UserReadServices,
/// Read the user's products.
UserReadProducts,
/// Read the user's letters.
UserReadLetters,
/// Read the user's products.
UserReadProducts,
/// Create posts as the user.
UserCreatePosts,
/// Create messages as the user.
@ -102,10 +102,10 @@ pub enum AppScope {
UserCreateDomains,
/// Create services on behalf of the user.
UserCreateServices,
/// Create products on behalf of the user.
UserCreateProducts,
/// Create letters on behalf of the user.
UserCreateLetters,
/// Create products on behalf of the user.
UserCreateProducts,
/// Send coins on behalf of the user.
UserSendCoins,
/// Delete posts owned by the user.
@ -148,12 +148,12 @@ pub enum AppScope {
UserManageDomains,
/// Manage the user's services.
UserManageServices,
/// Manage the user's products.
UserManageProducts,
/// Manage the user's channel mutes.
UserManageChannelMutes,
/// Manage the user's letters.
UserManageLetters,
/// Manage the user's products.
UserManageProducts,
/// Edit posts created by the user.
UserEditPosts,
/// Edit drafts created by the user.

View file

@ -1,6 +1,51 @@
use serde::{Serialize, Deserialize};
use tetratto_shared::{snow::Snowflake, unix_epoch_timestamp};
#[derive(Serialize, Deserialize, PartialEq, Eq)]
pub enum ActionData {
String(String),
Int32(i32),
Usize(usize),
Many(Vec<ActionData>),
Null,
}
impl ActionData {
pub fn read_string(self) -> String {
match self {
ActionData::String(x) => x,
_ => String::default(),
}
}
pub fn read_int32(self) -> i32 {
match self {
ActionData::Int32(x) => x,
_ => i32::default(),
}
}
pub fn read_usize(self) -> usize {
match self {
ActionData::Usize(x) => x,
_ => usize::default(),
}
}
pub fn read_many(self) -> Vec<ActionData> {
match self {
ActionData::Many(x) => x,
_ => Vec::default(),
}
}
}
impl Default for ActionData {
fn default() -> Self {
Self::Null
}
}
#[derive(Serialize, Deserialize, PartialEq, Eq)]
pub enum ActionType {
/// A request to join a community.
@ -15,6 +60,10 @@ pub enum ActionType {
///
/// `users` table.
Follow,
/// A request for the `owner` user (sender) to send the `linked_asset` user (receiver) coins.
///
/// Expects a `data` value of [`ActionData::Int32`] representing the coin amount.
Transfer,
}
#[derive(Serialize, Deserialize)]
@ -26,28 +75,49 @@ pub struct ActionRequest {
/// The ID of the asset this request links to. Should exist in the correct
/// table for the given [`ActionType`].
pub linked_asset: usize,
/// Optional data attached to the action request.
pub data: ActionData,
}
impl ActionRequest {
/// Create a new [`ActionRequest`].
pub fn new(owner: usize, action_type: ActionType, linked_asset: usize) -> Self {
pub fn new(
owner: usize,
action_type: ActionType,
linked_asset: usize,
data: Option<ActionData>,
) -> Self {
Self {
id: Snowflake::new().to_string().parse::<usize>().unwrap(),
created: unix_epoch_timestamp(),
owner,
action_type,
linked_asset,
data: match data {
Some(x) => x,
None => ActionData::default(),
},
}
}
/// Create a new [`ActionRequest`] with the given `id`.
pub fn with_id(id: usize, owner: usize, action_type: ActionType, linked_asset: usize) -> Self {
pub fn with_id(
id: usize,
owner: usize,
action_type: ActionType,
linked_asset: usize,
data: Option<ActionData>,
) -> Self {
Self {
id,
created: unix_epoch_timestamp(),
owner,
action_type,
linked_asset,
data: match data {
Some(x) => x,
None => ActionData::default(),
},
}
}
}