feat(labrinth): rework v3 side types to a single environment field (#3701)

* feat(labrinth): rework v3 side types to a single `environment` field

This field is meant to be able to represent the existing v2 side type
information and beyond, in a way that may also be slightly easier to
comprehend.

* chore(labrinth/migrations): use proper val for `HAVING` clause

* feat(labrinth): add `side_types_migration_review_status` field to projects
This commit is contained in:
Alejandro González
2025-06-17 00:44:57 +02:00
committed by GitHub
parent 65126b3a23
commit ef04dcc37b
22 changed files with 358 additions and 205 deletions

View File

@@ -127,7 +127,7 @@ impl LegacyProject {
.collect();
if let Some(versions_item) = versions_item {
// Extract side types from remaining fields (singleplayer, client_only, etc)
// Extract side types from remaining fields
let fields = versions_item
.version_fields
.iter()
@@ -135,10 +135,11 @@ impl LegacyProject {
(f.field_name.clone(), f.value.clone().serialize_internal())
})
.collect::<HashMap<_, _>>();
(client_side, server_side) = v2_reroute::convert_side_types_v2(
&fields,
Some(&*og_project_type),
);
(client_side, server_side) =
v2_reroute::convert_v3_side_types_to_v2_side_types(
&fields,
Some(&*og_project_type),
);
// - if loader is mrpack, this is a modpack
// the loaders are whatever the corresponding loader fields are

View File

@@ -102,28 +102,20 @@ impl LegacyResultSearchProject {
let project_loader_fields =
result_search_project.project_loader_fields.clone();
let get_one_bool_loader_field = |key: &str| {
let get_one_string_loader_field = |key: &str| {
project_loader_fields
.get(key)
.cloned()
.unwrap_or_default()
.map_or(&[][..], |values| values.as_slice())
.first()
.and_then(|s| s.as_bool())
.and_then(|s| s.as_str())
};
let singleplayer = get_one_bool_loader_field("singleplayer");
let client_only =
get_one_bool_loader_field("client_only").unwrap_or(false);
let server_only =
get_one_bool_loader_field("server_only").unwrap_or(false);
let client_and_server = get_one_bool_loader_field("client_and_server");
let environment =
get_one_string_loader_field("environment").unwrap_or("unknown");
let (client_side, server_side) =
v2_reroute::convert_side_types_v2_bools(
singleplayer,
client_only,
server_only,
client_and_server,
v2_reroute::convert_v3_environment_to_v2_side_types(
environment,
Some(&*og_project_type),
);
let client_side = client_side.to_string();

View File

@@ -92,6 +92,9 @@ pub struct Project {
/// The monetization status of this project
pub monetization_status: MonetizationStatus,
/// The status of the manual review of the migration of side types of this project
pub side_types_migration_review_status: SideTypesMigrationReviewStatus,
/// Aggregated loader-fields across its myriad of versions
#[serde(flatten)]
pub fields: HashMap<String, Vec<serde_json::Value>>,
@@ -206,6 +209,8 @@ impl From<ProjectQueryResult> for Project {
color: m.color,
thread_id: data.thread_id.into(),
monetization_status: m.monetization_status,
side_types_migration_review_status: m
.side_types_migration_review_status,
fields,
}
}
@@ -588,6 +593,35 @@ impl MonetizationStatus {
}
}
/// Represents the status of the manual review of the migration of side types of this
/// project to the new environment field.
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum SideTypesMigrationReviewStatus {
/// The project has been reviewed to use the new environment side types appropriately.
Reviewed,
/// The project has been automatically migrated to the new environment side types, but
/// the appropriateness of such migration has not been reviewed.
Pending,
}
impl SideTypesMigrationReviewStatus {
pub fn as_str(&self) -> &'static str {
match self {
SideTypesMigrationReviewStatus::Reviewed => "reviewed",
SideTypesMigrationReviewStatus::Pending => "pending",
}
}
pub fn from_string(string: &str) -> SideTypesMigrationReviewStatus {
match string {
"reviewed" => SideTypesMigrationReviewStatus::Reviewed,
"pending" => SideTypesMigrationReviewStatus::Pending,
_ => SideTypesMigrationReviewStatus::Reviewed,
}
}
}
/// A specific version of a project
#[derive(Serialize, Deserialize, Clone)]
pub struct Version {
@@ -846,7 +880,6 @@ impl std::fmt::Display for VersionType {
}
impl VersionType {
// These are constant, so this can remove unneccessary allocations (`to_string`)
pub fn as_str(&self) -> &'static str {
match self {
VersionType::Release => "release",