We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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)



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `saleor/graphql/core/utils/__init__.py`
Content:
```
1 import binascii
2 import os
3 import secrets
4 from typing import Literal, Tuple, Type, Union, overload
5 
6 import graphene
7 from django.core.exceptions import ValidationError
8 from graphene import ObjectType
9 from graphql.error import GraphQLError
10 
11 from ....plugins.const import APP_ID_PREFIX
12 from ..validators import validate_if_int_or_uuid
13 
14 
15 def snake_to_camel_case(name):
16     """Convert snake_case variable name to camelCase."""
17     if isinstance(name, str):
18         split_name = name.split("_")
19         return split_name[0] + "".join(map(str.capitalize, split_name[1:]))
20     return name
21 
22 
23 def str_to_enum(name):
24     """Create an enum value from a string."""
25     return name.replace(" ", "_").replace("-", "_").upper()
26 
27 
28 def get_duplicates_items(first_list, second_list):
29     """Return items that appear on both provided lists."""
30     if first_list and second_list:
31         return set(first_list) & set(second_list)
32     return []
33 
34 
35 def get_duplicated_values(values):
36     """Return set of duplicated values."""
37     return {value for value in values if values.count(value) > 1}
38 
39 
40 @overload
41 def from_global_id_or_error(
42     global_id: str,
43     only_type: Union[ObjectType, str, None] = None,
44     raise_error: Literal[True] = True,
45 ) -> Tuple[str, str]:
46     ...
47 
48 
49 @overload
50 def from_global_id_or_error(
51     global_id: str,
52     only_type: Union[Type[ObjectType], str, None] = None,
53     raise_error: bool = False,
54 ) -> Union[Tuple[str, str], Tuple[str, None]]:
55     ...
56 
57 
58 def from_global_id_or_error(
59     global_id: str,
60     only_type: Union[Type[ObjectType], str, None] = None,
61     raise_error: bool = False,
62 ):
63     """Resolve global ID or raise GraphQLError.
64 
65     Validates if given ID is a proper ID handled by Saleor.
66     Valid IDs formats, base64 encoded:
67     'app:<int>:<str>' : External app ID with 'app' prefix
68     '<type>:<int>' : Internal ID containing object type and ID as integer
69     '<type>:<UUID>' : Internal ID containing object type and UUID
70     Optionally validate the object type, if `only_type` is provided,
71     raise GraphQLError when `raise_error` is set to True.
72 
73     Returns tuple: (type, id).
74     """
75     try:
76         type_, id_ = graphene.Node.from_global_id(global_id)
77     except (binascii.Error, UnicodeDecodeError, ValueError):
78         raise GraphQLError(f"Couldn't resolve id: {global_id}.")
79     if type_ == APP_ID_PREFIX:
80         id_ = global_id
81     else:
82         if not validate_if_int_or_uuid(id_):
83             raise GraphQLError(f"Error occurred during ID - {global_id} validation.")
84 
85     if only_type and str(type_) != str(only_type):
86         if not raise_error:
87             return type_, None
88         raise GraphQLError(f"Must receive a {only_type} id.")
89     return type_, id_
90 
91 
92 def from_global_id_or_none(
93     global_id, only_type: Union[ObjectType, str, None] = None, raise_error: bool = False
94 ):
95     if not global_id:
96         return None
97 
98     return from_global_id_or_error(global_id, only_type, raise_error)[1]
99 
100 
101 def to_global_id_or_none(instance):
102     class_name = instance.__class__.__name__
103     if instance is None or instance.pk is None:
104         return None
105     return graphene.Node.to_global_id(class_name, instance.pk)
106 
107 
108 def add_hash_to_file_name(file):
109     """Add unique text fragment to the file name to prevent file overriding."""
110     file_name, format = os.path.splitext(file._name)
111     hash = secrets.token_hex(nbytes=4)
112     new_name = f"{file_name}_{hash}{format}"
113     file._name = new_name
114 
115 
116 def raise_validation_error(field=None, message=None, code=None):
117     raise ValidationError({field: ValidationError(message, code=code)})
118 
119 
120 def ext_ref_to_global_id_or_error(model, external_reference):
121     """Convert external reference to graphen global id."""
122     internal_id = (
123         model.objects.filter(external_reference=external_reference)
124         .values_list("id", flat=True)
125         .first()
126     )
127     if internal_id:
128         return graphene.Node.to_global_id(model.__name__, internal_id)
129     else:
130         raise_validation_error(
131             field="externalReference",
132             message=f"Couldn't resolve to a node: {external_reference}",
133             code="not_found",
134         )
135
```

Path: `saleor/graphql/core/validators/file.py`
Content:
```
1 import mimetypes
2 import os
3 import secrets
4 
5 import requests
6 from django.core.exceptions import ValidationError
7 from PIL import Image, UnidentifiedImageError
8 
9 from ....thumbnail import MIME_TYPE_TO_PIL_IDENTIFIER
10 from ..utils import add_hash_to_file_name
11 
12 Image.init()
13 
14 
15 def is_image_mimetype(mimetype: str) -> bool:
16     """Check if mimetype is image."""
17     if mimetype is None:
18         return False
19     return mimetype.startswith("image/")
20 
21 
22 def is_supported_image_mimetype(mimetype: str) -> bool:
23     """Check if mimetype is a mimetype that thumbnails support."""
24     if mimetype is None:
25         return False
26     return mimetype in MIME_TYPE_TO_PIL_IDENTIFIER.keys()
27 
28 
29 def is_image_url(url: str) -> bool:
30     """Check if file URL seems to be an image."""
31     if url.endswith(".webp"):
32         # webp is not recognized by mimetypes as image
33         # https://bugs.python.org/issue38902
34         return True
35     filetype = mimetypes.guess_type(url)[0]
36     return filetype is not None and is_image_mimetype(filetype)
37 
38 
39 def validate_image_url(url: str, field_name: str, error_code: str) -> None:
40     """Check if remote file has content type of image.
41 
42     Instead of the whole file, only the headers are fetched.
43     """
44     head = requests.head(url)
45     header = head.headers
46     content_type = header.get("content-type")
47     if content_type is None or not is_supported_image_mimetype(content_type):
48         raise ValidationError(
49             {field_name: ValidationError("Invalid file type.", code=error_code)}
50         )
51 
52 
53 def get_filename_from_url(url: str) -> str:
54     """Prepare unique filename for file from URL to avoid overwritting."""
55     file_name = os.path.basename(url)
56     name, format = os.path.splitext(file_name)
57     hash = secrets.token_hex(nbytes=4)
58     return f"{name}_{hash}{format}"
59 
60 
61 def clean_image_file(cleaned_input, img_field_name, error_class):
62     """Extract and clean uploaded image file.
63 
64     Validate if the file is an image supported by thumbnails.
65     """
66     img_file = cleaned_input.get(img_field_name)
67     if not img_file:
68         raise ValidationError(
69             {
70                 img_field_name: ValidationError(
71                     "File is required.", code=error_class.REQUIRED
72                 )
73             }
74         )
75     if not is_supported_image_mimetype(img_file.content_type):
76         raise ValidationError(
77             {
78                 img_field_name: ValidationError(
79                     "Invalid file type.", code=error_class.INVALID
80                 )
81             }
82         )
83 
84     _validate_image_format(img_file, img_field_name, error_class)
85     try:
86         with Image.open(img_file) as image:
87             _validate_image_exif(image, img_field_name, error_class)
88     except (SyntaxError, TypeError, UnidentifiedImageError) as e:
89         raise ValidationError(
90             {
91                 img_field_name: ValidationError(
92                     "Invalid file. The following error was raised during the attempt "
93                     f"of opening the file: {str(e)}",
94                     code=error_class.INVALID.value,
95                 )
96             }
97         )
98 
99     add_hash_to_file_name(img_file)
100     return img_file
101 
102 
103 def _validate_image_format(file, field_name, error_class):
104     """Validate image file format."""
105     allowed_extensions = _get_allowed_extensions()
106     _file_name, format = os.path.splitext(file._name)
107     if not format:
108         raise ValidationError(
109             {
110                 field_name: ValidationError(
111                     "Lack of file extension.", code=error_class.INVALID
112                 )
113             }
114         )
115     elif format not in allowed_extensions:
116         raise ValidationError(
117             {
118                 field_name: ValidationError(
119                     "Invalid file extension. Image file required.",
120                     code=error_class.INVALID,
121                 )
122             }
123         )
124 
125 
126 def _get_allowed_extensions():
127     """Return image extension lists that are supported by thumbnails."""
128     return [
129         ext.lower()
130         for ext, file_type in Image.EXTENSION.items()
131         if file_type.upper() in MIME_TYPE_TO_PIL_IDENTIFIER.values()
132     ]
133 
134 
135 def _validate_image_exif(img, field_name, error_class):
136     try:
137         img.getexif()
138     except (SyntaxError, TypeError, UnidentifiedImageError) as e:
139         raise ValidationError(
140             {
141                 field_name: ValidationError(
142                     "Invalid file. The following error was raised during the attempt "
143                     f"of getting the exchangeable image file data: {str(e)}.",
144                     code=error_class.INVALID.value,
145                 )
146             }
147         )
148
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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 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 @@
     """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}"

{"golden_diff": "diff --git a/saleor/graphql/core/utils/__init__.py b/saleor/graphql/core/utils/__init__.py\n--- a/saleor/graphql/core/utils/__init__.py\n+++ b/saleor/graphql/core/utils/__init__.py\n@@ -11,6 +11,8 @@\n from ....plugins.webhook.utils import APP_ID_PREFIX\n from ..validators import validate_if_int_or_uuid\n \n+FILE_NAME_MAX_LENGTH = 55\n+\n \n def snake_to_camel_case(name):\n     \"\"\"Convert snake_case variable name to camelCase.\"\"\"\n@@ -108,6 +110,7 @@\n def add_hash_to_file_name(file):\n     \"\"\"Add unique text fragment to the file name to prevent file overriding.\"\"\"\n     file_name, format = os.path.splitext(file._name)\n+    file_name = file_name[:FILE_NAME_MAX_LENGTH]\n     hash = secrets.token_hex(nbytes=4)\n     new_name = f\"{file_name}_{hash}{format}\"\n     file._name = new_name\ndiff --git a/saleor/graphql/core/validators/file.py b/saleor/graphql/core/validators/file.py\n--- a/saleor/graphql/core/validators/file.py\n+++ b/saleor/graphql/core/validators/file.py\n@@ -7,7 +7,7 @@\n from PIL import Image, UnidentifiedImageError\n \n from ....thumbnail import MIME_TYPE_TO_PIL_IDENTIFIER\n-from ..utils import add_hash_to_file_name\n+from ..utils import FILE_NAME_MAX_LENGTH, add_hash_to_file_name\n \n Image.init()\n \n@@ -54,6 +54,7 @@\n     \"\"\"Prepare unique filename for file from URL to avoid overwritting.\"\"\"\n     file_name = os.path.basename(url)\n     name, format = os.path.splitext(file_name)\n+    name = name[:FILE_NAME_MAX_LENGTH]\n     hash = secrets.token_hex(nbytes=4)\n     return f\"{name}_{hash}{format}\"\n", "issue": "Bug: Upload an image to product with really long name it generates only one thumbnail size.\n### What are you trying to achieve?\r\n\r\nThumbnails of different sizes should be generated regardless of the file name\r\n\r\n### Steps to reproduce the problem\r\n\r\n1. Go to the product page and upload an image with a long name `2Fvar2Ffolders2Fbj2F61gtb14j7rz4_4yd15tnkzjh0000gn2FT2Ftmp7yvuo2a1_30519a02`\r\n2. Query thumbnails for the product:\r\n```\r\nquery Product{\r\n  product(id: \"UHJvZHVjdDo4Nzk=\"){\r\n    id\r\n    thumbnail{\r\n      alt\r\n      url\r\n    }\r\n    thumbnailx2: thumbnail(size: 1024){\r\n      alt\r\n      url\r\n    }\r\n    media{\r\n      url\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nCurrent result: \r\nIn the response, it looks like thumbnails were generated \r\n```\r\n{\r\n  \"data\": {\r\n    \"product\": {\r\n      \"id\": \"UHJvZHVjdDo2MDk=\",\r\n      \"thumbnail\": {\r\n        \"alt\": \"\",\r\n        \"url\": \"https://*.staging.saleor.cloud/thumbnail/UHJvZHVjdE1lZGlhOjE3NzI=/256/\"\r\n      },\r\n      \"thumbnailx2\": {\r\n        \"alt\": \"\",\r\n        \"url\": \"https://*.staging.saleor.cloud/thumbnail/UHJvZHVjdE1lZGlhOjE3NzI=/1024/\"\r\n      },\r\n      \"media\": [\r\n        {\r\n          \"url\": \"https://*.staging.saleor.cloud/media/thumbnails/products/2Fvar2Ffolders2Fbj2F61gtb14j7rz4_4yd15tnkzjh0000gn2FT2Ftmp7yvuo2a1_30519a02.webp\"\r\n        }\r\n      ]\r\n    }\r\n  },\r\n```\r\nbut 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`\r\n\r\nhttps://saleorcommerce.slack.com/archives/C039MGJDWU8/p1678795547580359\r\n\r\n### What did you expect to happen?\r\n\r\nThumbnails are generated in proper size\r\n\r\n### Logs\r\n\r\n_No response_\r\n\r\n### Environment\r\n\r\nSaleor version: core v3.13.0-a (3.7.52 and 3.9.12)\r\n\r\n\n", "before_files": [{"content": "import binascii\nimport os\nimport secrets\nfrom typing import Literal, Tuple, Type, Union, overload\n\nimport graphene\nfrom django.core.exceptions import ValidationError\nfrom graphene import ObjectType\nfrom graphql.error import GraphQLError\n\nfrom ....plugins.const import APP_ID_PREFIX\nfrom ..validators import validate_if_int_or_uuid\n\n\ndef snake_to_camel_case(name):\n    \"\"\"Convert snake_case variable name to camelCase.\"\"\"\n    if isinstance(name, str):\n        split_name = name.split(\"_\")\n        return split_name[0] + \"\".join(map(str.capitalize, split_name[1:]))\n    return name\n\n\ndef str_to_enum(name):\n    \"\"\"Create an enum value from a string.\"\"\"\n    return name.replace(\" \", \"_\").replace(\"-\", \"_\").upper()\n\n\ndef get_duplicates_items(first_list, second_list):\n    \"\"\"Return items that appear on both provided lists.\"\"\"\n    if first_list and second_list:\n        return set(first_list) & set(second_list)\n    return []\n\n\ndef get_duplicated_values(values):\n    \"\"\"Return set of duplicated values.\"\"\"\n    return {value for value in values if values.count(value) > 1}\n\n\n@overload\ndef from_global_id_or_error(\n    global_id: str,\n    only_type: Union[ObjectType, str, None] = None,\n    raise_error: Literal[True] = True,\n) -> Tuple[str, str]:\n    ...\n\n\n@overload\ndef from_global_id_or_error(\n    global_id: str,\n    only_type: Union[Type[ObjectType], str, None] = None,\n    raise_error: bool = False,\n) -> Union[Tuple[str, str], Tuple[str, None]]:\n    ...\n\n\ndef from_global_id_or_error(\n    global_id: str,\n    only_type: Union[Type[ObjectType], str, None] = None,\n    raise_error: bool = False,\n):\n    \"\"\"Resolve global ID or raise GraphQLError.\n\n    Validates if given ID is a proper ID handled by Saleor.\n    Valid IDs formats, base64 encoded:\n    'app:<int>:<str>' : External app ID with 'app' prefix\n    '<type>:<int>' : Internal ID containing object type and ID as integer\n    '<type>:<UUID>' : Internal ID containing object type and UUID\n    Optionally validate the object type, if `only_type` is provided,\n    raise GraphQLError when `raise_error` is set to True.\n\n    Returns tuple: (type, id).\n    \"\"\"\n    try:\n        type_, id_ = graphene.Node.from_global_id(global_id)\n    except (binascii.Error, UnicodeDecodeError, ValueError):\n        raise GraphQLError(f\"Couldn't resolve id: {global_id}.\")\n    if type_ == APP_ID_PREFIX:\n        id_ = global_id\n    else:\n        if not validate_if_int_or_uuid(id_):\n            raise GraphQLError(f\"Error occurred during ID - {global_id} validation.\")\n\n    if only_type and str(type_) != str(only_type):\n        if not raise_error:\n            return type_, None\n        raise GraphQLError(f\"Must receive a {only_type} id.\")\n    return type_, id_\n\n\ndef from_global_id_or_none(\n    global_id, only_type: Union[ObjectType, str, None] = None, raise_error: bool = False\n):\n    if not global_id:\n        return None\n\n    return from_global_id_or_error(global_id, only_type, raise_error)[1]\n\n\ndef to_global_id_or_none(instance):\n    class_name = instance.__class__.__name__\n    if instance is None or instance.pk is None:\n        return None\n    return graphene.Node.to_global_id(class_name, instance.pk)\n\n\ndef add_hash_to_file_name(file):\n    \"\"\"Add unique text fragment to the file name to prevent file overriding.\"\"\"\n    file_name, format = os.path.splitext(file._name)\n    hash = secrets.token_hex(nbytes=4)\n    new_name = f\"{file_name}_{hash}{format}\"\n    file._name = new_name\n\n\ndef raise_validation_error(field=None, message=None, code=None):\n    raise ValidationError({field: ValidationError(message, code=code)})\n\n\ndef ext_ref_to_global_id_or_error(model, external_reference):\n    \"\"\"Convert external reference to graphen global id.\"\"\"\n    internal_id = (\n        model.objects.filter(external_reference=external_reference)\n        .values_list(\"id\", flat=True)\n        .first()\n    )\n    if internal_id:\n        return graphene.Node.to_global_id(model.__name__, internal_id)\n    else:\n        raise_validation_error(\n            field=\"externalReference\",\n            message=f\"Couldn't resolve to a node: {external_reference}\",\n            code=\"not_found\",\n        )\n", "path": "saleor/graphql/core/utils/__init__.py"}, {"content": "import mimetypes\nimport os\nimport secrets\n\nimport requests\nfrom django.core.exceptions import ValidationError\nfrom PIL import Image, UnidentifiedImageError\n\nfrom ....thumbnail import MIME_TYPE_TO_PIL_IDENTIFIER\nfrom ..utils import add_hash_to_file_name\n\nImage.init()\n\n\ndef is_image_mimetype(mimetype: str) -> bool:\n    \"\"\"Check if mimetype is image.\"\"\"\n    if mimetype is None:\n        return False\n    return mimetype.startswith(\"image/\")\n\n\ndef is_supported_image_mimetype(mimetype: str) -> bool:\n    \"\"\"Check if mimetype is a mimetype that thumbnails support.\"\"\"\n    if mimetype is None:\n        return False\n    return mimetype in MIME_TYPE_TO_PIL_IDENTIFIER.keys()\n\n\ndef is_image_url(url: str) -> bool:\n    \"\"\"Check if file URL seems to be an image.\"\"\"\n    if url.endswith(\".webp\"):\n        # webp is not recognized by mimetypes as image\n        # https://bugs.python.org/issue38902\n        return True\n    filetype = mimetypes.guess_type(url)[0]\n    return filetype is not None and is_image_mimetype(filetype)\n\n\ndef validate_image_url(url: str, field_name: str, error_code: str) -> None:\n    \"\"\"Check if remote file has content type of image.\n\n    Instead of the whole file, only the headers are fetched.\n    \"\"\"\n    head = requests.head(url)\n    header = head.headers\n    content_type = header.get(\"content-type\")\n    if content_type is None or not is_supported_image_mimetype(content_type):\n        raise ValidationError(\n            {field_name: ValidationError(\"Invalid file type.\", code=error_code)}\n        )\n\n\ndef get_filename_from_url(url: str) -> str:\n    \"\"\"Prepare unique filename for file from URL to avoid overwritting.\"\"\"\n    file_name = os.path.basename(url)\n    name, format = os.path.splitext(file_name)\n    hash = secrets.token_hex(nbytes=4)\n    return f\"{name}_{hash}{format}\"\n\n\ndef clean_image_file(cleaned_input, img_field_name, error_class):\n    \"\"\"Extract and clean uploaded image file.\n\n    Validate if the file is an image supported by thumbnails.\n    \"\"\"\n    img_file = cleaned_input.get(img_field_name)\n    if not img_file:\n        raise ValidationError(\n            {\n                img_field_name: ValidationError(\n                    \"File is required.\", code=error_class.REQUIRED\n                )\n            }\n        )\n    if not is_supported_image_mimetype(img_file.content_type):\n        raise ValidationError(\n            {\n                img_field_name: ValidationError(\n                    \"Invalid file type.\", code=error_class.INVALID\n                )\n            }\n        )\n\n    _validate_image_format(img_file, img_field_name, error_class)\n    try:\n        with Image.open(img_file) as image:\n            _validate_image_exif(image, img_field_name, error_class)\n    except (SyntaxError, TypeError, UnidentifiedImageError) as e:\n        raise ValidationError(\n            {\n                img_field_name: ValidationError(\n                    \"Invalid file. The following error was raised during the attempt \"\n                    f\"of opening the file: {str(e)}\",\n                    code=error_class.INVALID.value,\n                )\n            }\n        )\n\n    add_hash_to_file_name(img_file)\n    return img_file\n\n\ndef _validate_image_format(file, field_name, error_class):\n    \"\"\"Validate image file format.\"\"\"\n    allowed_extensions = _get_allowed_extensions()\n    _file_name, format = os.path.splitext(file._name)\n    if not format:\n        raise ValidationError(\n            {\n                field_name: ValidationError(\n                    \"Lack of file extension.\", code=error_class.INVALID\n                )\n            }\n        )\n    elif format not in allowed_extensions:\n        raise ValidationError(\n            {\n                field_name: ValidationError(\n                    \"Invalid file extension. Image file required.\",\n                    code=error_class.INVALID,\n                )\n            }\n        )\n\n\ndef _get_allowed_extensions():\n    \"\"\"Return image extension lists that are supported by thumbnails.\"\"\"\n    return [\n        ext.lower()\n        for ext, file_type in Image.EXTENSION.items()\n        if file_type.upper() in MIME_TYPE_TO_PIL_IDENTIFIER.values()\n    ]\n\n\ndef _validate_image_exif(img, field_name, error_class):\n    try:\n        img.getexif()\n    except (SyntaxError, TypeError, UnidentifiedImageError) as e:\n        raise ValidationError(\n            {\n                field_name: ValidationError(\n                    \"Invalid file. The following error was raised during the attempt \"\n                    f\"of getting the exchangeable image file data: {str(e)}.\",\n                    code=error_class.INVALID.value,\n                )\n            }\n        )\n", "path": "saleor/graphql/core/validators/file.py"}], "after_files": [{"content": "import binascii\nimport os\nimport secrets\nfrom typing import Literal, Tuple, Type, Union, overload\n\nimport graphene\nfrom django.core.exceptions import ValidationError\nfrom graphene import ObjectType\nfrom graphql.error import GraphQLError\n\nfrom ....plugins.webhook.utils import APP_ID_PREFIX\nfrom ..validators import validate_if_int_or_uuid\n\nFILE_NAME_MAX_LENGTH = 55\n\n\ndef snake_to_camel_case(name):\n    \"\"\"Convert snake_case variable name to camelCase.\"\"\"\n    if isinstance(name, str):\n        split_name = name.split(\"_\")\n        return split_name[0] + \"\".join(map(str.capitalize, split_name[1:]))\n    return name\n\n\ndef str_to_enum(name):\n    \"\"\"Create an enum value from a string.\"\"\"\n    return name.replace(\" \", \"_\").replace(\"-\", \"_\").upper()\n\n\ndef get_duplicates_items(first_list, second_list):\n    \"\"\"Return items that appear on both provided lists.\"\"\"\n    if first_list and second_list:\n        return set(first_list) & set(second_list)\n    return []\n\n\ndef get_duplicated_values(values):\n    \"\"\"Return set of duplicated values.\"\"\"\n    return {value for value in values if values.count(value) > 1}\n\n\n@overload\ndef from_global_id_or_error(\n    global_id: str,\n    only_type: Union[ObjectType, str, None] = None,\n    raise_error: Literal[True] = True,\n) -> Tuple[str, str]:\n    ...\n\n\n@overload\ndef from_global_id_or_error(\n    global_id: str,\n    only_type: Union[Type[ObjectType], str, None] = None,\n    raise_error: bool = False,\n) -> Union[Tuple[str, str], Tuple[str, None]]:\n    ...\n\n\ndef from_global_id_or_error(\n    global_id: str,\n    only_type: Union[Type[ObjectType], str, None] = None,\n    raise_error: bool = False,\n):\n    \"\"\"Resolve global ID or raise GraphQLError.\n\n    Validates if given ID is a proper ID handled by Saleor.\n    Valid IDs formats, base64 encoded:\n    'app:<int>:<str>' : External app ID with 'app' prefix\n    '<type>:<int>' : Internal ID containing object type and ID as integer\n    '<type>:<UUID>' : Internal ID containing object type and UUID\n    Optionally validate the object type, if `only_type` is provided,\n    raise GraphQLError when `raise_error` is set to True.\n\n    Returns tuple: (type, id).\n    \"\"\"\n    try:\n        type_, id_ = graphene.Node.from_global_id(global_id)\n    except (binascii.Error, UnicodeDecodeError, ValueError):\n        raise GraphQLError(f\"Couldn't resolve id: {global_id}.\")\n    if type_ == APP_ID_PREFIX:\n        id_ = global_id\n    else:\n        if not validate_if_int_or_uuid(id_):\n            raise GraphQLError(f\"Error occurred during ID - {global_id} validation.\")\n\n    if only_type and str(type_) != str(only_type):\n        if not raise_error:\n            return type_, None\n        raise GraphQLError(f\"Must receive a {only_type} id.\")\n    return type_, id_\n\n\ndef from_global_id_or_none(\n    global_id, only_type: Union[ObjectType, str, None] = None, raise_error: bool = False\n):\n    if not global_id:\n        return None\n\n    return from_global_id_or_error(global_id, only_type, raise_error)[1]\n\n\ndef to_global_id_or_none(instance):\n    class_name = instance.__class__.__name__\n    if instance is None or instance.pk is None:\n        return None\n    return graphene.Node.to_global_id(class_name, instance.pk)\n\n\ndef add_hash_to_file_name(file):\n    \"\"\"Add unique text fragment to the file name to prevent file overriding.\"\"\"\n    file_name, format = os.path.splitext(file._name)\n    file_name = file_name[:FILE_NAME_MAX_LENGTH]\n    hash = secrets.token_hex(nbytes=4)\n    new_name = f\"{file_name}_{hash}{format}\"\n    file._name = new_name\n\n\ndef raise_validation_error(field=None, message=None, code=None):\n    raise ValidationError({field: ValidationError(message, code=code)})\n\n\ndef ext_ref_to_global_id_or_error(model, external_reference):\n    \"\"\"Convert external reference to graphen global id.\"\"\"\n    internal_id = (\n        model.objects.filter(external_reference=external_reference)\n        .values_list(\"id\", flat=True)\n        .first()\n    )\n    if internal_id:\n        return graphene.Node.to_global_id(model.__name__, internal_id)\n    else:\n        raise_validation_error(\n            field=\"externalReference\",\n            message=f\"Couldn't resolve to a node: {external_reference}\",\n            code=\"not_found\",\n        )\n", "path": "saleor/graphql/core/utils/__init__.py"}, {"content": "import mimetypes\nimport os\nimport secrets\n\nimport requests\nfrom django.core.exceptions import ValidationError\nfrom PIL import Image, UnidentifiedImageError\n\nfrom ....thumbnail import MIME_TYPE_TO_PIL_IDENTIFIER\nfrom ..utils import FILE_NAME_MAX_LENGTH, add_hash_to_file_name\n\nImage.init()\n\n\ndef is_image_mimetype(mimetype: str) -> bool:\n    \"\"\"Check if mimetype is image.\"\"\"\n    if mimetype is None:\n        return False\n    return mimetype.startswith(\"image/\")\n\n\ndef is_supported_image_mimetype(mimetype: str) -> bool:\n    \"\"\"Check if mimetype is a mimetype that thumbnails support.\"\"\"\n    if mimetype is None:\n        return False\n    return mimetype in MIME_TYPE_TO_PIL_IDENTIFIER.keys()\n\n\ndef is_image_url(url: str) -> bool:\n    \"\"\"Check if file URL seems to be an image.\"\"\"\n    if url.endswith(\".webp\"):\n        # webp is not recognized by mimetypes as image\n        # https://bugs.python.org/issue38902\n        return True\n    filetype = mimetypes.guess_type(url)[0]\n    return filetype is not None and is_image_mimetype(filetype)\n\n\ndef validate_image_url(url: str, field_name: str, error_code: str) -> None:\n    \"\"\"Check if remote file has content type of image.\n\n    Instead of the whole file, only the headers are fetched.\n    \"\"\"\n    head = requests.head(url)\n    header = head.headers\n    content_type = header.get(\"content-type\")\n    if content_type is None or not is_supported_image_mimetype(content_type):\n        raise ValidationError(\n            {field_name: ValidationError(\"Invalid file type.\", code=error_code)}\n        )\n\n\ndef get_filename_from_url(url: str) -> str:\n    \"\"\"Prepare unique filename for file from URL to avoid overwritting.\"\"\"\n    file_name = os.path.basename(url)\n    name, format = os.path.splitext(file_name)\n    name = name[:FILE_NAME_MAX_LENGTH]\n    hash = secrets.token_hex(nbytes=4)\n    return f\"{name}_{hash}{format}\"\n\n\ndef clean_image_file(cleaned_input, img_field_name, error_class):\n    \"\"\"Extract and clean uploaded image file.\n\n    Validate if the file is an image supported by thumbnails.\n    \"\"\"\n    img_file = cleaned_input.get(img_field_name)\n    if not img_file:\n        raise ValidationError(\n            {\n                img_field_name: ValidationError(\n                    \"File is required.\", code=error_class.REQUIRED\n                )\n            }\n        )\n    if not is_supported_image_mimetype(img_file.content_type):\n        raise ValidationError(\n            {\n                img_field_name: ValidationError(\n                    \"Invalid file type.\", code=error_class.INVALID\n                )\n            }\n        )\n\n    _validate_image_format(img_file, img_field_name, error_class)\n    try:\n        with Image.open(img_file) as image:\n            _validate_image_exif(image, img_field_name, error_class)\n    except (SyntaxError, TypeError, UnidentifiedImageError) as e:\n        raise ValidationError(\n            {\n                img_field_name: ValidationError(\n                    \"Invalid file. The following error was raised during the attempt \"\n                    f\"of opening the file: {str(e)}\",\n                    code=error_class.INVALID.value,\n                )\n            }\n        )\n\n    add_hash_to_file_name(img_file)\n    return img_file\n\n\ndef _validate_image_format(file, field_name, error_class):\n    \"\"\"Validate image file format.\"\"\"\n    allowed_extensions = _get_allowed_extensions()\n    _file_name, format = os.path.splitext(file._name)\n    if not format:\n        raise ValidationError(\n            {\n                field_name: ValidationError(\n                    \"Lack of file extension.\", code=error_class.INVALID\n                )\n            }\n        )\n    elif format not in allowed_extensions:\n        raise ValidationError(\n            {\n                field_name: ValidationError(\n                    \"Invalid file extension. Image file required.\",\n                    code=error_class.INVALID,\n                )\n            }\n        )\n\n\ndef _get_allowed_extensions():\n    \"\"\"Return image extension lists that are supported by thumbnails.\"\"\"\n    return [\n        ext.lower()\n        for ext, file_type in Image.EXTENSION.items()\n        if file_type.upper() in MIME_TYPE_TO_PIL_IDENTIFIER.values()\n    ]\n\n\ndef _validate_image_exif(img, field_name, error_class):\n    try:\n        img.getexif()\n    except (SyntaxError, TypeError, UnidentifiedImageError) as e:\n        raise ValidationError(\n            {\n                field_name: ValidationError(\n                    \"Invalid file. The following error was raised during the attempt \"\n                    f\"of getting the exchangeable image file data: {str(e)}.\",\n                    code=error_class.INVALID.value,\n                )\n            }\n        )\n", "path": "saleor/graphql/core/validators/file.py"}]}