From f9c89ae3922d9987d5342d7e0a82707e9e7a7226 Mon Sep 17 00:00:00 2001 From: Chloe <25387744+qimiko@users.noreply.github.com> Date: Sat, 23 Nov 2024 05:14:07 -0700 Subject: [PATCH] impl get many for loader version --- src/endpoints/loader.rs | 68 +++++++++++++++++++----- src/main.rs | 1 + src/types/models/loader_version.rs | 84 ++++++++++++++++++++++++++++-- 3 files changed, 137 insertions(+), 16 deletions(-) diff --git a/src/endpoints/loader.rs b/src/endpoints/loader.rs index 5e9565d..bcd609c 100644 --- a/src/endpoints/loader.rs +++ b/src/endpoints/loader.rs @@ -10,7 +10,12 @@ use crate::{ api::{ApiError, ApiResponse}, models::{ gd_version_alias::GDVersionAlias, - loader_version::{LoaderVersion, LoaderVersionCreate}, + loader_version::{ + LoaderVersion, + LoaderVersionCreate, + LoaderGDVersion, + GetVersionsQuery + }, mod_gd_version::{GDVersionEnum, VerPlatform} } }, @@ -19,7 +24,7 @@ use crate::{ #[derive(Deserialize)] struct GetOneQuery { - platform: Option, + platform: Option, gd: Option, #[serde(default)] prerelease: bool, @@ -39,17 +44,11 @@ pub async fn get_one( let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?; let version = if path.version == "latest" { - let platform = query.platform.as_ref() - .map(|s| VerPlatform::from_str(s)) - .transpose() - .map_err(|_| ApiError::BadRequest("Invalid platform".to_string()))?; - - let gd = if let Some(i) = &query.gd { if let Ok(g) = GDVersionEnum::from_str(i) { Some(g) } else { - let platform = platform + let platform = query.platform .ok_or_else(|| ApiError::BadRequest("Platform is required when a version alias is given".to_string()))?; Some(GDVersionAlias::find(platform, i, &mut pool).await?) } @@ -57,7 +56,7 @@ pub async fn get_one( None }; - LoaderVersion::get_latest(gd, platform, query.prerelease, &mut pool).await? + LoaderVersion::get_latest(gd, query.platform, query.prerelease, &mut pool).await? } else { LoaderVersion::get_one(&path.version, &mut pool).await? }; @@ -68,10 +67,18 @@ pub async fn get_one( })) } +#[derive(Deserialize)] +struct CreateVersionBody { + pub tag: String, + pub gd: LoaderGDVersion, + #[serde(default)] + pub prerelease: bool +} + #[post("v1/loader/versions")] pub async fn create_version( data: web::Data, - payload: web::Json, + payload: web::Json, auth: Auth, ) -> Result { let dev = auth.developer()?; @@ -82,7 +89,11 @@ pub async fn create_version( } let mut transaction = pool.begin().await.or(Err(ApiError::TransactionError))?; - if let Err(e) = LoaderVersion::create_version(payload.into_inner(), &mut transaction).await { + if let Err(e) = LoaderVersion::create_version(LoaderVersionCreate { + tag: payload.tag.clone(), + gd: payload.gd.clone(), + prerelease: payload.prerelease + }, &mut transaction).await { transaction .rollback() .await @@ -97,3 +108,36 @@ pub async fn create_version( Ok(HttpResponse::NoContent()) } + +#[derive(Deserialize)] +struct GetManyQuery { + pub gd: Option, + pub platform: Option, + pub per_page: Option, + pub page: Option, + pub prerelease: Option +} + +#[get("v1/loader/versions")] +pub async fn get_many( + data: web::Data, + query: web::Query, +) -> Result { + let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?; + + let versions = LoaderVersion::get_many( + GetVersionsQuery { + gd: query.gd, + platform: query.platform, + prerelease: query.prerelease.unwrap_or(true) + }, + query.per_page.unwrap_or(10), + query.page.unwrap_or(1), + &mut pool + ).await?; + + Ok(web::Json(ApiResponse { + error: "".to_string(), + payload: versions, + })) +} diff --git a/src/main.rs b/src/main.rs index acd434f..1e38156 100644 --- a/src/main.rs +++ b/src/main.rs @@ -128,6 +128,7 @@ async fn main() -> anyhow::Result<()> { .service(endpoints::stats::get_stats) .service(endpoints::loader::get_one) .service(endpoints::loader::create_version) + .service(endpoints::loader::get_many) .service(health) }) .bind((addr, port))?; diff --git a/src/types/models/loader_version.rs b/src/types/models/loader_version.rs index d492965..69b201a 100644 --- a/src/types/models/loader_version.rs +++ b/src/types/models/loader_version.rs @@ -7,21 +7,21 @@ use chrono::SecondsFormat; use serde::{Deserialize, Serialize}; use sqlx::{ - types::chrono::{DateTime, Utc}, PgConnection, Postgres, QueryBuilder + types::chrono::{DateTime, Utc}, + PgConnection, Postgres, QueryBuilder }; -#[derive(sqlx::FromRow, Deserialize, Serialize, Debug)] +#[derive(sqlx::FromRow, Deserialize, Serialize, Debug, Clone)] pub struct LoaderGDVersion { pub win: Option, pub android: Option, pub mac: Option, } -#[derive(Deserialize, Debug)] +#[derive(Debug)] pub struct LoaderVersionCreate { pub tag: String, pub gd: LoaderGDVersion, - #[serde(default)] pub prerelease: bool } @@ -42,6 +42,12 @@ pub struct LoaderVersionGetOne { pub created_at: DateTime } +pub struct GetVersionsQuery { + pub gd: Option, + pub platform: Option, + pub prerelease: bool +} + impl LoaderVersionGetOne { pub fn into_loader_version(self) -> LoaderVersion { LoaderVersion { @@ -175,4 +181,74 @@ impl LoaderVersion { } } } + + pub async fn get_many( + query: GetVersionsQuery, + per_page: i64, + page: i64, + pool: &mut PgConnection + ) -> Result, ApiError> { + let limit = per_page; + let offset = (page - 1) * per_page; + + let mut query_builder = QueryBuilder::new(r#" + SELECT mac, win, android, tag, created_at, prerelease FROM geode_versions + "#); + + match (query.platform, query.gd) { + (Some(p), Some(g)) => { + match p { + VerPlatform::Android | VerPlatform::Android32 | VerPlatform::Android64 => query_builder.push(" WHERE android="), + VerPlatform::Mac | VerPlatform::MacIntel | VerPlatform::MacArm => query_builder.push(" WHERE mac="), + VerPlatform::Win => query_builder.push(" WHERE win="), + _ => return Err(ApiError::BadRequest("Invalid platform".to_string())), + }; + + query_builder.push_bind(g); + } + (Some(p), None) => { + match p { + VerPlatform::Android | VerPlatform::Android32 | VerPlatform::Android64 => query_builder.push(" WHERE android IS NOT NULL"), + VerPlatform::Mac | VerPlatform::MacIntel | VerPlatform::MacArm => query_builder.push(" WHERE mac IS NOT NULL"), + VerPlatform::Win => query_builder.push(" WHERE win IS NOT NULL"), + _ => return Err(ApiError::BadRequest("Invalid platform".to_string())), + }; + } + (None, Some(g)) => { + query_builder.push(" WHERE android="); + query_builder.push_bind(g); + query_builder.push(" or mac="); + query_builder.push_bind(g); + query_builder.push(" or win="); + query_builder.push_bind(g); + } + _ => { + query_builder.push(" WHERE 1=1"); + } + } + + if !query.prerelease { + query_builder.push(" AND prerelease=FALSE "); + } + + query_builder.push(" ORDER BY created_at DESC "); + + query_builder.push(" LIMIT "); + query_builder.push_bind(limit); + query_builder.push(" OFFSET "); + query_builder.push_bind(offset); + + match query_builder + .build_query_as::() + .fetch_all(&mut *pool) + .await + { + Ok(r) => + Ok(r.into_iter().map(|x| x.into_loader_version()).collect()), + Err(e) => { + log::error!("{:?}", e); + Err(ApiError::DbError) + } + } + } }