From 97dbd854e5dc4a4f42d560362d83146ba975e6e0 Mon Sep 17 00:00:00 2001 From: Fleeym <61891787+Fleeym@users.noreply.github.com> Date: Wed, 4 Dec 2024 23:48:32 +0200 Subject: [PATCH] temp commit --- src/endpoints/mod_versions.rs | 87 ++++++++++++++++++----------- src/types/models/dependency.rs | 29 +++++++--- src/types/models/mod_gd_version.rs | 90 +++++++++++++++++++++++++++++- src/types/models/mod_version.rs | 86 ++++++++++++++++------------ 4 files changed, 212 insertions(+), 80 deletions(-) diff --git a/src/endpoints/mod_versions.rs b/src/endpoints/mod_versions.rs index 834ff34..0877d64 100644 --- a/src/endpoints/mod_versions.rs +++ b/src/endpoints/mod_versions.rs @@ -5,18 +5,21 @@ use serde::Deserialize; use sqlx::{types::ipnetwork::IpNetwork, Acquire}; use crate::{ - extractors::auth::Auth, types::{ + extractors::auth::Auth, + types::{ api::{ApiError, ApiResponse}, mod_json::{split_version_and_compare, ModJson}, models::{ developer::Developer, download, mod_entity::{download_geode_file, Mod}, - mod_gd_version::{GDVersionEnum, VerPlatform}, + mod_gd_version::{add_all_to_gdvec, GDVersionEnum, VerPlatform}, mod_version::{self, ModVersion}, mod_version_status::ModVersionStatusEnum, }, - }, webhook::send_webhook, AppData + }, + webhook::send_webhook, + AppData, }; #[derive(Deserialize)] @@ -92,9 +95,8 @@ pub async fn get_version_index( let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?; let has_extended_permissions = match auth.developer() { - Ok(dev) => dev.admin || - Developer::has_access_to_mod(dev.id, &path.id, &mut pool).await?, - _ => false + Ok(dev) => dev.admin || Developer::has_access_to_mod(dev.id, &path.id, &mut pool).await?, + _ => false, }; let mut result = ModVersion::get_index( @@ -130,20 +132,21 @@ pub async fn get_one( let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?; let has_extended_permissions = match auth.developer() { - Ok(dev) => dev.admin || - Developer::has_access_to_mod(dev.id, &path.id, &mut pool).await?, - _ => false + Ok(dev) => dev.admin || Developer::has_access_to_mod(dev.id, &path.id, &mut pool).await?, + _ => false, }; let mut version = { if path.version == "latest" { - let gd: Option = match query.gd { - Some(ref gd) => Some( - GDVersionEnum::from_str(gd) - .or(Err(ApiError::BadRequest("Invalid gd".to_string())))?, - ), - None => None, - }; + let mut gd = match query.gd { + Some(ref gd) => match GDVersionEnum::from_str(gd) { + Ok(g) => Ok(vec![g]), + Err(_) => Err(ApiError::BadRequest("Invalid gd".to_string())), + }, + None => Ok(vec![]), + }?; + + add_all_to_gdvec(&mut gd); let platform_string = query.platforms.clone().unwrap_or_default(); let platforms = VerPlatform::parse_query_string(&platform_string); @@ -178,10 +181,18 @@ pub async fn download_version( ) -> Result { let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?; let mod_version = { + let mut gd_vec: Vec = Vec::with_capacity(2); + + if let Some(gd) = query.gd { + gd_vec.push(gd); + } + + add_all_to_gdvec(&mut gd_vec); + + let platform_str = query.platforms.clone().unwrap_or_default(); + let platforms = VerPlatform::parse_query_string(&platform_str); if path.version == "latest" { - let platform_str = query.platforms.clone().unwrap_or_default(); - let platforms = VerPlatform::parse_query_string(&platform_str); - ModVersion::get_latest_for_mod(&path.id, query.gd, platforms, query.major, &mut pool) + ModVersion::get_latest_for_mod(&path.id, gd_vec, platforms, query.major, &mut pool) .await? } else { ModVersion::get_one(&path.id, &path.version, false, false, &mut pool).await? @@ -202,16 +213,18 @@ pub async fn download_version( }; let net: IpNetwork = ip.parse().or(Err(ApiError::InternalError))?; - if let Ok((downloaded_version, downloaded_mod)) = download::create_download( - net, mod_version.id, &mod_version.mod_id, &mut pool - ).await { + if let Ok((downloaded_version, downloaded_mod)) = + download::create_download(net, mod_version.id, &mod_version.mod_id, &mut pool).await + { let name = mod_version.mod_id.clone(); let version = mod_version.version.clone(); // only accepted mods can have their download counts incremented // we'll just fix this once they're updated anyways - if (downloaded_version || downloaded_mod) && mod_version.status == ModVersionStatusEnum::Accepted { + if (downloaded_version || downloaded_mod) + && mod_version.status == ModVersionStatusEnum::Accepted + { tokio::spawn(async move { if downloaded_version { // we must nest more @@ -264,8 +277,11 @@ pub async fn create_version( } // remove invalid characters from link - they break the location header on download - let download_link: String = payload.download_link.chars() - .filter(|c| c.is_ascii() && *c != '\0').collect(); + let download_link: String = payload + .download_link + .chars() + .filter(|c| c.is_ascii() && *c != '\0') + .collect(); let mut file_path = download_geode_file(&download_link).await?; let json = ModJson::from_zip(&mut file_path, &download_link, dev.verified) @@ -283,10 +299,15 @@ pub async fn create_version( json.name.clone(), json.version.clone(), true, - Developer { id: dev.id, username: dev.username.clone(), display_name: dev.display_name.clone(), is_owner: true }, + Developer { + id: dev.id, + username: dev.username.clone(), + display_name: dev.display_name.clone(), + is_owner: true, + }, dev.clone(), data.webhook_url.clone(), - data.app_url.clone() + data.app_url.clone(), ) .await; } @@ -324,8 +345,9 @@ pub async fn update_version( path.version.as_str(), false, false, - &mut pool - ).await?; + &mut pool, + ) + .await?; let approved_count = ModVersion::get_accepted_count(version.mod_id.as_str(), &mut pool).await?; let mut transaction = pool.begin().await.or(Err(ApiError::TransactionError))?; let id = match sqlx::query!( @@ -365,7 +387,7 @@ pub async fn update_version( .commit() .await .or(Err(ApiError::TransactionError))?; - + if payload.status == ModVersionStatusEnum::Accepted { let is_update = approved_count > 0; @@ -382,8 +404,9 @@ pub async fn update_version( owner.as_ref().unwrap().clone(), dev.clone(), data.webhook_url.clone(), - data.app_url.clone() - ).await; + data.app_url.clone(), + ) + .await; } Ok(HttpResponse::NoContent()) diff --git a/src/types/models/dependency.rs b/src/types/models/dependency.rs index c4ba26a..737182b 100644 --- a/src/types/models/dependency.rs +++ b/src/types/models/dependency.rs @@ -3,7 +3,7 @@ use std::{collections::HashMap, fmt::Display}; use serde::{Deserialize, Serialize}; use sqlx::{PgConnection, Postgres, QueryBuilder}; -use crate::types::api::ApiError; +use crate::types::{api::ApiError, models::mod_gd_version::add_all_to_gdvec}; use super::mod_gd_version::{GDVersionEnum, VerPlatform}; @@ -130,8 +130,8 @@ impl Dependency { pub async fn get_for_mod_versions( ids: &Vec, - platform: Option, - gd: Option, + platforms: Vec, + gd: Vec, geode: Option<&semver::Version>, pool: &mut PgConnection, ) -> Result>, ApiError> { @@ -145,6 +145,17 @@ impl Dependency { dependency: String, importance: DependencyImportance, } + + let mut gd = gd; + add_all_to_gdvec(&mut gd); + + let platforms = { + if !platforms.is_empty() { + platforms + } else { + VerPlatform::all_platforms() + } + }; let q = sqlx::query_as::( r#" @@ -176,8 +187,8 @@ impl Dependency { INNER JOIN mod_version_statuses dpcy_status ON dpcy_version.status_id = dpcy_status.id WHERE dpcy_status.status = 'accepted' AND mv.id = ANY($1) - AND ($2 IS NULL OR dpcy_mgv.gd = $2 OR dpcy_mgv.gd = '*') - AND ($3 IS NULL OR dpcy_mgv.platform = $3) + AND dpcy_mgv.gd = ANY($2) + AND dpcy_mgv.platform = ANY($3) AND ($4 IS NULL OR ( CASE WHEN SPLIT_PART($4, '-', 2) ILIKE 'alpha%' THEN $4 = dpcy_version.geode @@ -230,8 +241,8 @@ impl Dependency { INNER JOIN mod_version_statuses dpcy_status2 ON dpcy_version2.status_id = dpcy_status2.id INNER JOIN dep_tree dt ON dt.dependency_vid = mv2.id WHERE dpcy_status2.status = 'accepted' - AND ($2 IS NULL OR dpcy_mgv2.gd = $2 OR dpcy_mgv2.gd = '*') - AND ($3 IS NULL OR dpcy_mgv2.platform = $3) + AND dpcy_mgv2.gd = ANY($2) + AND dpcy_mgv2.platform = ANY($3) AND ($4 IS NULL OR ( CASE WHEN SPLIT_PART($4, '-', 2) ILIKE 'alpha%' THEN $4 = dpcy_version2.geode @@ -260,8 +271,8 @@ impl Dependency { SELECT * FROM dep_tree; "#, ).bind(ids) - .bind(gd) - .bind(platform) + .bind(&gd) + .bind(&platforms) .bind(geode.map(|x| x.to_string())); let result = match q.fetch_all(&mut *pool).await { diff --git a/src/types/models/mod_gd_version.rs b/src/types/models/mod_gd_version.rs index 5577bcf..e32781f 100644 --- a/src/types/models/mod_gd_version.rs +++ b/src/types/models/mod_gd_version.rs @@ -4,11 +4,14 @@ use std::{ }; use serde::{Deserialize, Serialize}; -use sqlx::{PgConnection, Postgres, QueryBuilder}; +use sqlx::{ + postgres::{PgHasArrayType, PgTypeInfo}, + PgConnection, Postgres, QueryBuilder, +}; use crate::types::{api::ApiError, mod_json::ModJson}; -#[derive(sqlx::Type, Debug, Deserialize, Serialize, Clone, Copy)] +#[derive(sqlx::Type, Debug, Deserialize, Serialize, Clone, Copy, PartialEq)] #[sqlx(type_name = "gd_version")] pub enum GDVersionEnum { #[serde(rename = "*")] @@ -46,6 +49,12 @@ pub enum GDVersionEnum { GD22074, } +impl PgHasArrayType for GDVersionEnum { + fn array_type_info() -> PgTypeInfo { + PgTypeInfo::with_name("gd_version[]") + } +} + impl FromStr for GDVersionEnum { type Err = (); fn from_str(s: &str) -> Result { @@ -86,6 +95,12 @@ pub enum VerPlatform { Win, } +impl PgHasArrayType for VerPlatform { + fn array_type_info() -> sqlx::postgres::PgTypeInfo { + PgTypeInfo::with_name("gd_ver_platform[]") + } +} + impl FromStr for VerPlatform { type Err = (); fn from_str(s: &str) -> Result { @@ -106,6 +121,16 @@ impl FromStr for VerPlatform { } impl VerPlatform { + pub fn all_platforms() -> Vec { + vec![ + VerPlatform::Android32, + VerPlatform::Android64, + VerPlatform::Win, + VerPlatform::MacArm, + VerPlatform::MacIntel, + ] + } + pub fn parse_query_string(s: &str) -> Vec { let mut ret = vec![]; if s.is_empty() { @@ -163,6 +188,58 @@ pub struct DetailedGDVersion { } impl DetailedGDVersion { + pub fn to_platform_vec(&self) -> Vec { + let mut ret = Vec::with_capacity(6); + + if self.android32.is_some() { + ret.push(VerPlatform::Android32); + } + + if self.android64.is_some() { + ret.push(VerPlatform::Android64); + } + + if self.win.is_some() { + ret.push(VerPlatform::Win); + } + + if self.mac_arm.is_some() { + ret.push(VerPlatform::MacArm); + } + + if self.mac_intel.is_some() { + ret.push(VerPlatform::MacIntel); + } + + ret + } + + pub fn to_vec(&self) -> Vec { + let mut ret = Vec::with_capacity(6); + + if let Some(v) = self.android32 { + ret.push(v); + } + + if let Some(v) = self.android64 { + ret.push(v); + } + + if let Some(v) = self.win { + ret.push(v); + } + + if let Some(v) = self.mac_arm { + ret.push(v); + } + + if let Some(v) = self.mac_intel { + ret.push(v); + } + + ret + } + pub fn to_create_payload(&self, json: &ModJson) -> Vec { let mut ret: Vec<_> = vec![]; if self.android.is_some() { @@ -371,6 +448,15 @@ impl ModGDVersion { } } +pub fn add_all_to_gdvec(v: &mut Vec) { + for i in v.iter() { + if *i == GDVersionEnum::All { + return; + } + } + v.push(GDVersionEnum::All); +} + fn check_for_duplicate_platforms(versions: &Vec) -> Result<(), String> { let mut found: HashMap = HashMap::new(); for i in versions { diff --git a/src/types/models/mod_version.rs b/src/types/models/mod_version.rs index f647257..b2bfa31 100644 --- a/src/types/models/mod_version.rs +++ b/src/types/models/mod_version.rs @@ -5,13 +5,13 @@ use semver::Version; use serde::Serialize; use sqlx::{ types::chrono::{DateTime, Utc}, - PgConnection, Postgres, QueryBuilder, Row + PgConnection, Postgres, QueryBuilder, Row, }; use crate::types::{ api::{create_download_link, ApiError, PaginatedData}, mod_json::ModJson, - models::{mod_entity::Mod, download}, + models::{download, mod_entity::Mod}, }; use super::{ @@ -116,8 +116,12 @@ impl ModVersionGetOne { incompatibilities: None, info: self.info, direct_download_link: None, - created_at: self.created_at.map(|x| x.to_rfc3339_opts(SecondsFormat::Secs, true)), - updated_at: self.updated_at.map(|x| x.to_rfc3339_opts(SecondsFormat::Secs, true)), + created_at: self + .created_at + .map(|x| x.to_rfc3339_opts(SecondsFormat::Secs, true)), + updated_at: self + .updated_at + .map(|x| x.to_rfc3339_opts(SecondsFormat::Secs, true)), } } } @@ -261,7 +265,8 @@ impl ModVersion { } let version_ids: Vec = records.iter().map(|x| x.id).collect(); - let deps = Dependency::get_for_mod_versions(&version_ids, None, None, None, pool).await?; + let deps = + Dependency::get_for_mod_versions(&version_ids, vec![], vec![], None, pool).await?; let incompat = Incompatibility::get_for_mod_versions(&version_ids, None, None, None, pool).await?; @@ -443,7 +448,7 @@ impl ModVersion { pub async fn get_latest_for_mod( id: &str, - gd: Option, + gd: Vec, platforms: Vec, major: Option, pool: &mut PgConnection, @@ -469,24 +474,25 @@ impl ModVersion { query_builder.push(" AND mv.version LIKE "); query_builder.push_bind(major_ver); } - if let Some(g) = gd { - query_builder.push(" AND (mgv.gd = "); - query_builder.push_bind(g); - query_builder.push(" OR mgv.gd = "); - query_builder.push_bind(GDVersionEnum::All); + + if !gd.is_empty() { + query_builder.push(" AND mgv.gd IN ("); + let mut separated = query_builder.separated(", "); + for i in gd.iter() { + separated.push_bind(*i); + } query_builder.push(")"); } - for (i, platform) in platforms.iter().enumerate() { - if i == 0 { - query_builder.push(" AND mgv.platform IN ("); - } - query_builder.push_bind(*platform); - if i == platforms.len() - 1 { - query_builder.push(")"); - } else { - query_builder.push(", "); + + if !platforms.is_empty() { + query_builder.push(" AND mgv.platform IN ("); + let mut separated = query_builder.separated(", "); + for platform in platforms.iter() { + separated.push_bind(*platform); } + query_builder.push(")"); } + query_builder.push(" AND mv.mod_id = "); query_builder.push_bind(id); query_builder.push(") q WHERE q.rn = 1"); @@ -508,7 +514,7 @@ impl ModVersion { let ids: Vec = vec![version.id]; version.gd = ModGDVersion::get_for_mod_version(version.id, pool).await?; version.dependencies = Some( - Dependency::get_for_mod_versions(&ids, None, None, None, pool) + Dependency::get_for_mod_versions(&ids, platforms, gd, None, pool) .await? .get(&version.id) .cloned() @@ -664,15 +670,22 @@ impl ModVersion { if fetch_extras { version.gd = ModGDVersion::get_for_mod_version(version.id, pool).await?; let ids = vec![version.id]; + let geode = semver::Version::parse(version.geode.as_str()).ok(); version.dependencies = Some( - Dependency::get_for_mod_versions(&ids, None, None, None, pool) - .await? - .get(&version.id) - .cloned() - .unwrap_or_default() - .into_iter() - .map(|x| x.to_response()) - .collect(), + Dependency::get_for_mod_versions( + &ids, + version.gd.to_platform_vec(), + version.gd.to_vec(), + geode.as_ref(), + pool, + ) + .await? + .get(&version.id) + .cloned() + .unwrap_or_default() + .into_iter() + .map(|x| x.to_response()) + .collect(), ); let incompat = Incompatibility::get_for_mod_version(version.id, pool).await?; version.incompatibilities = @@ -697,7 +710,8 @@ impl ModVersion { mod_version_id ) .execute(&mut *pool) - .await { + .await + { log::error!("{}", e); return Err(ApiError::DbError); } @@ -719,7 +733,8 @@ impl ModVersion { mod_version_id ) .execute(&mut *pool) - .await { + .await + { log::error!("{}", e); return Err(ApiError::DbError); } @@ -790,12 +805,9 @@ impl ModVersion { // should probably spawn this, but we do a download in the transaction which is probably // a little worse. idk - let info = match sqlx::query!( - "SELECT mod_id FROM mod_versions WHERE id = $1", - id - ) - .fetch_one(&mut *pool) - .await + let info = match sqlx::query!("SELECT mod_id FROM mod_versions WHERE id = $1", id) + .fetch_one(&mut *pool) + .await { Err(e) => { log::error!("{}", e);