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

Fix duplicate file names #927

Merged
merged 3 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

This file was deleted.

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/routes/v2/version_creation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::models::projects::{
Dependency, FileType, Loader, ProjectId, Version, VersionId, VersionStatus, VersionType,
};
use crate::models::v2::projects::LegacyVersion;
use crate::queue::moderation::AutomatedModerationQueue;
use crate::queue::session::AuthQueue;
use crate::routes::v3::project_creation::CreateError;
use crate::routes::v3::version_creation;
Expand Down Expand Up @@ -87,6 +88,7 @@ pub async fn version_create(
redis: Data<RedisPool>,
file_host: Data<Arc<dyn FileHost + Send + Sync>>,
session_queue: Data<AuthQueue>,
moderation_queue: Data<AutomatedModerationQueue>,
) -> Result<HttpResponse, CreateError> {
let payload = v2_reroute::alter_actix_multipart(
payload,
Expand Down Expand Up @@ -233,6 +235,7 @@ pub async fn version_create(
redis.clone(),
file_host,
session_queue,
moderation_queue,
)
.await?;

Expand Down
2 changes: 0 additions & 2 deletions src/routes/v2/versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@ pub struct EditVersion {
pub game_versions: Option<Vec<String>>,
pub loaders: Option<Vec<models::projects::Loader>>,
pub featured: Option<bool>,
pub primary_file: Option<(String, String)>,
pub downloads: Option<u32>,
pub status: Option<VersionStatus>,
pub file_types: Option<Vec<EditVersionFileType>>,
Expand Down Expand Up @@ -278,7 +277,6 @@ pub async fn version_edit(
dependencies: new_version.dependencies,
loaders,
featured: new_version.featured,
primary_file: new_version.primary_file,
downloads: new_version.downloads,
status: new_version.status,
file_types: new_version.file_types.map(|v| {
Expand Down
6 changes: 6 additions & 0 deletions src/routes/v3/project_creation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,11 @@ async fn project_create_inner(
let version_data = project_create_data.initial_versions.get(index).unwrap();
// TODO: maybe redundant is this calculation done elsewhere?

let existing_file_names = created_version
.files
.iter()
.map(|x| x.filename.clone())
.collect();
// Upload the new jar file
super::version_creation::upload_file(
&mut field,
Expand All @@ -555,6 +560,7 @@ async fn project_create_inner(
version_data.primary_file.is_some(),
version_data.primary_file.as_deref() == Some(name),
None,
existing_file_names,
transaction,
redis,
)
Expand Down
30 changes: 29 additions & 1 deletion src/routes/v3/version_creation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ use crate::models::images::{Image, ImageContext, ImageId};
use crate::models::notifications::NotificationBody;
use crate::models::pack::PackFileHash;
use crate::models::pats::Scopes;
use crate::models::projects::{skip_nulls, DependencyType};
use crate::models::projects::{skip_nulls, DependencyType, ProjectStatus};
use crate::models::projects::{
Dependency, FileType, Loader, ProjectId, Version, VersionFile, VersionId, VersionStatus,
VersionType,
};
use crate::models::teams::ProjectPermissions;
use crate::queue::moderation::AutomatedModerationQueue;
use crate::queue::session::AuthQueue;
use crate::util::routes::read_from_field;
use crate::util::validate::validation_errors_to_string;
Expand Down Expand Up @@ -102,6 +103,7 @@ pub async fn version_create(
redis: Data<RedisPool>,
file_host: Data<Arc<dyn FileHost + Send + Sync>>,
session_queue: Data<AuthQueue>,
moderation_queue: web::Data<AutomatedModerationQueue>,
) -> Result<HttpResponse, CreateError> {
let mut transaction = client.begin().await?;
let mut uploaded_files = Vec::new();
Expand All @@ -115,6 +117,7 @@ pub async fn version_create(
&mut uploaded_files,
&client,
&session_queue,
&moderation_queue,
)
.await;

Expand Down Expand Up @@ -144,6 +147,7 @@ async fn version_create_inner(
uploaded_files: &mut Vec<UploadedFile>,
pool: &PgPool,
session_queue: &AuthQueue,
moderation_queue: &AutomatedModerationQueue,
) -> Result<HttpResponse, CreateError> {
let cdn_url = dotenvy::var("CDN_URL")?;

Expand Down Expand Up @@ -333,6 +337,8 @@ async fn version_create_inner(
.clone()
.ok_or_else(|| CreateError::InvalidInput("`data` field is required".to_string()))?;

let existing_file_names = version.files.iter().map(|x| x.filename.clone()).collect();

upload_file(
&mut field,
file_host,
Expand All @@ -349,6 +355,7 @@ async fn version_create_inner(
version_data.primary_file.is_some(),
version_data.primary_file.as_deref() == Some(name),
version_data.file_types.get(name).copied().flatten(),
existing_file_names,
transaction,
redis,
)
Expand Down Expand Up @@ -498,6 +505,19 @@ async fn version_create_inner(

models::Project::clear_cache(project_id, None, Some(true), redis).await?;

let project_status = sqlx::query!(
"SELECT status FROM mods WHERE id = $1",
project_id as models::ProjectId,
)
.fetch_optional(pool)
.await?;

if let Some(project_status) = project_status {
if project_status.status == ProjectStatus::Processing.as_str() {
moderation_queue.projects.insert(project_id.into());
}
}

Ok(HttpResponse::Ok().json(response))
}

Expand Down Expand Up @@ -706,6 +726,7 @@ async fn upload_file_to_version_inner(
true,
false,
file_data.file_types.get(name).copied().flatten(),
version.files.iter().map(|x| x.filename.clone()).collect(),
transaction,
&redis,
)
Expand Down Expand Up @@ -759,11 +780,18 @@ pub async fn upload_file(
ignore_primary: bool,
force_primary: bool,
file_type: Option<FileType>,
other_file_names: Vec<String>,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
redis: &RedisPool,
) -> Result<(), CreateError> {
let (file_name, file_extension) = get_name_ext(content_disposition)?;

if other_file_names.contains(&format!("{}.{}", file_name, file_extension)) {
return Err(CreateError::InvalidInput(
"Duplicate files are not allowed to be uploaded to Modrinth!".to_string(),
));
}

if file_name.contains('/') {
return Err(CreateError::InvalidInput(
"File names must not contain slashes!".to_string(),
Expand Down
43 changes: 0 additions & 43 deletions src/routes/v3/versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ pub struct EditVersion {
pub dependencies: Option<Vec<Dependency>>,
pub loaders: Option<Vec<Loader>>,
pub featured: Option<bool>,
pub primary_file: Option<(String, String)>,
pub downloads: Option<u32>,
pub status: Option<VersionStatus>,
pub file_types: Option<Vec<EditVersionFileType>>,
Expand Down Expand Up @@ -490,48 +489,6 @@ pub async fn version_edit_helper(
.await?;
}

if let Some(primary_file) = &new_version.primary_file {
let result = sqlx::query!(
"
SELECT f.id id FROM hashes h
INNER JOIN files f ON h.file_id = f.id
WHERE h.algorithm = $2 AND h.hash = $1
",
primary_file.1.as_bytes(),
primary_file.0
)
.fetch_optional(&**pool)
.await?
.ok_or_else(|| {
ApiError::InvalidInput(format!(
"Specified file with hash {} does not exist.",
primary_file.1.clone()
))
})?;

sqlx::query!(
"
UPDATE files
SET is_primary = FALSE
WHERE (version_id = $1)
",
id as database::models::ids::VersionId,
)
.execute(&mut *transaction)
.await?;

sqlx::query!(
"
UPDATE files
SET is_primary = TRUE
WHERE (id = $1)
",
result.id,
)
.execute(&mut *transaction)
.await?;
}

if let Some(body) = &new_version.changelog {
sqlx::query!(
"
Expand Down
6 changes: 5 additions & 1 deletion src/validate/modpack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ impl super::Validator for ModpackValidator {
(x.ends_with("jar") || x.ends_with("zip"))
&& (x.starts_with("overrides/mods")
|| x.starts_with("client-overrides/mods")
|| x.starts_with("server-overrides/mods"))
|| x.starts_with("server-overrides/mods")
|| x.starts_with("overrides/resourcepacks")
|| x.starts_with("server-overrides/resourcepacks")
|| x.starts_with("overrides/shaderpacks")
|| x.starts_with("client-overrides/shaderpacks"))
})
.flat_map(|x| x.rsplit('/').next().map(|x| x.to_string()))
.collect::<Vec<String>>(),
Expand Down
Loading