From d8b9d8431e8b86c77b975ad4ba77f68847e3b5be Mon Sep 17 00:00:00 2001 From: Geometrically <18202329+Geometrically@users.noreply.github.com> Date: Thu, 8 Dec 2022 15:13:01 -0700 Subject: [PATCH] Shader fixes (#495) * Shader fixes * Add core shaders validator * Update validator again * Rename shaders * Fix build --- sqlx-data.json | 14 ++--- src/routes/projects.rs | 35 +++++++----- src/util/webhook.rs | 9 +--- src/validate/mod.rs | 9 +++- src/validate/shader.rs | 119 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 32 deletions(-) create mode 100644 src/validate/shader.rs diff --git a/sqlx-data.json b/sqlx-data.json index 3a09e0fa..e4ccbe5a 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -3204,7 +3204,7 @@ }, "query": "\n INSERT INTO notifications_actions (\n notification_id, title, action_route, action_route_method\n )\n VALUES (\n $1, $2, $3, $4\n )\n " }, - "8408e6e0b473abe606f917d6d59eb30424c9913840fc3a89d3cda7aec249a77a": { + "86720f27dbb8ce88ec10603c69c15bde44d9faf203fc235f08a4840922e94a8f": { "describe": { "columns": [ { @@ -3272,19 +3272,14 @@ "ordinal": 12, "type_info": "Jsonb" }, - { - "name": "all_game_versions", - "ordinal": 13, - "type_info": "Jsonb" - }, { "name": "gallery", - "ordinal": 14, + "ordinal": 13, "type_info": "VarcharArray" }, { "name": "featured_gallery", - "ordinal": 15, + "ordinal": 14, "type_info": "VarcharArray" } ], @@ -3303,7 +3298,6 @@ null, null, null, - null, null ], "parameters": { @@ -3314,7 +3308,7 @@ ] } }, - "query": "\n SELECT m.id id, m.title title, m.description description,\n m.icon_url icon_url, m.slug slug, cs.name client_side_type, ss.name server_side_type,\n pt.name project_type, u.username username, u.avatar_url avatar_url,\n ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null) categories,\n ARRAY_AGG(DISTINCT lo.loader) filter (where lo.loader is not null) loaders,\n JSONB_AGG(DISTINCT jsonb_build_object('id', gv.id, 'version', gv.version, 'type', gv.type, 'created', gv.created, 'major', gv.major)) filter (where gv.version is not null) versions,\n JSONB_AGG(DISTINCT jsonb_build_object('id', agv.id, 'version', agv.version, 'type', agv.type, 'created', agv.created, 'major', agv.major)) filter (where agv.version is not null) all_game_versions,\n ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is false) gallery,\n ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is true) featured_gallery\n FROM mods m\n LEFT OUTER JOIN mods_categories mc ON joining_mod_id = m.id AND mc.is_additional = FALSE\n LEFT OUTER JOIN categories c ON mc.joining_category_id = c.id\n LEFT OUTER JOIN versions v ON v.mod_id = m.id AND v.status != ANY($2)\n LEFT OUTER JOIN game_versions_versions gvv ON gvv.joining_version_id = v.id\n LEFT OUTER JOIN game_versions gv ON gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv ON lv.version_id = v.id\n LEFT OUTER JOIN loaders lo ON lo.id = lv.loader_id\n LEFT OUTER JOIN mods_gallery mg ON mg.mod_id = m.id\n LEFT OUTER JOIN game_versions agv ON 1=1\n INNER JOIN project_types pt ON pt.id = m.project_type\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.role = $3 AND tm.accepted = TRUE\n INNER JOIN users u ON tm.user_id = u.id\n WHERE m.id = $1\n GROUP BY m.id, cs.id, ss.id, pt.id, u.id;\n " + "query": "\n SELECT m.id id, m.title title, m.description description,\n m.icon_url icon_url, m.slug slug, cs.name client_side_type, ss.name server_side_type,\n pt.name project_type, u.username username, u.avatar_url avatar_url,\n ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null) categories,\n ARRAY_AGG(DISTINCT lo.loader) filter (where lo.loader is not null) loaders,\n JSONB_AGG(DISTINCT jsonb_build_object('id', gv.id, 'version', gv.version, 'type', gv.type, 'created', gv.created, 'major', gv.major)) filter (where gv.version is not null) versions,\n ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is false) gallery,\n ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is true) featured_gallery\n FROM mods m\n LEFT OUTER JOIN mods_categories mc ON joining_mod_id = m.id AND mc.is_additional = FALSE\n LEFT OUTER JOIN categories c ON mc.joining_category_id = c.id\n LEFT OUTER JOIN versions v ON v.mod_id = m.id AND v.status != ANY($2)\n LEFT OUTER JOIN game_versions_versions gvv ON gvv.joining_version_id = v.id\n LEFT OUTER JOIN game_versions gv ON gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv ON lv.version_id = v.id\n LEFT OUTER JOIN loaders lo ON lo.id = lv.loader_id\n LEFT OUTER JOIN mods_gallery mg ON mg.mod_id = m.id\n INNER JOIN project_types pt ON pt.id = m.project_type\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.role = $3 AND tm.accepted = TRUE\n INNER JOIN users u ON tm.user_id = u.id\n WHERE m.id = $1\n GROUP BY m.id, cs.id, ss.id, pt.id, u.id;\n " }, "868ee76d507cc9e94cd3c2e44770faff127e2b3c5f49b8100a9a37ac4d7b1f1d": { "describe": { diff --git a/src/routes/projects.rs b/src/routes/projects.rs index 68da0106..c6654fce 100644 --- a/src/routes/projects.rs +++ b/src/routes/projects.rs @@ -457,15 +457,6 @@ pub async fn project_edit( )); } - if (status.is_approved() || !status.can_be_requested()) - && !user.role.is_mod() - { - return Err(ApiError::CustomAuthentication( - "You don't have permission to set this status!" - .to_string(), - )); - } - if status == &ProjectStatus::Processing { if project_item.versions.is_empty() { return Err(ApiError::InvalidInput(String::from( @@ -508,6 +499,15 @@ pub async fn project_edit( } } + if (status.is_approved() || !status.can_be_requested()) + && !user.role.is_mod() + { + return Err(ApiError::CustomAuthentication( + "You don't have permission to set this status!" + .to_string(), + )); + } + if status.is_approved() && !project_item.inner.status.is_approved() { @@ -1420,7 +1420,7 @@ pub async fn add_gallery_item( let string = info.into_inner().0; let project_item = - database::models::Project::get_from_slug_or_project_id( + database::models::Project::get_full_from_slug_or_project_id( &string, &**pool, ) .await? @@ -1430,9 +1430,16 @@ pub async fn add_gallery_item( ) })?; + if project_item.gallery_items.len() > 64 { + return Err(ApiError::CustomAuthentication( + "You have reached the maximum of gallery images to upload." + .to_string(), + )); + } + if !user.role.is_admin() { let team_member = database::models::TeamMember::get_from_user_id( - project_item.team_id, + project_item.inner.team_id, user.id.into(), &**pool, ) @@ -1460,7 +1467,7 @@ pub async fn add_gallery_item( .await?; let hash = sha1::Sha1::from(&bytes).hexdigest(); - let id: ProjectId = project_item.id.into(); + let id: ProjectId = project_item.inner.id.into(); let url = format!("data/{}/images/{}.{}", id, hash, &*ext.ext); file_host .upload_file(content_type, &url, bytes.freeze()) @@ -1475,7 +1482,7 @@ pub async fn add_gallery_item( SET featured = $2 WHERE mod_id = $1 ", - project_item.id as database::models::ids::ProjectId, + project_item.inner.id as database::models::ids::ProjectId, false, ) .execute(&mut *transaction) @@ -1489,7 +1496,7 @@ pub async fn add_gallery_item( description: item.description, created: Utc::now(), } - .insert(project_item.id, &mut transaction) + .insert(project_item.inner.id, &mut transaction) .await?; transaction.commit().await?; diff --git a/src/util/webhook.rs b/src/util/webhook.rs index 00089098..8420e932 100644 --- a/src/util/webhook.rs +++ b/src/util/webhook.rs @@ -62,6 +62,8 @@ pub async fn send_discord_webhook( pool: &PgPool, webhook_url: String, ) -> Result<(), ApiError> { + let all_game_versions = GameVersion::list(pool).await?; + let row = sqlx::query!( " @@ -71,7 +73,6 @@ pub async fn send_discord_webhook( ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null) categories, ARRAY_AGG(DISTINCT lo.loader) filter (where lo.loader is not null) loaders, JSONB_AGG(DISTINCT jsonb_build_object('id', gv.id, 'version', gv.version, 'type', gv.type, 'created', gv.created, 'major', gv.major)) filter (where gv.version is not null) versions, - JSONB_AGG(DISTINCT jsonb_build_object('id', agv.id, 'version', agv.version, 'type', agv.type, 'created', agv.created, 'major', agv.major)) filter (where agv.version is not null) all_game_versions, ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is false) gallery, ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is true) featured_gallery FROM mods m @@ -83,7 +84,6 @@ pub async fn send_discord_webhook( LEFT OUTER JOIN loaders_versions lv ON lv.version_id = v.id LEFT OUTER JOIN loaders lo ON lo.id = lv.loader_id LEFT OUTER JOIN mods_gallery mg ON mg.mod_id = m.id - LEFT OUTER JOIN game_versions agv ON 1=1 INNER JOIN project_types pt ON pt.id = m.project_type INNER JOIN side_types cs ON m.client_side = cs.id INNER JOIN side_types ss ON m.server_side = ss.id @@ -109,11 +109,6 @@ pub async fn send_discord_webhook( serde_json::from_value(project.versions.unwrap_or_default()) .ok() .unwrap_or_default(); - let all_game_versions: Vec = serde_json::from_value( - project.all_game_versions.unwrap_or_default(), - ) - .ok() - .unwrap_or_default(); if !categories.is_empty() { fields.push(DiscordEmbedField { diff --git a/src/validate/mod.rs b/src/validate/mod.rs index 3e6cb41b..7b6ee91a 100644 --- a/src/validate/mod.rs +++ b/src/validate/mod.rs @@ -7,6 +7,9 @@ use crate::validate::modpack::ModpackValidator; use crate::validate::plugin::*; use crate::validate::quilt::QuiltValidator; use crate::validate::resourcepack::{PackValidator, TexturePackValidator}; +use crate::validate::shader::{ + CanvasShaderValidator, CoreShaderValidator, ShaderValidator, +}; use chrono::{DateTime, Utc}; use std::io::Cursor; use thiserror::Error; @@ -19,6 +22,7 @@ mod modpack; pub mod plugin; mod quilt; mod resourcepack; +mod shader; #[derive(Error, Debug)] pub enum ValidationError { @@ -76,7 +80,7 @@ pub trait Validator: Sync { ) -> Result; } -static VALIDATORS: [&dyn Validator; 12] = [ +static VALIDATORS: [&dyn Validator; 15] = [ &ModpackValidator, &FabricValidator, &ForgeValidator, @@ -89,6 +93,9 @@ static VALIDATORS: [&dyn Validator; 12] = [ &BungeeCordValidator, &VelocityValidator, &SpongeValidator, + &CanvasShaderValidator, + &ShaderValidator, + &CoreShaderValidator, ]; /// The return value is whether this file should be marked as primary or not, based on the analysis of the file diff --git a/src/validate/shader.rs b/src/validate/shader.rs new file mode 100644 index 00000000..6bd42939 --- /dev/null +++ b/src/validate/shader.rs @@ -0,0 +1,119 @@ +use crate::validate::{ + SupportedGameVersions, ValidationError, ValidationResult, +}; +use std::io::Cursor; +use zip::ZipArchive; + +pub struct ShaderValidator; + +impl super::Validator for ShaderValidator { + fn get_file_extensions(&self) -> &[&str] { + &["zip"] + } + + fn get_project_types(&self) -> &[&str] { + &["shader"] + } + + fn get_supported_loaders(&self) -> &[&str] { + &["optifine", "iris"] + } + + fn get_supported_game_versions(&self) -> SupportedGameVersions { + SupportedGameVersions::All + } + + fn validate( + &self, + archive: &mut ZipArchive>, + ) -> Result { + if !archive.file_names().any(|x| x.starts_with("shaders/")) { + return Err(ValidationError::InvalidInput( + "No shaders folder present for OptiFine/Iris shader.".into(), + )); + } + + Ok(ValidationResult::Pass) + } +} + +pub struct CanvasShaderValidator; + +impl super::Validator for CanvasShaderValidator { + fn get_file_extensions(&self) -> &[&str] { + &["zip"] + } + + fn get_project_types(&self) -> &[&str] { + &["shader"] + } + + fn get_supported_loaders(&self) -> &[&str] { + &["canvas"] + } + + fn get_supported_game_versions(&self) -> SupportedGameVersions { + SupportedGameVersions::All + } + + fn validate( + &self, + archive: &mut ZipArchive>, + ) -> Result { + archive.by_name("pack.mcmeta").map_err(|_| { + ValidationError::InvalidInput( + "No pack.mcmeta present for pack file. Tip: Make sure pack.mcmeta is in the root directory of your pack!".into(), + ) + })?; + + if !archive.file_names().any(|x| x.contains("/pipelines/")) { + return Err(ValidationError::InvalidInput( + "No pipeline shaders folder present for canvas shaders.".into(), + )); + } + + Ok(ValidationResult::Pass) + } +} + +pub struct CoreShaderValidator; + +impl super::Validator for CoreShaderValidator { + fn get_file_extensions(&self) -> &[&str] { + &["zip"] + } + + fn get_project_types(&self) -> &[&str] { + &["shader"] + } + + fn get_supported_loaders(&self) -> &[&str] { + &["vanilla"] + } + + fn get_supported_game_versions(&self) -> SupportedGameVersions { + SupportedGameVersions::All + } + + fn validate( + &self, + archive: &mut ZipArchive>, + ) -> Result { + archive.by_name("pack.mcmeta").map_err(|_| { + ValidationError::InvalidInput( + "No pack.mcmeta present for pack file. Tip: Make sure pack.mcmeta is in the root directory of your pack!".into(), + ) + })?; + + if !archive + .file_names() + .any(|x| x.starts_with("assets/minecraft/shaders/")) + { + return Err(ValidationError::InvalidInput( + "No shaders folder present for vanilla shaders.".into(), + )); + } + + Ok(ValidationResult::Pass) + } +}