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

@@ -158,10 +158,12 @@ pub async fn project_create(
.into_iter()
.map(|v| {
let mut fields = HashMap::new();
fields.extend(v2_reroute::convert_side_types_v3(
client_side,
server_side,
));
fields.extend(
v2_reroute::convert_v2_side_types_to_v3_side_types(
client_side,
server_side,
),
);
fields.insert(
"game_versions".to_string(),
json!(v.game_versions),

View File

@@ -511,6 +511,7 @@ pub async fn project_edit(
moderation_message: v2_new_project.moderation_message,
moderation_message_body: v2_new_project.moderation_message_body,
monetization_status: v2_new_project.monetization_status,
side_types_migration_review_status: None, // Not to be exposed in v2
};
// This returns 204 or failure so we don't need to do anything with it
@@ -547,10 +548,12 @@ pub async fn project_edit(
let version = Version::from(version);
let mut fields = version.fields;
let (current_client_side, current_server_side) =
v2_reroute::convert_side_types_v2(&fields, None);
v2_reroute::convert_v3_side_types_to_v2_side_types(
&fields, None,
);
let client_side = client_side.unwrap_or(current_client_side);
let server_side = server_side.unwrap_or(current_server_side);
fields.extend(v2_reroute::convert_side_types_v3(
fields.extend(v2_reroute::convert_v2_side_types_to_v3_side_types(
client_side,
server_side,
));

View File

@@ -105,7 +105,7 @@ pub async fn version_create(
json!(legacy_create.game_versions),
);
// Get all possible side-types for loaders given- we will use these to check if we need to convert/apply singleplayer, etc.
// Get all possible side-types for loaders given- we will use these to check if we need to convert/apply side types
let loaders =
match v3::tags::loader_list(client.clone(), redis.clone())
.await
@@ -136,53 +136,32 @@ pub async fn version_create(
.collect::<Vec<_>>();
// Copies side types of another version of the project.
// If no version exists, defaults to all false.
// If no version exists, defaults to an unknown side type.
// This is inherently lossy, but not much can be done about it, as side types are no longer associated with projects,
// so the 'missing' ones can't be easily accessed, and versions do need to have these fields explicitly set.
let side_type_loader_field_names = [
"singleplayer",
"client_and_server",
"client_only",
"server_only",
];
// so the 'missing' ones can't be easily accessed, and versions do need to have that field explicitly set.
// Check if loader_fields_aggregate contains any of these side types
// Check if loader_fields_aggregate contains the side types
// We assume these four fields are linked together.
if loader_fields_aggregate
.iter()
.any(|f| side_type_loader_field_names.contains(&f.as_str()))
.any(|field| field == "environment")
{
// If so, we get the fields of the example version of the project, and set the side types to match.
fields.extend(
side_type_loader_field_names
.iter()
.map(|f| (f.to_string(), json!(false))),
);
if let Some(example_version_fields) =
// If so, we get the field of an example version of the project, and set the side types to match.
fields.insert(
"environment".into(),
get_example_version_fields(
legacy_create.project_id,
client,
&redis,
)
.await?
{
fields.extend(
example_version_fields.into_iter().filter_map(
|f| {
if side_type_loader_field_names
.contains(&f.field_name.as_str())
{
Some((
f.field_name,
f.value.serialize_internal(),
))
} else {
None
}
},
),
);
}
.into_iter()
.flatten()
.find(|f| f.field_name == "environment")
.map_or(json!("unknown"), |f| {
f.value.serialize_internal()
}),
);
}
// Handle project type via file extension prediction
let mut project_type = None;