From 07bac8ffde10aa355227161ff426e637ad4ba091 Mon Sep 17 00:00:00 2001 From: aecsocket <43144841+aecsocket@users.noreply.github.com> Date: Tue, 11 Aug 2026 00:42:56 +0900 Subject: [PATCH] fix: v3 environment fields in all v2 endpoints (#7082) --- apps/labrinth/src/models/v2/projects.rs | 21 +++++++++++++++++++++ apps/labrinth/src/models/v2/search.rs | 10 ++++++++++ apps/labrinth/tests/v2/search.rs | 1 + apps/labrinth/tests/v2/version.rs | 12 +++++++++++- 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/apps/labrinth/src/models/v2/projects.rs b/apps/labrinth/src/models/v2/projects.rs index a5edfd216b..4f00ed8486 100644 --- a/apps/labrinth/src/models/v2/projects.rs +++ b/apps/labrinth/src/models/v2/projects.rs @@ -28,6 +28,8 @@ pub struct LegacyProject { pub server_side: LegacySideType, /// A list of game versions this project supports pub game_versions: Vec, + /// The environments this project supports + pub environment: Vec, // All other fields are the same as V3 // If they change, or their constituent types change, we may need to @@ -125,6 +127,14 @@ impl LegacyProject { .filter_map(|v| v.as_str()) .map(|v| v.to_string()) .collect(); + let environment = data + .fields + .get("environment") + .unwrap_or(&Vec::new()) + .iter() + .filter_map(|v| v.as_str()) + .map(|v| v.to_string()) + .collect(); if let Some(versions_item) = versions_item { // Extract side types from remaining fields @@ -221,6 +231,7 @@ impl LegacyProject { client_side, server_side, game_versions, + environment, } } @@ -302,6 +313,9 @@ pub struct LegacyVersion { /// A list of loaders this project supports (has a newtype struct) pub loaders: Vec, + /// The environment this version supports + pub environment: String, + pub id: VersionId, pub project_id: ProjectId, pub author_id: UserId, @@ -332,6 +346,12 @@ impl From for LegacyVersion { } } } + let environment = data + .fields + .get("environment") + .and_then(|value| value.as_str()) + .unwrap_or("unknown") + .to_string(); // - if loader is mrpack, this is a modpack // the v2 loaders are whatever the corresponding loader fields are @@ -366,6 +386,7 @@ impl From for LegacyVersion { dependencies: data.dependencies, game_versions, loaders, + environment, } } } diff --git a/apps/labrinth/src/models/v2/search.rs b/apps/labrinth/src/models/v2/search.rs index 46865a47a5..5f617153bc 100644 --- a/apps/labrinth/src/models/v2/search.rs +++ b/apps/labrinth/src/models/v2/search.rs @@ -41,6 +41,7 @@ pub struct LegacyResultSearchProject { pub license: String, pub client_side: String, pub server_side: String, + pub environment: Vec, pub gallery: Vec, pub featured_gallery: Option, pub color: Option, @@ -118,6 +119,14 @@ impl LegacyResultSearchProject { let environment = get_one_string_loader_field("environment").unwrap_or("unknown"); + let environments = result_search_project + .loader_fields + .get("environment") + .cloned() + .unwrap_or_default() + .into_iter() + .filter_map(|environment| environment.as_str().map(String::from)) + .collect(); let (client_side, server_side) = v2_reroute::convert_v3_environment_to_v2_side_types( @@ -141,6 +150,7 @@ impl LegacyResultSearchProject { all_project_types: result_search_project.all_project_types, client_side, server_side, + environment: environments, versions, latest_version: result_search_project.version_id, categories, diff --git a/apps/labrinth/tests/v2/search.rs b/apps/labrinth/tests/v2/search.rs index cf27d5a0cf..510a21fde0 100644 --- a/apps/labrinth/tests/v2/search.rs +++ b/apps/labrinth/tests/v2/search.rs @@ -378,6 +378,7 @@ async fn search_projects() { for hit in client_side_optional_server_side_optional.hits { assert_eq!(hit.client_side, "optional".to_string()); assert_eq!(hit.server_side, "optional".to_string()); + assert_eq!(hit.environment, vec!["client_or_server".to_string()]); } // Ensure game_versions return correctly, but also correctly aggregated diff --git a/apps/labrinth/tests/v2/version.rs b/apps/labrinth/tests/v2/version.rs index 788a368421..6cf14aa4aa 100644 --- a/apps/labrinth/tests/v2/version.rs +++ b/apps/labrinth/tests/v2/version.rs @@ -7,7 +7,7 @@ use futures::StreamExt; use labrinth::{ models::ids::VersionId, models::projects::{Loader, VersionStatus, VersionType}, - models::v2::projects::LegacySideType, + models::v2::projects::{LegacySideType, LegacyVersion}, routes::v2::version_file::FileUpdateData, }; use serde_json::json; @@ -550,6 +550,8 @@ async fn add_version_accepts_environment_v2() { ) .await; assert_status!(&resp, StatusCode::OK); + let version: LegacyVersion = test::read_body_json(resp).await; + assert_eq!(version.environment, "server_only_client_optional"); let project = api .get_project_deserialized( @@ -559,6 +561,10 @@ async fn add_version_accepts_environment_v2() { .await; assert_eq!(project.client_side, LegacySideType::Optional); assert_eq!(project.server_side, LegacySideType::Required); + assert_eq!( + project.environment, + vec!["server_only_client_optional".to_string()] + ); }, ) .await; @@ -589,6 +595,10 @@ async fn create_project_initial_version_accepts_environment_v2() { api.get_project_deserialized(slug, USER_USER_PAT).await; assert_eq!(project.client_side, LegacySideType::Required); assert_eq!(project.server_side, LegacySideType::Optional); + assert_eq!( + project.environment, + vec!["client_only_server_optional".to_string()] + ); }, ) .await;