diff --git a/django/thunderstore/repository/package_manifest.py b/django/thunderstore/repository/package_manifest.py index 0eeca6c94..70107c103 100644 --- a/django/thunderstore/repository/package_manifest.py +++ b/django/thunderstore/repository/package_manifest.py @@ -13,7 +13,11 @@ PackageVersionField, StrictCharField, ) -from thunderstore.repository.utils import does_contain_package, has_duplicate_packages +from thunderstore.repository.utils import ( + does_contain_package, + has_different_case, + has_duplicate_packages, +) class PackageInstallerSerializer(serializers.Serializer): @@ -96,6 +100,10 @@ def validate(self, data): ) if does_contain_package(result["dependencies"], reference): raise ValidationError("Package depending on itself is not allowed") + if has_different_case(reference.without_version): + raise ValidationError( + "Package name already exists with different capitalization" + ) return result def update(self, instance, validated_data): diff --git a/django/thunderstore/repository/package_reference.py b/django/thunderstore/repository/package_reference.py index 98e75c0b6..f380480ca 100644 --- a/django/thunderstore/repository/package_reference.py +++ b/django/thunderstore/repository/package_reference.py @@ -257,3 +257,15 @@ def exists(self) -> bool: :rtype: bool """ return self.queryset.exists() + + @cached_property + def exists_in_any_case(self) -> bool: + """ + Check if a package with a name with different capitalization exists in the db + + :return: True if a different case package exists, False otherwise + :rtype: bool + """ + return Package.objects.filter( + namespace=self.namespace, name__iexact=self.name + ).exists() diff --git a/django/thunderstore/repository/utils.py b/django/thunderstore/repository/utils.py index 0fb669594..b643c08a8 100644 --- a/django/thunderstore/repository/utils.py +++ b/django/thunderstore/repository/utils.py @@ -42,6 +42,14 @@ def has_duplicate_packages(packages: List["PackageReference"]) -> bool: return False +def has_different_case(reference: "PackageReference") -> bool: + if reference.exists: + return False + elif reference.exists_in_any_case: + return True + return False + + def unpack_serializer_errors(field, errors, error_dict=None): if error_dict is None: error_dict = {}