You've already forked AstralRinth
forked from didirus/AstralRinth
Credit subscriptions (#4575)
* Implement subscription crediting * chore: query cache, clippy, fmt * Improve code, improve query for next open charge * chore: query cache, clippy, fmt * Move server ID copy button up * Node + region crediting * Make it less ugly * chore: query cache, clippy, fmt * Bugfixes * Fix lint * Adjust migration * Adjust migration * Remove billing change * Move DEFAULT_CREDIT_EMAIL_MESSAGE to utils.ts * Lint * Merge * bump clickhouse, disable validation * tombi fmt * Update cargo lock
This commit is contained in:
committed by
GitHub
parent
79502a19d6
commit
eeed4e572d
@@ -233,7 +233,10 @@ impl DBCharge {
|
||||
) -> Result<Option<DBCharge>, DatabaseError> {
|
||||
let user_subscription_id = user_subscription_id.0;
|
||||
let res = select_charges_with_predicate!(
|
||||
"WHERE subscription_id = $1 AND (status = 'open' OR status = 'expiring' OR status = 'cancelled' OR status = 'failed')",
|
||||
"WHERE
|
||||
subscription_id = $1
|
||||
AND (status = 'open' OR status = 'expiring' OR status = 'cancelled' OR status = 'failed')
|
||||
ORDER BY due ASC LIMIT 1",
|
||||
user_subscription_id
|
||||
)
|
||||
.fetch_optional(exec)
|
||||
|
||||
@@ -35,6 +35,7 @@ pub mod user_subscription_item;
|
||||
pub mod users_compliance;
|
||||
pub mod users_notifications_preferences_item;
|
||||
pub mod users_redeemals;
|
||||
pub mod users_subscriptions_credits;
|
||||
pub mod version_item;
|
||||
|
||||
pub use affiliate_code_item::DBAffiliateCode;
|
||||
|
||||
@@ -160,6 +160,32 @@ impl DBUserSubscription {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_many_by_server_ids(
|
||||
server_ids: &[String],
|
||||
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
||||
) -> Result<Vec<DBUserSubscription>, DatabaseError> {
|
||||
if server_ids.is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let results = sqlx::query_as!(
|
||||
UserSubscriptionQueryResult,
|
||||
r#"
|
||||
SELECT us.id, us.user_id, us.price_id, us.interval, us.created, us.status, us.metadata
|
||||
FROM users_subscriptions us
|
||||
WHERE us.metadata->>'type' = 'pyro' AND us.metadata->>'id' = ANY($1::text[])
|
||||
"#,
|
||||
server_ids
|
||||
)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
|
||||
Ok(results
|
||||
.into_iter()
|
||||
.map(|r| r.try_into())
|
||||
.collect::<Result<Vec<_>, serde_json::Error>>()?)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SubscriptionWithCharge {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
use crate::database::models::{DBUserId, DBUserSubscriptionId};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::query_scalar;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DBUserSubscriptionCredit {
|
||||
pub id: i32,
|
||||
pub subscription_id: DBUserSubscriptionId,
|
||||
pub user_id: DBUserId,
|
||||
pub creditor_id: DBUserId,
|
||||
pub days: i32,
|
||||
pub previous_due: DateTime<Utc>,
|
||||
pub next_due: DateTime<Utc>,
|
||||
pub created: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl DBUserSubscriptionCredit {
|
||||
/// Inserts this audit entry and sets its id.
|
||||
pub async fn insert<'a, E>(&mut self, exec: E) -> sqlx::Result<()>
|
||||
where
|
||||
E: sqlx::PgExecutor<'a>,
|
||||
{
|
||||
let id = query_scalar!(
|
||||
r#"
|
||||
INSERT INTO users_subscriptions_credits
|
||||
(subscription_id, user_id, creditor_id, days, previous_due, next_due)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING id
|
||||
"#,
|
||||
self.subscription_id.0,
|
||||
self.user_id.0,
|
||||
self.creditor_id.0,
|
||||
self.days,
|
||||
self.previous_due,
|
||||
self.next_due,
|
||||
)
|
||||
.fetch_one(exec)
|
||||
.await?;
|
||||
|
||||
self.id = id;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn insert_many(
|
||||
exec: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
subscription_ids: &[DBUserSubscriptionId],
|
||||
user_ids: &[DBUserId],
|
||||
creditor_ids: &[DBUserId],
|
||||
days: &[i32],
|
||||
previous_dues: &[DateTime<Utc>],
|
||||
next_dues: &[DateTime<Utc>],
|
||||
) -> sqlx::Result<()> {
|
||||
debug_assert_eq!(subscription_ids.len(), user_ids.len());
|
||||
debug_assert_eq!(user_ids.len(), creditor_ids.len());
|
||||
debug_assert_eq!(creditor_ids.len(), days.len());
|
||||
debug_assert_eq!(days.len(), previous_dues.len());
|
||||
debug_assert_eq!(previous_dues.len(), next_dues.len());
|
||||
|
||||
let subs: Vec<i64> = subscription_ids.iter().map(|x| x.0).collect();
|
||||
let users: Vec<i64> = user_ids.iter().map(|x| x.0).collect();
|
||||
let creditors: Vec<i64> = creditor_ids.iter().map(|x| x.0).collect();
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO users_subscriptions_credits
|
||||
(subscription_id, user_id, creditor_id, days, previous_due, next_due)
|
||||
SELECT * FROM UNNEST($1::bigint[], $2::bigint[], $3::bigint[], $4::int[], $5::timestamptz[], $6::timestamptz[])
|
||||
"#,
|
||||
&subs[..],
|
||||
&users[..],
|
||||
&creditors[..],
|
||||
&days[..],
|
||||
&previous_dues[..],
|
||||
&next_dues[..],
|
||||
)
|
||||
.execute(&mut **exec)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user