Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
side types overhaul
Browse files Browse the repository at this point in the history
  • Loading branch information
thesuzerain committed Nov 26, 2023
1 parent 172b93d commit 3c74fa8
Show file tree
Hide file tree
Showing 25 changed files with 684 additions and 443 deletions.
77 changes: 77 additions & 0 deletions migrations/20231116112800_side_types_overhaul.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
INSERT INTO loader_fields (field, field_type, optional) SELECT 'singleplayer', 'boolean', false;
INSERT INTO loader_fields (field, field_type, optional) SELECT 'client_and_server', 'boolean', false;
INSERT INTO loader_fields (field, field_type, optional) SELECT 'client_only', 'boolean', false;
INSERT INTO loader_fields (field, field_type, optional) SELECT 'server_only', 'boolean', false;

-- Create 4 temporary columns for the four booleans (makes queries easier)
ALTER TABLE versions ADD COLUMN singleplayer boolean;
ALTER TABLE versions ADD COLUMN client_and_server boolean;
ALTER TABLE versions ADD COLUMN client_only boolean;
ALTER TABLE versions ADD COLUMN server_only boolean;

-- Set singleplayer to be true if either client_side or server_side is 'required' OR 'optional'
UPDATE versions v SET singleplayer = true
FROM version_fields vf
INNER JOIN loader_fields lf ON vf.field_id = lf.id
INNER JOIN loader_field_enum_values lfev ON lf.enum_type = lfev.id
WHERE (lf.field = 'client_side' OR lf.field = 'server_side') AND (lfev.value = 'required' OR lfev.value = 'optional');

-- Set client and server to be true if either client_side or server_side is 'required' OR 'optional'
UPDATE versions v SET client_and_server = true
FROM version_fields vf
INNER JOIN loader_fields lf ON vf.field_id = lf.id
INNER JOIN loader_field_enum_values lfev ON lf.enum_type = lfev.id
WHERE (lf.field = 'client_side' OR lf.field = 'server_side') AND (lfev.value = 'required' OR lfev.value = 'optional');

-- Set client_only to be true if client_side is 'required' or 'optional', and server_side is 'optional', 'unsupported', or 'unknown'
UPDATE versions v SET client_only = true
FROM version_fields vf
INNER JOIN loader_fields lf ON vf.field_id = lf.id
INNER JOIN loader_fields lf2 ON vf.field_id = lf2.id
INNER JOIN loader_field_enum_values lfev ON lf.enum_type = lfev.id
INNER JOIN loader_field_enum_values lfev2 ON lf2.enum_type = lfev2.id
WHERE lf.field = 'client_side' AND (lfev.value = 'required' OR lfev.value = 'optional')
AND lf2.field = 'server_side' AND (lfev2.value = 'optional' OR lfev2.value = 'unsupported' OR lfev2.value = 'unknown');

-- Set server_only to be true if server_side is 'required' or 'optional', and client_side is 'optional', 'unsupported', or 'unknown'
UPDATE versions v SET server_only = true
FROM version_fields vf
INNER JOIN loader_fields lf ON vf.field_id = lf.id
INNER JOIN loader_fields lf2 ON vf.field_id = lf2.id
INNER JOIN loader_field_enum_values lfev ON lf.enum_type = lfev.id
INNER JOIN loader_field_enum_values lfev2 ON lf2.enum_type = lfev2.id
WHERE lf.field = 'server_side' AND (lfev.value = 'required' OR lfev.value = 'optional')
AND lf2.field = 'client_side' AND (lfev2.value = 'optional' OR lfev2.value = 'unsupported' OR lfev2.value = 'unknown');

-- Insert the values into the version_fields table
INSERT INTO version_fields (version_id, field_id, int_value)
SELECT v.id, lf.id, CASE WHEN v.singleplayer THEN 1 ELSE 0 END
FROM versions v
INNER JOIN loader_fields lf ON lf.field = 'singleplayer';

INSERT INTO version_fields (version_id, field_id, int_value)
SELECT v.id, lf.id, CASE WHEN v.client_and_server THEN 1 ELSE 0 END
FROM versions v
INNER JOIN loader_fields lf ON lf.field = 'client_and_server';

INSERT INTO version_fields (version_id, field_id, int_value)
SELECT v.id, lf.id, CASE WHEN v.client_only THEN 1 ELSE 0 END
FROM versions v
INNER JOIN loader_fields lf ON lf.field = 'client_only';

INSERT INTO version_fields (version_id, field_id, int_value)
SELECT v.id, lf.id, CASE WHEN v.server_only THEN 1 ELSE 0 END
FROM versions v
INNER JOIN loader_fields lf ON lf.field = 'server_only';

-- Drop the temporary columns
ALTER TABLE versions DROP COLUMN singleplayer;
ALTER TABLE versions DROP COLUMN client_and_server;
ALTER TABLE versions DROP COLUMN client_only;
ALTER TABLE versions DROP COLUMN server_only;

-- Drop client_side and server_side loader fields
DELETE FROM version_fields WHERE field_id IN (SELECT id FROM loader_fields WHERE field = 'client_side' OR field = 'server_side');
DELETE FROM loader_field_enum_values WHERE id IN (SELECT enum_type FROM loader_fields WHERE field = 'client_side' OR field = 'server_side');
DELETE FROM loader_fields WHERE field = 'client_side' OR field = 'server_side';
DELETE FROM loader_field_enums WHERE id IN (SELECT enum_type FROM loader_fields WHERE field = 'side_types');
30 changes: 22 additions & 8 deletions src/database/models/loader_fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,24 @@ impl LoaderField {
exec: E,
redis: &RedisPool,
) -> Result<Vec<LoaderField>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let found_loader_fields = Self::get_fields_per_loader(loader_ids, exec, redis).await?;
let result = found_loader_fields
.into_values()
.flatten()
.into_iter()

Check warning on line 326 in src/database/models/loader_fields.rs

View workflow job for this annotation

GitHub Actions / clippy

useless conversion to the same type: `std::iter::Flatten<std::collections::hash_map::IntoValues<database::models::ids::LoaderId, std::vec::Vec<database::models::loader_fields::LoaderField>>>`

warning: useless conversion to the same type: `std::iter::Flatten<std::collections::hash_map::IntoValues<database::models::ids::LoaderId, std::vec::Vec<database::models::loader_fields::LoaderField>>>` --> src/database/models/loader_fields.rs:323:22 | 323 | let result = found_loader_fields | ______________________^ 324 | | .into_values() 325 | | .flatten() 326 | | .into_iter() | |________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion = note: `#[warn(clippy::useless_conversion)]` on by default help: consider removing `.into_iter()` | 323 ~ let result = found_loader_fields 324 + .into_values() 325 + .flatten() |
.unique_by(|x| x.id)
.collect();
Ok(result)
}

pub async fn get_fields_per_loader<'a, E>(
loader_ids: &[LoaderId],
exec: E,
redis: &RedisPool,
) -> Result<HashMap<LoaderId, Vec<LoaderField>>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
Expand All @@ -332,11 +350,11 @@ impl LoaderField {
.filter_map(|x: String| serde_json::from_str::<RedisLoaderFieldTuple>(&x).ok())
.collect();

let mut found_loader_fields = vec![];
let mut found_loader_fields = HashMap::new();
if !cached_fields.is_empty() {
for (loader_id, fields) in cached_fields {
if loader_ids.contains(&loader_id) {
found_loader_fields.extend(fields);
found_loader_fields.insert(loader_id, fields);
loader_ids.retain(|x| x != &loader_id);
}
}
Expand Down Expand Up @@ -384,14 +402,10 @@ impl LoaderField {
redis
.set_serialized_to_json(LOADER_FIELDS_NAMESPACE, k.0, (k, &v), None)
.await?;
found_loader_fields.extend(v);
found_loader_fields.insert(k, v);
}
}
let result = found_loader_fields
.into_iter()
.unique_by(|x| x.id)
.collect();
Ok(result)
Ok(found_loader_fields)
}
}

Expand Down
29 changes: 8 additions & 21 deletions src/models/v2/projects.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashMap;

use super::super::ids::OrganizationId;
use super::super::teams::TeamId;
use super::super::users::UserId;
Expand All @@ -10,6 +12,7 @@ use crate::models::projects::{
Project, ProjectStatus, Version, VersionFile, VersionStatus, VersionType,
};
use crate::models::threads::ThreadId;
use crate::routes::v2_reroute;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -81,26 +84,6 @@ impl LegacyProject {
let mut loaders = data.loaders;

if let Some(versions_item) = versions_item {
client_side = versions_item
.version_fields
.iter()
.find(|f| f.field_name == "client_side")
.and_then(|f| {
Some(LegacySideType::from_string(
f.value.serialize_internal().as_str()?,
))
})
.unwrap_or(LegacySideType::Unknown);
server_side = versions_item
.version_fields
.iter()
.find(|f| f.field_name == "server_side")
.and_then(|f| {
Some(LegacySideType::from_string(
f.value.serialize_internal().as_str()?,
))
})
.unwrap_or(LegacySideType::Unknown);
game_versions = versions_item
.version_fields
.iter()
Expand All @@ -109,6 +92,10 @@ impl LegacyProject {
.map(|v| v.into_iter().map(|v| v.version).collect())
.unwrap_or(Vec::new());

// Extract side types from remaining fields (singleplayer, client_only, etc)
let fields = versions_item.version_fields.iter().map(|f| (f.field_name.clone(), f.value.clone().serialize_internal())).collect::<HashMap<_, _>>();
(client_side, server_side) = v2_reroute::convert_side_types_v2(&fields);

// - if loader is mrpack, this is a modpack
// the loaders are whatever the corresponding loader fields are
if versions_item.loaders == vec!["mrpack".to_string()] {
Expand Down Expand Up @@ -190,7 +177,7 @@ impl LegacyProject {
}
}

#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Copy)]
#[serde(rename_all = "kebab-case")]
pub enum LegacySideType {
Required,
Expand Down
4 changes: 2 additions & 2 deletions src/models/v3/pack.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{models::projects::SideType, util::env::parse_strings_from_var};
use crate::{util::env::parse_strings_from_var, models::v2::projects::LegacySideType};
use serde::{Deserialize, Serialize};
use validator::Validate;

Expand All @@ -23,7 +23,7 @@ pub struct PackFormat {
pub struct PackFile {
pub path: String,
pub hashes: std::collections::HashMap<PackFileHash, String>,
pub env: Option<std::collections::HashMap<EnvType, SideType>>,
pub env: Option<std::collections::HashMap<EnvType, LegacySideType>>, // TODO: Should this use LegacySideType? Will probably require a overhaul of mrpack format to change this
#[validate(custom(function = "validate_download_url"))]
pub downloads: Vec<String>,
pub file_size: u32,
Expand Down
36 changes: 0 additions & 36 deletions src/models/v3/projects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,42 +216,6 @@ pub struct ModeratorMessage {
pub body: Option<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum SideType {
Required,
Optional,
Unsupported,
Unknown,
}

impl std::fmt::Display for SideType {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{}", self.as_str())
}
}

impl SideType {
// These are constant, so this can remove unneccessary allocations (`to_string`)
pub fn as_str(&self) -> &'static str {
match self {
SideType::Required => "required",
SideType::Optional => "optional",
SideType::Unsupported => "unsupported",
SideType::Unknown => "unknown",
}
}

pub fn from_string(string: &str) -> SideType {
match string {
"required" => SideType::Required,
"optional" => SideType::Optional,
"unsupported" => SideType::Unsupported,
_ => SideType::Unknown,
}
}
}

pub const DEFAULT_LICENSE_ID: &str = "LicenseRef-All-Rights-Reserved";

#[derive(Serialize, Deserialize, Clone)]
Expand Down
13 changes: 6 additions & 7 deletions src/routes/v2/project_creation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use crate::database::redis::RedisPool;
use crate::file_hosting::FileHost;
use crate::models;
use crate::models::ids::ImageId;
use crate::models::projects::{DonationLink, Loader, Project, ProjectStatus, SideType};
use crate::models::v2::projects::LegacyProject;
use crate::models::projects::{DonationLink, Loader, Project, ProjectStatus};
use crate::models::v2::projects::{LegacyProject, LegacySideType};
use crate::queue::session::AuthQueue;
use crate::routes::v3::project_creation::default_project_type;
use crate::routes::v3::project_creation::{CreateError, NewGalleryItem};
Expand Down Expand Up @@ -60,9 +60,9 @@ struct ProjectCreateData {
pub body: String,

/// The support range for the client project
pub client_side: SideType,
pub client_side: LegacySideType,
/// The support range for the server project
pub server_side: SideType,
pub server_side: LegacySideType,

#[validate(length(max = 32))]
#[validate]
Expand Down Expand Up @@ -146,7 +146,7 @@ pub async fn project_create(
let payload = v2_reroute::alter_actix_multipart(
payload,
req.headers().clone(),
|legacy_create: ProjectCreateData| {
|legacy_create: ProjectCreateData| async move {
// Side types will be applied to each version
let client_side = legacy_create.client_side;
let server_side = legacy_create.server_side;
Expand All @@ -158,8 +158,7 @@ pub async fn project_create(
.into_iter()
.map(|v| {
let mut fields = HashMap::new();
fields.insert("client_side".to_string(), json!(client_side));
fields.insert("server_side".to_string(), json!(server_side));
fields.extend(v2_reroute::convert_side_types_v3(client_side, server_side));
fields.insert("game_versions".to_string(), json!(v.game_versions));

// Modpacks now use the "mrpack" loader, and loaders are converted to loader fields.
Expand Down
Loading

0 comments on commit 3c74fa8

Please sign in to comment.