add: ProfileStyle products

This commit is contained in:
trisua 2025-08-08 23:44:45 -04:00
parent 077e9252e3
commit 95cb889080
19 changed files with 525 additions and 54 deletions

View file

@ -1,15 +1,15 @@
use super::common::NAME_REGEX;
use oiseau::cache::Cache;
use crate::model::auth::{
Achievement, AchievementName, AchievementRarity, Notification, UserConnections, ACHIEVEMENTS,
};
use crate::model::moderation::AuditLogEntry;
use crate::model::oauth::AuthGrant;
use crate::model::permissions::SecondaryPermission;
use crate::model::{
Error, Result,
auth::{Token, User, UserSettings},
permissions::FinePermission,
permissions::{FinePermission, SecondaryPermission},
oauth::AuthGrant,
moderation::AuditLogEntry,
auth::{
Achievement, AchievementName, AchievementRarity, Notification, UserConnections,
ACHIEVEMENTS, AppliedConfigType,
},
};
use pathbufd::PathBufD;
use std::fs::{exists, remove_file};
@ -130,6 +130,7 @@ impl DataManager {
ban_expire: get!(x->30(i64)) as usize,
coins: get!(x->31(i32)),
checkouts: serde_json::from_str(&get!(x->32(String)).to_string()).unwrap(),
applied_configurations: serde_json::from_str(&get!(x->33(String)).to_string()).unwrap(),
}
}
@ -286,7 +287,7 @@ impl DataManager {
let res = execute!(
&conn,
"INSERT INTO users VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33)",
"INSERT INTO users VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34)",
params![
&(data.id as i64),
&(data.created as i64),
@ -321,6 +322,7 @@ impl DataManager {
&(data.ban_expire as i64),
&(data.coins as i32),
&serde_json::to_string(&data.checkouts).unwrap(),
&serde_json::to_string(&data.applied_configurations).unwrap(),
]
);
@ -1091,6 +1093,29 @@ impl DataManager {
Ok((totp.get_secret_base32(), qr, recovery))
}
/// Get all applied configurations as a vector of strings from the given user.
pub async fn get_applied_configurations(&self, user: &User) -> Result<Vec<String>> {
let mut out = Vec::new();
for config in &user.applied_configurations {
let product = match self.get_product_by_id(config.1).await {
Ok(x) => x,
Err(_) => continue,
};
out.push(match config.0 {
AppliedConfigType::StyleSnippet => {
format!(
"<style>{}</style>",
product.data.replace("<", "&lt;").replace(">", "&gt;")
)
}
})
}
Ok(out)
}
pub async fn cache_clear_user(&self, user: &User) {
self.0.1.remove(format!("atto.user:{}", user.id)).await;
self.0
@ -1119,6 +1144,7 @@ impl DataManager {
auto_method!(update_user_ban_expire(i64)@get_user_by_id -> "UPDATE users SET ban_expire = $1 WHERE id = $2" --cache-key-tmpl=cache_clear_user);
auto_method!(update_user_coins(i32)@get_user_by_id -> "UPDATE users SET coins = $1 WHERE id = $2" --cache-key-tmpl=cache_clear_user);
auto_method!(update_user_checkouts(Vec<String>)@get_user_by_id -> "UPDATE users SET checkouts = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
auto_method!(update_user_applied_configurations(Vec<(AppliedConfigType, usize)>)@get_user_by_id -> "UPDATE users SET applied_configurations = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
auto_method!(get_user_by_stripe_id(&str)@get_user_from_row -> "SELECT * FROM users WHERE stripe_id = $1" --name="user" --returns=User);
auto_method!(update_user_stripe_id(&str)@get_user_by_id -> "UPDATE users SET stripe_id = $1 WHERE id = $2" --cache-key-tmpl=cache_clear_user);

View file

@ -8,5 +8,6 @@ CREATE TABLE IF NOT EXISTS products (
on_sale INT NOT NULL,
price INT NOT NULL,
stock INT NOT NULL,
single_use INT NOT NULL
single_use INT NOT NULL,
data TEXT NOT NULL
)

View file

@ -31,5 +31,6 @@ CREATE TABLE IF NOT EXISTS users (
is_deactivated INT NOT NULL,
ban_expire BIGINT NOT NULL,
coins INT NOT NULL,
checkouts TEXT NOT NULL
checkouts TEXT NOT NULL,
applied_configurations TEXT NOT NULL
)

View file

@ -53,3 +53,11 @@ ADD COLUMN IF NOT EXISTS single_use INT DEFAULT 1;
-- transfers source
ALTER TABLE transfers
ADD COLUMN IF NOT EXISTS source TEXT DEFAULT '"General"';
-- products single_use
ALTER TABLE products
ADD COLUMN IF NOT EXISTS data TEXT DEFAULT '';
-- users applied_configurations
ALTER TABLE users
ADD COLUMN IF NOT EXISTS applied_configurations TEXT DEFAULT '[]';

View file

@ -24,6 +24,7 @@ impl DataManager {
price: get!(x->7(i32)),
stock: get!(x->8(i32)),
single_use: get!(x->9(i32)) as i8 == 1,
data: get!(x->10(String)),
}
}
@ -106,7 +107,7 @@ impl DataManager {
let res = execute!(
&conn,
"INSERT INTO products VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
"INSERT INTO products VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
params![
&(data.id as i64),
&(data.created as i64),
@ -118,6 +119,7 @@ impl DataManager {
&data.price,
&(data.stock as i32),
&{ if data.single_use { 1 } else { 0 } },
&data.data,
]
);
@ -219,6 +221,21 @@ If your product is a purchase of goods or services, please be sure to fulfill th
// return
Ok(transfer)
}
ProductFulfillmentMethod::ProfileStyle => {
// pretty much an automail without the message
self.create_transfer(&mut transfer, true).await?;
self.create_letter(Letter::new(
self.0.0.system_user,
vec![customer.id],
format!("Thank you for purchasing \"{}\"", product.title),
"You've purchased a CSS snippet which can be applied to your profile through the product's page!".to_string(),
0,
))
.await?;
Ok(transfer)
}
}
}
@ -253,6 +270,7 @@ If your product is a purchase of goods or services, please be sure to fulfill th
auto_method!(update_product_on_sale(i32)@get_product_by_id:FinePermission::MANAGE_USERS; -> "UPDATE products SET on_sale = $1 WHERE id = $2" --cache-key-tmpl="atto.product:{}");
auto_method!(update_product_method(ProductFulfillmentMethod)@get_product_by_id:FinePermission::MANAGE_USERS; -> "UPDATE products SET method = $1 WHERE id = $2" --serde --cache-key-tmpl="atto.product:{}");
auto_method!(update_product_single_use(i32)@get_product_by_id:FinePermission::MANAGE_USERS; -> "UPDATE products SET single_use = $1 WHERE id = $2" --cache-key-tmpl="atto.product:{}");
auto_method!(update_product_data(&str)@get_product_by_id:FinePermission::MANAGE_USERS; -> "UPDATE products SET data = $1 WHERE id = $2" --cache-key-tmpl="atto.product:{}");
auto_method!(update_product_stock(i32)@get_product_by_id:FinePermission::MANAGE_USERS; -> "UPDATE products SET stock = $1 WHERE id = $2" --cache-key-tmpl="atto.product:{}");
auto_method!(incr_product_stock() -> "UPDATE products SET stock = stock + 1 WHERE id = $1" --cache-key-tmpl="atto.product:{}" --incr);

View file

@ -29,7 +29,14 @@ impl DataManager {
.get(format!("atto.request:{}:{}", id, linked_asset))
.await
{
return Ok(serde_json::from_str(&cached).unwrap());
if let Ok(x) = serde_json::from_str(&cached) {
return Ok(x);
} else {
self.0
.1
.remove(format!("atto.request:{}:{}", id, linked_asset))
.await;
}
}
let conn = match self.0.connect().await {