Repository: saleor/saleor

Issue:
Bug: Upload an image to product with really long name it generates only one thumbnail size.
### What are you trying to achieve?

Thumbnails of different sizes should be generated regardless of the file name

### Steps to reproduce the problem

1. Go to the product page and upload an image with a long name `2Fvar2Ffolders2Fbj2F61gtb14j7rz4_4yd15tnkzjh0000gn2FT2Ftmp7yvuo2a1_30519a02`
2. Query thumbnails for the product:
```
query Product{
  product(id: "UHJvZHVjdDo4Nzk="){
    id
    thumbnail{
      alt
      url
    }
    thumbnailx2: thumbnail(size: 1024){
      alt
      url
    }
    media{
      url
    }
  }
}
```

Current result: 
In the response, it looks like thumbnails were generated 
```
{
  "data": {
    "product": {
      "id": "UHJvZHVjdDo2MDk=",
      "thumbnail": {
        "alt": "",
        "url": "https://*.staging.saleor.cloud/thumbnail/UHJvZHVjdE1lZGlhOjE3NzI=/256/"
      },
      "thumbnailx2": {
        "alt": "",
        "url": "https://*.staging.saleor.cloud/thumbnail/UHJvZHVjdE1lZGlhOjE3NzI=/1024/"
      },
      "media": [
        {
          "url": "https://*.staging.saleor.cloud/media/thumbnails/products/2Fvar2Ffolders2Fbj2F61gtb14j7rz4_4yd15tnkzjh0000gn2FT2Ftmp7yvuo2a1_30519a02.webp"
        }
      ]
    }
  },
```
but when entering the URL `https://*.staging.saleor.cloud/thumbnail/UHJvZHVjdE1lZGlhOjE3NzI=/256/` it changed to the original media URL `https://*.staging.saleor.cloud/media/thumbnails/products/2Fvar2Ffolders2Fbj2F61gtb14j7rz4_4yd15tnkzjh0000gn2FT2Ftmp7yvuo2a1_30519a02.webp`

https://saleorcommerce.slack.com/archives/C039MGJDWU8/p1678795547580359

### What did you expect to happen?

Thumbnails are generated in proper size

### Logs

_No response_

### Environment

Saleor version: core v3.13.0-a (3.7.52 and 3.9.12)




Discussion:

Resolving patch:
diff --git a/saleor/graphql/core/utils/__init__.py b/saleor/graphql/core/utils/__init__.py
--- a/saleor/graphql/core/utils/__init__.py
+++ b/saleor/graphql/core/utils/__init__.py
@@ -11,6 +11,8 @@
 from ....plugins.webhook.utils import APP_ID_PREFIX
 from ..validators import validate_if_int_or_uuid
 
+FILE_NAME_MAX_LENGTH = 55
+
 
 def snake_to_camel_case(name):
     """Convert snake_case variable name to camelCase."""
@@ -108,6 +110,7 @@ def to_global_id_or_none(instance):
 def add_hash_to_file_name(file):
     """Add unique text fragment to the file name to prevent file overriding."""
     file_name, format = os.path.splitext(file._name)
+    file_name = file_name[:FILE_NAME_MAX_LENGTH]
     hash = secrets.token_hex(nbytes=4)
     new_name = f"{file_name}_{hash}{format}"
     file._name = new_name
diff --git a/saleor/graphql/core/validators/file.py b/saleor/graphql/core/validators/file.py
--- a/saleor/graphql/core/validators/file.py
+++ b/saleor/graphql/core/validators/file.py
@@ -7,7 +7,7 @@
 from PIL import Image, UnidentifiedImageError
 
 from ....thumbnail import MIME_TYPE_TO_PIL_IDENTIFIER
-from ..utils import add_hash_to_file_name
+from ..utils import FILE_NAME_MAX_LENGTH, add_hash_to_file_name
 
 Image.init()
 
@@ -54,6 +54,7 @@ def get_filename_from_url(url: str) -> str:
     """Prepare unique filename for file from URL to avoid overwritting."""
     file_name = os.path.basename(url)
     name, format = os.path.splitext(file_name)
+    name = name[:FILE_NAME_MAX_LENGTH]
     hash = secrets.token_hex(nbytes=4)
     return f"{name}_{hash}{format}"
 


Test patch:
diff --git a/saleor/graphql/core/tests/test_core.py b/saleor/graphql/core/tests/test_core.py
--- a/saleor/graphql/core/tests/test_core.py
+++ b/saleor/graphql/core/tests/test_core.py
@@ -21,6 +21,7 @@
 from ..mutations import BaseMutation, ModelWithExtRefMutation
 from ..types import FilterInputObjectType
 from ..utils import (
+    FILE_NAME_MAX_LENGTH,
     add_hash_to_file_name,
     ext_ref_to_global_id_or_error,
     get_duplicated_values,
@@ -304,6 +305,35 @@ def test_add_hash_to_file_name(image, media_root):
     assert image._name.endswith(format)
 
 
+def test_short_file_name_is_not_trimmed(image, media_root):
+    image._name = "image"
+    previous_file_name = image._name
+    assert len(previous_file_name) < FILE_NAME_MAX_LENGTH
+
+    add_hash_to_file_name(image)
+
+    assert previous_file_name != image._name
+    file_name, format = os.path.splitext(image._name)
+    assert image._name.startswith(file_name)
+    assert image._name.endswith(format)
+    assert len(image._name.split("_")[0]) < FILE_NAME_MAX_LENGTH
+
+
+def test_long_file_name_is_trimmed(image, media_root):
+    image._name = "2Fvar2Ffolders2Fbj2F61gtb14j7rz474yd15tnkzjh0000gn2FT2Fa"
+    previous_file_name = image._name
+    assert len(previous_file_name) > FILE_NAME_MAX_LENGTH
+
+    add_hash_to_file_name(image)
+
+    assert previous_file_name != image._name
+    file_name, format = os.path.splitext(image._name)
+    assert image._name.startswith(file_name)
+    assert image._name.startswith(file_name[:FILE_NAME_MAX_LENGTH])
+    assert image._name.endswith(format)
+    assert len(image._name.split("_")[0]) == FILE_NAME_MAX_LENGTH
+
+
 def test_external_reference_to_global_id(product):
     # given
     product.external_reference = "test-ext-id"
diff --git a/saleor/graphql/core/tests/test_file_validation.py b/saleor/graphql/core/tests/test_file_validation.py
--- a/saleor/graphql/core/tests/test_file_validation.py
+++ b/saleor/graphql/core/tests/test_file_validation.py
@@ -7,6 +7,7 @@
 from PIL import Image
 
 from ....product.error_codes import ProductErrorCode
+from ...core.utils import FILE_NAME_MAX_LENGTH
 from ..validators.file import (
     clean_image_file,
     get_filename_from_url,
@@ -31,6 +32,40 @@ def test_get_filename_from_url_unique():
     assert result != f"{file_name}.{file_format}"
 
 
+def test_get_filename_from_url_with_long_name_is_trimmed():
+    # given
+    file_format = "jpg"
+    file_name = "2Fvar2Ffolders2Fbj2F61gtb14j7rz474yd15tnkzjh0000gn2FT2Fa"
+    assert len(file_name) > FILE_NAME_MAX_LENGTH
+    url = f"http://example.com/{file_name}.{file_format}"
+
+    # when
+    result = get_filename_from_url(url)
+
+    # then
+    assert result.startswith(file_name[:FILE_NAME_MAX_LENGTH])
+    assert result.endswith(file_format)
+    assert result != f"{file_name}.{file_format}"
+    assert len(result.split("_")[0]) == FILE_NAME_MAX_LENGTH
+
+
+def test_get_filename_from_url_with_short_name_is_not_trimmed():
+    # given
+    file_format = "jpg"
+    file_name = "short"
+    assert len(file_name) < FILE_NAME_MAX_LENGTH
+    url = f"http://example.com/{file_name}.{file_format}"
+
+    # when
+    result = get_filename_from_url(url)
+
+    # then
+    assert result.startswith(file_name)
+    assert result.endswith(file_format)
+    assert result != f"{file_name}.{file_format}"
+    assert len(result.split("_")[0]) < FILE_NAME_MAX_LENGTH
+
+
 def test_is_image_mimetype_valid_mimetype():
     # given
     valid_mimetype = "image/jpeg"