Repository: saleor/saleor

Issue:
Warehouse name is not stripped in validation
User can create a warehouse without a name by passing empty spaces as the name in API.

### Steps to reproduce the problem
1. Run this mutation:
```
mutation {
  createWarehouse(
    input: {
      name: " "
      slug: "test-12345"
      address: {
        country: PL
        city: "Test"
        streetAddress1: "Test"
        postalCode: "12-345"
      }
    }
  ) {
    warehouseErrors {
      field
      code
    }
    warehouse {
      id
      name
      slug
    }
  }
}
```
Note that `name` is ` `.

2. Mutation creates a warehouse with an empty name.

### What I expected to happen
I should get the error:
```
{
    "field": "name",
    "code": "REQUIRED"
},
```


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
@@ -108,3 +108,14 @@ def get_duplicates_ids(first_list, second_list):
 def get_duplicated_values(values):
     """Return set of duplicated values."""
     return {value for value in values if values.count(value) > 1}
+
+
+def validate_required_string_field(cleaned_input, field_name: str):
+    """Strip and validate field value."""
+    field_value = cleaned_input.get(field_name)
+    field_value = field_value.strip() if field_value else ""
+    if field_value:
+        cleaned_input[field_name] = field_value
+    else:
+        raise ValidationError(f"{field_name.capitalize()} is required.")
+    return cleaned_input
diff --git a/saleor/graphql/order/mutations/orders.py b/saleor/graphql/order/mutations/orders.py
--- a/saleor/graphql/order/mutations/orders.py
+++ b/saleor/graphql/order/mutations/orders.py
@@ -21,6 +21,7 @@
 from ...core.mutations import BaseMutation
 from ...core.scalars import UUID, Decimal
 from ...core.types.common import OrderError
+from ...core.utils import validate_required_string_field
 from ...meta.deprecated.mutations import ClearMetaBaseMutation, UpdateMetaBaseMutation
 from ...meta.deprecated.types import MetaInput, MetaPath
 from ...order.mutations.draft_orders import DraftOrderUpdate
@@ -282,8 +283,9 @@ class Meta:
 
     @classmethod
     def clean_input(cls, _info, _instance, data):
-        message = data["input"]["message"].strip()
-        if not message:
+        try:
+            cleaned_input = validate_required_string_field(data["input"], "message")
+        except ValidationError:
             raise ValidationError(
                 {
                     "message": ValidationError(
@@ -291,17 +293,14 @@ def clean_input(cls, _info, _instance, data):
                     )
                 }
             )
-        data["input"]["message"] = message
-        return data
+        return cleaned_input
 
     @classmethod
     def perform_mutation(cls, _root, info, **data):
         order = cls.get_node_or_error(info, data.get("id"), only_type=Order)
         cleaned_input = cls.clean_input(info, order, data)
         event = events.order_note_added_event(
-            order=order,
-            user=info.context.user,
-            message=cleaned_input["input"]["message"],
+            order=order, user=info.context.user, message=cleaned_input["message"],
         )
         return OrderAddNote(order=order, event=event)
 
diff --git a/saleor/graphql/warehouse/mutations.py b/saleor/graphql/warehouse/mutations.py
--- a/saleor/graphql/warehouse/mutations.py
+++ b/saleor/graphql/warehouse/mutations.py
@@ -8,7 +8,10 @@
 from ..account.i18n import I18nMixin
 from ..core.mutations import ModelDeleteMutation, ModelMutation
 from ..core.types.common import WarehouseError
-from ..core.utils import validate_slug_and_generate_if_needed
+from ..core.utils import (
+    validate_required_string_field,
+    validate_slug_and_generate_if_needed,
+)
 from ..shipping.types import ShippingZone
 from .types import Warehouse, WarehouseCreateInput, WarehouseUpdateInput
 
@@ -35,6 +38,14 @@ def clean_input(cls, info, instance, data, input_cls=None):
         except ValidationError as error:
             error.code = WarehouseErrorCode.REQUIRED.value
             raise ValidationError({"slug": error})
+
+        if "name" in cleaned_input:
+            try:
+                cleaned_input = validate_required_string_field(cleaned_input, "name")
+            except ValidationError as error:
+                error.code = WarehouseErrorCode.REQUIRED.value
+                raise ValidationError({"name": error})
+
         shipping_zones = cleaned_input.get("shipping_zones", [])
         if not validate_warehouse_count(shipping_zones, instance):
             msg = "Shipping zone can be assigned only to one warehouse."


Test patch:
diff --git a/saleor/graphql/warehouse/tests/test_warehouse.py b/saleor/graphql/warehouse/tests/test_warehouse.py
--- a/saleor/graphql/warehouse/tests/test_warehouse.py
+++ b/saleor/graphql/warehouse/tests/test_warehouse.py
@@ -339,7 +339,6 @@ def test_query_warehouses_with_filters_and_no_id(
 def test_mutation_create_warehouse(
     staff_api_client, permission_manage_products, shipping_zone
 ):
-    Warehouse.objects.all().delete()
     variables = {
         "input": {
             "name": "Test warehouse",
@@ -374,6 +373,41 @@ def test_mutation_create_warehouse(
     assert created_warehouse["slug"] == warehouse.slug
 
 
+def test_mutation_create_warehouse_does_not_create_when_name_is_empty_string(
+    staff_api_client, permission_manage_products, shipping_zone
+):
+    variables = {
+        "input": {
+            "name": "  ",
+            "slug": "test-warhouse",
+            "companyName": "Amazing Company Inc",
+            "email": "test-admin@example.com",
+            "address": {
+                "streetAddress1": "Teczowa 8",
+                "city": "Wroclaw",
+                "country": "PL",
+                "postalCode": "53-601",
+            },
+            "shippingZones": [
+                graphene.Node.to_global_id("ShippingZone", shipping_zone.id)
+            ],
+        }
+    }
+
+    response = staff_api_client.post_graphql(
+        MUTATION_CREATE_WAREHOUSE,
+        variables=variables,
+        permissions=[permission_manage_products],
+    )
+    content = get_graphql_content(response)
+    data = content["data"]["createWarehouse"]
+    errors = data["warehouseErrors"]
+    assert Warehouse.objects.count() == 0
+    assert len(errors) == 1
+    assert errors[0]["field"] == "name"
+    assert errors[0]["code"] == WarehouseErrorCode.REQUIRED.name
+
+
 def test_create_warehouse_creates_address(
     staff_api_client, permission_manage_products, shipping_zone
 ):
@@ -564,14 +598,16 @@ def test_update_warehouse_slug_exists(
 
 
 @pytest.mark.parametrize(
-    "input_slug, expected_slug, input_name, error_message, error_field",
+    "input_slug, expected_slug, input_name, expected_name, error_message, error_field",
     [
-        ("test-slug", "test-slug", "New name", None, None),
-        ("", "", "New name", "Slug value cannot be blank.", "slug"),
-        (None, "", "New name", "Slug value cannot be blank.", "slug"),
-        ("test-slug", "", None, "This field cannot be blank.", "name"),
-        ("test-slug", "", "", "This field cannot be blank.", "name"),
-        (None, None, None, "Slug value cannot be blank.", "slug"),
+        ("test-slug", "test-slug", "New name", "New name", None, None),
+        ("test-slug", "test-slug", " stripped ", "stripped", None, None,),
+        ("", "", "New name", "New name", "Slug value cannot be blank.", "slug"),
+        (None, "", "New name", "New name", "Slug value cannot be blank.", "slug"),
+        ("test-slug", "", None, None, "This field cannot be blank.", "name"),
+        ("test-slug", "", "", None, "This field cannot be blank.", "name"),
+        (None, None, None, None, "Slug value cannot be blank.", "slug"),
+        ("test-slug", "test-slug", "  ", None, "Name value cannot be blank", "name"),
     ],
 )
 def test_update_warehouse_slug_and_name(
@@ -581,6 +617,7 @@ def test_update_warehouse_slug_and_name(
     input_slug,
     expected_slug,
     input_name,
+    expected_name,
     error_message,
     error_field,
 ):
@@ -602,8 +639,10 @@ def test_update_warehouse_slug_and_name(
     data = content["data"]["updateWarehouse"]
     errors = data["warehouseErrors"]
     if not error_message:
-        assert data["warehouse"]["name"] == input_name == warehouse.name
-        assert data["warehouse"]["slug"] == input_slug == warehouse.slug
+        assert data["warehouse"]["name"] == expected_name == warehouse.name
+        assert (
+            data["warehouse"]["slug"] == input_slug == warehouse.slug == expected_slug
+        )
     else:
         assert errors
         assert errors[0]["field"] == error_field