add: purchased accounts
This commit is contained in:
parent
0aa2ea362f
commit
2ec8d86edf
22 changed files with 1279 additions and 124 deletions
|
@ -192,6 +192,8 @@ pub struct StripeConfig {
|
|||
///
|
||||
/// <https://docs.stripe.com/no-code/customer-portal>
|
||||
pub billing_portal_url: String,
|
||||
/// The text representation of the price of supporter. (like `$4 USD`)
|
||||
pub supporter_price_text: String,
|
||||
}
|
||||
|
||||
/// Manuals config (search help, etc)
|
||||
|
|
|
@ -112,6 +112,8 @@ impl DataManager {
|
|||
invite_code: get!(x->21(i64)) as usize,
|
||||
secondary_permissions: SecondaryPermission::from_bits(get!(x->22(i32)) as u32).unwrap(),
|
||||
achievements: serde_json::from_str(&get!(x->23(String)).to_string()).unwrap(),
|
||||
awaiting_purchase: get!(x->24(i32)) as i8 == 1,
|
||||
was_purchased: get!(x->25(i32)) as i8 == 1,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,7 +269,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)",
|
||||
"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)",
|
||||
params![
|
||||
&(data.id as i64),
|
||||
&(data.created as i64),
|
||||
|
@ -277,7 +279,7 @@ impl DataManager {
|
|||
&serde_json::to_string(&data.settings).unwrap(),
|
||||
&serde_json::to_string(&data.tokens).unwrap(),
|
||||
&(FinePermission::DEFAULT.bits() as i32),
|
||||
&(if data.is_verified { 1_i32 } else { 0_i32 }),
|
||||
&if data.is_verified { 1_i32 } else { 0_i32 },
|
||||
&0_i32,
|
||||
&0_i32,
|
||||
&0_i32,
|
||||
|
@ -293,6 +295,8 @@ impl DataManager {
|
|||
&(data.invite_code as i64),
|
||||
&(SecondaryPermission::DEFAULT.bits() as i32),
|
||||
&serde_json::to_string(&data.achievements).unwrap(),
|
||||
&if data.awaiting_purchase { 1_i32 } else { 0_i32 },
|
||||
&if data.was_purchased { 1_i32 } else { 0_i32 },
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -688,6 +692,52 @@ impl DataManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_user_awaiting_purchased_status(
|
||||
&self,
|
||||
id: usize,
|
||||
x: bool,
|
||||
user: User,
|
||||
require_permission: bool,
|
||||
) -> Result<()> {
|
||||
if (user.id != id) | require_permission {
|
||||
if !user.permissions.check(FinePermission::MANAGE_USERS) {
|
||||
return Err(Error::NotAllowed);
|
||||
}
|
||||
}
|
||||
|
||||
let other_user = self.get_user_by_id(id).await?;
|
||||
|
||||
let conn = match self.0.connect().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
|
||||
};
|
||||
|
||||
let res = execute!(
|
||||
&conn,
|
||||
"UPDATE users SET awaiting_purchase = $1 WHERE id = $2",
|
||||
params![&{ if x { 1 } else { 0 } }, &(id as i64)]
|
||||
);
|
||||
|
||||
if let Err(e) = res {
|
||||
return Err(Error::DatabaseError(e.to_string()));
|
||||
}
|
||||
|
||||
self.cache_clear_user(&other_user).await;
|
||||
|
||||
// create audit log entry
|
||||
self.create_audit_log_entry(AuditLogEntry::new(
|
||||
user.id,
|
||||
format!(
|
||||
"invoked `update_user_purchased_status` with x value `{}` and y value `{}`",
|
||||
other_user.id, x
|
||||
),
|
||||
))
|
||||
.await?;
|
||||
|
||||
// ...
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn seen_user(&self, user: &User) -> Result<()> {
|
||||
let conn = match self.0.connect().await {
|
||||
Ok(c) => c,
|
||||
|
@ -923,6 +973,7 @@ impl DataManager {
|
|||
auto_method!(update_user_connections(UserConnections)@get_user_by_id -> "UPDATE users SET connections = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
|
||||
auto_method!(update_user_associated(Vec<usize>)@get_user_by_id -> "UPDATE users SET associated = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
|
||||
auto_method!(update_user_achievements(Vec<Achievement>)@get_user_by_id -> "UPDATE users SET achievements = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
|
||||
auto_method!(update_user_invite_code(i64)@get_user_by_id -> "UPDATE users SET invite_code = $1 WHERE id = $2" --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);
|
||||
|
|
|
@ -21,5 +21,7 @@ CREATE TABLE IF NOT EXISTS users (
|
|||
grants TEXT NOT NULL,
|
||||
associated TEXT NOT NULL,
|
||||
secondary_permissions INT NOT NULL,
|
||||
achievements TEXT NOT NULL
|
||||
achievements TEXT NOT NULL,
|
||||
awaiting_purchase INT NOT NULL,
|
||||
was_purchased INT NOT NULL
|
||||
)
|
||||
|
|
|
@ -20,8 +20,8 @@ impl DataManager {
|
|||
}
|
||||
}
|
||||
|
||||
auto_method!(get_invite_code_by_id()@get_invite_code_from_row -> "SELECT * FROM invite_codes WHERE id = $1" --name="invite_code" --returns=InviteCode --cache-key-tmpl="atto.invite_code:{}");
|
||||
auto_method!(get_invite_code_by_code(&str)@get_invite_code_from_row -> "SELECT * FROM invite_codes WHERE code = $1" --name="invite_code" --returns=InviteCode);
|
||||
auto_method!(get_invite_code_by_id()@get_invite_code_from_row -> "SELECT * FROM invite_codes WHERE id = $1" --name="invite code" --returns=InviteCode --cache-key-tmpl="atto.invite_code:{}");
|
||||
auto_method!(get_invite_code_by_code(&str)@get_invite_code_from_row -> "SELECT * FROM invite_codes WHERE code = $1" --name="invite code" --returns=InviteCode);
|
||||
|
||||
/// Get invite_codes by `owner`.
|
||||
pub async fn get_invite_codes_by_owner(
|
||||
|
@ -96,23 +96,22 @@ impl DataManager {
|
|||
|
||||
const MAXIMUM_FREE_INVITE_CODES: usize = 4;
|
||||
const MAXIMUM_SUPPORTER_INVITE_CODES: usize = 48;
|
||||
const MINIMUM_ACCOUNT_AGE_FOR_FREE_INVITE_CODES: usize = 2_629_800_000; // 1mo
|
||||
const MINIMUM_ACCOUNT_AGE_FOR_INVITE_CODES: usize = 2_629_800_000; // 1mo
|
||||
|
||||
/// Create a new invite_code in the database.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `data` - a mock [`InviteCode`] object to insert
|
||||
pub async fn create_invite_code(&self, data: InviteCode, user: &User) -> Result<InviteCode> {
|
||||
if !user.permissions.check(FinePermission::SUPPORTER) {
|
||||
// check account creation date
|
||||
if unix_epoch_timestamp() - user.created
|
||||
< Self::MINIMUM_ACCOUNT_AGE_FOR_FREE_INVITE_CODES
|
||||
{
|
||||
return Err(Error::MiscError(
|
||||
"Your account is too young to do this".to_string(),
|
||||
));
|
||||
}
|
||||
// check account creation date
|
||||
if unix_epoch_timestamp() - user.created < Self::MINIMUM_ACCOUNT_AGE_FOR_INVITE_CODES {
|
||||
return Err(Error::MiscError(
|
||||
"Your account is too young to do this".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// ...
|
||||
if !user.permissions.check(FinePermission::SUPPORTER) {
|
||||
// our account is old enough, but we need to make sure we don't already have
|
||||
// 2 invite codes
|
||||
if (self.get_invite_codes_by_owner_count(user.id).await? as usize)
|
||||
|
|
|
@ -61,6 +61,15 @@ pub struct User {
|
|||
/// Users collect achievements through little actions across the site.
|
||||
#[serde(default)]
|
||||
pub achievements: Vec<Achievement>,
|
||||
/// If the account was registered as a "bought" account, the user should not
|
||||
/// be allowed to actually use the account if they haven't paid for supporter yet.
|
||||
#[serde(default)]
|
||||
pub awaiting_purchase: bool,
|
||||
/// This value cannot be changed after account creation. This value is used to
|
||||
/// lock the user's account again if the subscription is cancelled and they haven't
|
||||
/// used an invite code.
|
||||
#[serde(default)]
|
||||
pub was_purchased: bool,
|
||||
}
|
||||
|
||||
pub type UserConnections =
|
||||
|
@ -319,6 +328,8 @@ impl User {
|
|||
invite_code: 0,
|
||||
secondary_permissions: SecondaryPermission::DEFAULT,
|
||||
achievements: Vec::new(),
|
||||
awaiting_purchase: false,
|
||||
was_purchased: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue