You've already forked AstralRinth
forked from didirus/AstralRinth
Switch to Trolley for Modrinth Payments (#727)
* most of trolley * Switch to trolley for payments * run prepare * fix clippy * fix more * Fix most tests + bitflags * Update src/auth/flows.rs Co-authored-by: Jackson Kruger <jak.kruger@gmail.com> * Finish trolley * run prep for merge * Update src/queue/payouts.rs Co-authored-by: Jackson Kruger <jak.kruger@gmail.com> --------- Co-authored-by: Jackson Kruger <jak.kruger@gmail.com>
This commit is contained in:
@@ -8,7 +8,8 @@ use crate::file_hosting::FileHost;
|
||||
use crate::models::ids::base62_impl::{parse_base62, to_base62};
|
||||
use crate::models::ids::random_base62_rng;
|
||||
use crate::models::pats::Scopes;
|
||||
use crate::models::users::{Badges, Role};
|
||||
use crate::models::users::{Badges, RecipientStatus, Role, UserPayoutData};
|
||||
use crate::queue::payouts::{AccountUser, PayoutsQueue};
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::queue::socket::ActiveSockets;
|
||||
use crate::routes::ApiError;
|
||||
@@ -30,7 +31,7 @@ use serde::{Deserialize, Serialize};
|
||||
use sqlx::postgres::PgPool;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use validator::Validate;
|
||||
|
||||
pub fn config(cfg: &mut ServiceConfig) {
|
||||
@@ -51,7 +52,8 @@ pub fn config(cfg: &mut ServiceConfig) {
|
||||
.service(resend_verify_email)
|
||||
.service(set_email)
|
||||
.service(verify_email)
|
||||
.service(subscribe_newsletter),
|
||||
.service(subscribe_newsletter)
|
||||
.service(link_trolley),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -225,9 +227,8 @@ impl TempUser {
|
||||
role: Role::Developer.to_string(),
|
||||
badges: Badges::default(),
|
||||
balance: Decimal::ZERO,
|
||||
payout_wallet: None,
|
||||
payout_wallet_type: None,
|
||||
payout_address: None,
|
||||
trolley_id: None,
|
||||
trolley_account_status: None,
|
||||
}
|
||||
.insert(transaction)
|
||||
.await?;
|
||||
@@ -1013,7 +1014,7 @@ pub async fn auth_callback(
|
||||
|
||||
let sockets = active_sockets.clone();
|
||||
let state = state_string.clone();
|
||||
let res: Result<HttpResponse, AuthenticationError> = (|| async move {
|
||||
let res: Result<HttpResponse, AuthenticationError> = async move {
|
||||
|
||||
let flow = Flow::get(&state, &redis).await?;
|
||||
|
||||
@@ -1175,7 +1176,7 @@ pub async fn auth_callback(
|
||||
} else {
|
||||
Err::<HttpResponse, AuthenticationError>(AuthenticationError::InvalidCredentials)
|
||||
}
|
||||
})().await;
|
||||
}.await;
|
||||
|
||||
// Because this is callback route, if we have an error, we need to ensure we close the original socket if it exists
|
||||
if let Err(ref e) = res {
|
||||
@@ -1385,9 +1386,8 @@ pub async fn create_account_with_password(
|
||||
role: Role::Developer.to_string(),
|
||||
badges: Badges::default(),
|
||||
balance: Decimal::ZERO,
|
||||
payout_wallet: None,
|
||||
payout_wallet_type: None,
|
||||
payout_address: None,
|
||||
trolley_id: None,
|
||||
trolley_account_status: None,
|
||||
}
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
@@ -2011,6 +2011,7 @@ pub async fn set_email(
|
||||
redis: Data<RedisPool>,
|
||||
email: web::Json<SetEmail>,
|
||||
session_queue: Data<AuthQueue>,
|
||||
payouts_queue: Data<Mutex<PayoutsQueue>>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
email
|
||||
.0
|
||||
@@ -2064,6 +2065,17 @@ pub async fn set_email(
|
||||
"We need to verify your email address.",
|
||||
)?;
|
||||
|
||||
if let Some(UserPayoutData {
|
||||
trolley_id: Some(trolley_id),
|
||||
..
|
||||
}) = user.payout_data
|
||||
{
|
||||
let queue = payouts_queue.lock().await;
|
||||
queue
|
||||
.update_recipient_email(&trolley_id, &email.email)
|
||||
.await?;
|
||||
}
|
||||
|
||||
crate::database::models::User::clear_caches(&[(user.id.into(), None)], &redis).await?;
|
||||
transaction.commit().await?;
|
||||
|
||||
@@ -2206,3 +2218,59 @@ fn send_email_verify(
|
||||
Some(("Verify email", &format!("{}/{}?flow={}", dotenvy::var("SITE_URL")?, dotenvy::var("SITE_VERIFY_EMAIL_PATH")?, flow))),
|
||||
)
|
||||
}
|
||||
|
||||
#[post("trolley/link")]
|
||||
pub async fn link_trolley(
|
||||
req: HttpRequest,
|
||||
pool: Data<PgPool>,
|
||||
redis: Data<RedisPool>,
|
||||
session_queue: Data<AuthQueue>,
|
||||
payouts_queue: Data<Mutex<PayoutsQueue>>,
|
||||
body: web::Json<AccountUser>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let user = get_user_from_headers(
|
||||
&req,
|
||||
&**pool,
|
||||
&redis,
|
||||
&session_queue,
|
||||
Some(&[Scopes::PAYOUTS_WRITE]),
|
||||
)
|
||||
.await?
|
||||
.1;
|
||||
|
||||
if let Some(payout_data) = user.payout_data {
|
||||
if payout_data.trolley_id.is_some() {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"User already has a trolley account.".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(email) = user.email {
|
||||
let id = payouts_queue.lock().await.register_recipient(&email, body.0).await?;
|
||||
|
||||
let mut transaction = pool.begin().await?;
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users
|
||||
SET trolley_id = $1, trolley_account_status = $2
|
||||
WHERE id = $3
|
||||
",
|
||||
id,
|
||||
RecipientStatus::Incomplete.as_str(),
|
||||
user.id.0 as i64,
|
||||
)
|
||||
.execute(&mut transaction)
|
||||
.await?;
|
||||
|
||||
transaction.commit().await?;
|
||||
crate::database::models::User::clear_caches(&[(user.id.into(), None)], &redis).await?;
|
||||
|
||||
Ok(HttpResponse::NoContent().finish())
|
||||
} else {
|
||||
Err(ApiError::InvalidInput(
|
||||
"User needs to have an email set on account.".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,16 +56,15 @@ where
|
||||
created: db_user.created,
|
||||
role: Role::from_string(&db_user.role),
|
||||
badges: db_user.badges,
|
||||
payout_data: Some(UserPayoutData {
|
||||
balance: db_user.balance,
|
||||
payout_wallet: db_user.payout_wallet,
|
||||
payout_wallet_type: db_user.payout_wallet_type,
|
||||
payout_address: db_user.payout_address,
|
||||
}),
|
||||
auth_providers: Some(auth_providers),
|
||||
has_password: Some(db_user.password.is_some()),
|
||||
has_totp: Some(db_user.totp_secret.is_some()),
|
||||
github_id: None,
|
||||
payout_data: Some(UserPayoutData {
|
||||
balance: db_user.balance,
|
||||
trolley_id: db_user.trolley_id,
|
||||
trolley_status: db_user.trolley_account_status,
|
||||
}),
|
||||
};
|
||||
|
||||
if let Some(required_scopes) = required_scopes {
|
||||
|
||||
Reference in New Issue
Block a user