Repository: saleor/saleor

Issue:
It should not be possible to add empty order note
### What I'm trying to achieve
To add empty order note.

### What I expected to happen
I expect mutation to throw an error.

References https://github.com/mirumee/saleor-dashboard/issues/423


Discussion:

Resolving patch:
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
@@ -255,7 +255,9 @@ def perform_mutation(cls, _root, info, **data):
 
 
 class OrderAddNoteInput(graphene.InputObjectType):
-    message = graphene.String(description="Note message.", name="message")
+    message = graphene.String(
+        description="Note message.", name="message", required=True
+    )
 
 
 class OrderAddNote(BaseMutation):
@@ -278,11 +280,28 @@ class Meta:
         error_type_class = OrderError
         error_type_field = "order_errors"
 
+    @classmethod
+    def clean_input(cls, _info, _instance, data):
+        message = data["input"]["message"].strip()
+        if not message:
+            raise ValidationError(
+                {
+                    "message": ValidationError(
+                        "Message can't be empty.", code=OrderErrorCode.REQUIRED,
+                    )
+                }
+            )
+        data["input"]["message"] = message
+        return data
+
     @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=data.get("input")["message"]
+            order=order,
+            user=info.context.user,
+            message=cleaned_input["input"]["message"],
         )
         return OrderAddNote(order=order, event=event)
 


Test patch:
diff --git a/tests/api/test_order.py b/tests/api/test_order.py
--- a/tests/api/test_order.py
+++ b/tests/api/test_order.py
@@ -1339,37 +1339,40 @@ def test_order_update_user_email_existing_user(
     assert order.user == customer_user
 
 
+ORDER_ADD_NOTE_MUTATION = """
+    mutation addNote($id: ID!, $message: String!) {
+        orderAddNote(order: $id, input: {message: $message}) {
+            orderErrors {
+                field
+                message
+                code
+            }
+            order {
+                id
+            }
+            event {
+                user {
+                    email
+                }
+                message
+            }
+        }
+    }
+"""
+
+
 def test_order_add_note_as_staff_user(
     staff_api_client, permission_manage_orders, order_with_lines, staff_user
 ):
     """We are testing that adding a note to an order as a staff user is doing the
     expected behaviors."""
     order = order_with_lines
-    query = """
-        mutation addNote($id: ID!, $message: String) {
-            orderAddNote(order: $id, input: {message: $message}) {
-                errors {
-                    field
-                    message
-                }
-                order {
-                    id
-                }
-                event {
-                    user {
-                        email
-                    }
-                    message
-                }
-            }
-        }
-    """
     assert not order.events.all()
     order_id = graphene.Node.to_global_id("Order", order.id)
     message = "nuclear note"
     variables = {"id": order_id, "message": message}
     response = staff_api_client.post_graphql(
-        query, variables, permissions=[permission_manage_orders]
+        ORDER_ADD_NOTE_MUTATION, variables, permissions=[permission_manage_orders]
     )
     content = get_graphql_content(response)
     data = content["data"]["orderAddNote"]
@@ -1391,6 +1394,21 @@ def test_order_add_note_as_staff_user(
     assert not CustomerEvent.objects.exists()
 
 
+@pytest.mark.parametrize("message", ("", "   ",))
+def test_order_add_note_fail_on_empty_message(
+    staff_api_client, permission_manage_orders, order_with_lines, message
+):
+    order_id = graphene.Node.to_global_id("Order", order_with_lines.id)
+    variables = {"id": order_id, "message": message}
+    response = staff_api_client.post_graphql(
+        ORDER_ADD_NOTE_MUTATION, variables, permissions=[permission_manage_orders]
+    )
+    content = get_graphql_content(response)
+    data = content["data"]["orderAddNote"]
+    assert data["orderErrors"][0]["field"] == "message"
+    assert data["orderErrors"][0]["code"] == OrderErrorCode.REQUIRED.name
+
+
 CANCEL_ORDER_QUERY = """
     mutation cancelOrder($id: ID!, $restock: Boolean!) {
         orderCancel(id: $id, restock: $restock) {