You've already forked AstralRinth
forked from didirus/AstralRinth
Fix payouts desync (#890)
* Fix payouts desync * fix tests + user payouts req
This commit is contained in:
15
.sqlx/query-e1c24a57013cbc64f463d3a49cb68989eced49b475c0bbab90b21908ae0e77b4.json
generated
Normal file
15
.sqlx/query-e1c24a57013cbc64f463d3a49cb68989eced49b475c0bbab90b21908ae0e77b4.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE users u\n SET balance = u.balance + v.amount\n FROM unnest($1::BIGINT[], $2::NUMERIC[]) AS v(id, amount)\n WHERE u.id = v.id\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8Array",
|
||||
"NumericArray"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e1c24a57013cbc64f463d3a49cb68989eced49b475c0bbab90b21908ae0e77b4"
|
||||
}
|
||||
@@ -726,7 +726,7 @@ pub async fn process_payout(
|
||||
let mut clear_cache_users = Vec::new();
|
||||
let (mut insert_user_ids, mut insert_project_ids, mut insert_payouts, mut insert_starts) =
|
||||
(Vec::new(), Vec::new(), Vec::new(), Vec::new());
|
||||
let (mut update_user_ids, mut update_user_balances) = (Vec::new(), Vec::new());
|
||||
let mut update_user_balance: HashMap<i64, Decimal> = HashMap::new();
|
||||
for (id, project) in projects_map {
|
||||
if let Some(value) = &multipliers.values.get(&(id as u64)) {
|
||||
let project_multiplier: Decimal =
|
||||
@@ -744,8 +744,7 @@ pub async fn process_payout(
|
||||
insert_payouts.push(payout);
|
||||
insert_starts.push(start);
|
||||
|
||||
update_user_ids.push(user_id);
|
||||
update_user_balances.push(payout);
|
||||
*update_user_balance.entry(user_id).or_default() += payout;
|
||||
|
||||
clear_cache_users.push(user_id);
|
||||
}
|
||||
@@ -754,16 +753,23 @@ pub async fn process_payout(
|
||||
}
|
||||
}
|
||||
|
||||
sqlx::query(
|
||||
let (mut update_user_ids, mut update_user_balances) = (Vec::new(), Vec::new());
|
||||
|
||||
for (user_id, payout) in update_user_balance {
|
||||
update_user_ids.push(user_id);
|
||||
update_user_balances.push(payout);
|
||||
}
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users u
|
||||
SET balance = u.balance + v.amount
|
||||
FROM unnest($1::BIGINT[], $2::NUMERIC[]) AS v(id, amount)
|
||||
WHERE u.id = v.id
|
||||
",
|
||||
&update_user_ids,
|
||||
&update_user_balances
|
||||
)
|
||||
.bind(&update_user_ids)
|
||||
.bind(&update_user_balances)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -14,12 +14,6 @@ use sqlx::PgPool;
|
||||
use validator::Validate;
|
||||
|
||||
use super::ApiError;
|
||||
use crate::{
|
||||
auth::checks::ValidateAllAuthorized,
|
||||
file_hosting::FileHost,
|
||||
models::{ids::base62_impl::parse_base62, oauth_clients::DeleteOAuthClientQueryParam},
|
||||
util::routes::read_from_payload,
|
||||
};
|
||||
use crate::{
|
||||
auth::{checks::ValidateAuthorized, get_user_from_headers},
|
||||
database::{
|
||||
@@ -40,6 +34,11 @@ use crate::{
|
||||
routes::v3::project_creation::CreateError,
|
||||
util::validate::validation_errors_to_string,
|
||||
};
|
||||
use crate::{
|
||||
file_hosting::FileHost,
|
||||
models::{ids::base62_impl::parse_base62, oauth_clients::DeleteOAuthClientQueryParam},
|
||||
util::routes::read_from_payload,
|
||||
};
|
||||
|
||||
use crate::database::models::oauth_client_item::OAuthClient as DBOAuthClient;
|
||||
use crate::models::ids::OAuthClientId as ApiOAuthClientId;
|
||||
@@ -80,10 +79,13 @@ pub async fn get_user_clients(
|
||||
let target_user = User::get(&info.into_inner(), &**pool, &redis).await?;
|
||||
|
||||
if let Some(target_user) = target_user {
|
||||
if target_user.id != current_user.id.into() && !current_user.role.is_admin() {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You do not have permission to see the OAuth clients of this user!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let clients = OAuthClient::get_all_user_clients(target_user.id, &**pool).await?;
|
||||
clients
|
||||
.iter()
|
||||
.validate_all_authorized(Some(¤t_user))?;
|
||||
|
||||
let response = clients
|
||||
.into_iter()
|
||||
@@ -98,13 +100,10 @@ pub async fn get_user_clients(
|
||||
|
||||
#[get("app/{id}")]
|
||||
pub async fn get_client(
|
||||
req: HttpRequest,
|
||||
id: web::Path<ApiOAuthClientId>,
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let clients = get_clients_inner(&[id.into_inner()], req, pool, redis, session_queue).await?;
|
||||
let clients = get_clients_inner(&[id.into_inner()], pool).await?;
|
||||
if let Some(client) = clients.into_iter().next() {
|
||||
Ok(HttpResponse::Ok().json(client))
|
||||
} else {
|
||||
@@ -114,11 +113,8 @@ pub async fn get_client(
|
||||
|
||||
#[get("apps")]
|
||||
pub async fn get_clients(
|
||||
req: HttpRequest,
|
||||
info: web::Query<GetOAuthClientsRequest>,
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let ids: Vec<_> = info
|
||||
.ids
|
||||
@@ -126,7 +122,7 @@ pub async fn get_clients(
|
||||
.map(|id| parse_base62(id).map(ApiOAuthClientId))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let clients = get_clients_inner(&ids, req, pool, redis, session_queue).await?;
|
||||
let clients = get_clients_inner(&ids, pool).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(clients))
|
||||
}
|
||||
@@ -583,26 +579,10 @@ async fn edit_redirects(
|
||||
|
||||
pub async fn get_clients_inner(
|
||||
ids: &[ApiOAuthClientId],
|
||||
req: HttpRequest,
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<RedisPool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<Vec<models::oauth_clients::OAuthClient>, ApiError> {
|
||||
let current_user = get_user_from_headers(
|
||||
&req,
|
||||
&**pool,
|
||||
&redis,
|
||||
&session_queue,
|
||||
Some(&[Scopes::SESSION_ACCESS]),
|
||||
)
|
||||
.await?
|
||||
.1;
|
||||
|
||||
let ids: Vec<OAuthClientId> = ids.iter().map(|i| (*i).into()).collect();
|
||||
let clients = OAuthClient::get_many(&ids, &**pool).await?;
|
||||
clients
|
||||
.iter()
|
||||
.validate_all_authorized(Some(¤t_user))?;
|
||||
|
||||
Ok(clients.into_iter().map(|c| c.into()).collect_vec())
|
||||
}
|
||||
|
||||
@@ -112,21 +112,6 @@ async fn get_oauth_client_for_client_creator_succeeds() {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn get_oauth_client_for_unrelated_user_fails() {
|
||||
with_test_environment(None, |env: TestEnvironment<ApiV3>| async move {
|
||||
let DummyOAuthClientAlpha { client_id, .. } = env.dummy.oauth_client_alpha.clone();
|
||||
|
||||
let resp = env
|
||||
.api
|
||||
.get_oauth_client(client_id.clone(), FRIEND_USER_PAT)
|
||||
.await;
|
||||
|
||||
assert_status!(&resp, StatusCode::UNAUTHORIZED);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn can_delete_oauth_client() {
|
||||
with_test_environment(None, |env: TestEnvironment<ApiV3>| async move {
|
||||
|
||||
Reference in New Issue
Block a user