Repository: saleor/saleor

Issue:
GraphQL mutation to create a new user
### What I'm trying to achieve

I want to be able to create a new user (registration) in storefront using graphQL API.


Discussion:

Resolving patch:
diff --git a/saleor/graphql/account/mutations.py b/saleor/graphql/account/mutations.py
--- a/saleor/graphql/account/mutations.py
+++ b/saleor/graphql/account/mutations.py
@@ -34,6 +34,29 @@ def send_user_password_reset_email(user, site):
 SHIPPING_ADDRESS_FIELD = 'default_shipping_address'
 
 
+class CustomerRegisterInput(graphene.InputObjectType):
+    email = graphene.String(
+        description='The unique email address of the user.', required=True)
+    password = graphene.String(description='Password', required=True)
+
+
+class CustomerRegister(ModelMutation):
+    class Arguments:
+        input = CustomerRegisterInput(
+            description='Fields required to create a user.', required=True)
+
+    class Meta:
+        description = 'Register a new user.'
+        exclude = ['password']
+        model = models.User
+
+    @classmethod
+    def save(cls, info, user, cleaned_input):
+        password = cleaned_input['password']
+        user.set_password(password)
+        user.save()
+
+
 class UserInput(graphene.InputObjectType):
     email = graphene.String(
         description='The unique email address of the user.')
@@ -111,7 +134,6 @@ def clean_input(cls, info, instance, input, errors):
             billing_address = cls.construct_address(
                 BILLING_ADDRESS_FIELD, billing_address_input, instance, errors)
             cleaned_input[BILLING_ADDRESS_FIELD] = billing_address
-
         return cleaned_input
 
     @classmethod
diff --git a/saleor/graphql/api.py b/saleor/graphql/api.py
--- a/saleor/graphql/api.py
+++ b/saleor/graphql/api.py
@@ -4,8 +4,9 @@
 from graphql_jwt.decorators import login_required, permission_required
 
 from .account.mutations import (
-    CustomerCreate, CustomerUpdate, PasswordReset, SetPassword, StaffCreate,
-    StaffDelete, StaffUpdate, AddressCreate, AddressUpdate, AddressDelete)
+    CustomerCreate, CustomerUpdate, CustomerRegister, PasswordReset,
+    SetPassword, StaffCreate, StaffDelete, StaffUpdate, AddressCreate,
+    AddressUpdate, AddressDelete)
 from .account.types import AddressValidationData, AddressValidationInput, User
 from .account.resolvers import (
     resolve_address_validator, resolve_customers, resolve_staff_users)
@@ -287,6 +288,7 @@ class Mutations(graphene.ObjectType):
 
     customer_create = CustomerCreate.Field()
     customer_update = CustomerUpdate.Field()
+    customer_register = CustomerRegister.Field()
 
     staff_create = StaffCreate.Field()
     staff_update = StaffUpdate.Field()


Test patch:
diff --git a/tests/api/test_account.py b/tests/api/test_account.py
--- a/tests/api/test_account.py
+++ b/tests/api/test_account.py
@@ -246,6 +246,39 @@ def test_who_can_see_user(
     assert content['data']['customers']['totalCount'] == 1
 
 
+def test_customer_register(user_api_client):
+    query = """
+        mutation RegisterCustomer($password: String!, $email: String!) {
+            customerRegister(input: {password: $password, email: $email}) {
+                errors {
+                    field
+                    message
+                }
+                user {
+                    id
+                }
+            }
+        }
+    """
+    email = 'customer@example.com'
+    variables = json.dumps({'email': email, 'password': 'Password'})
+    response = user_api_client.post(
+        reverse('api'), {'query': query, 'variables': variables})
+    content = get_graphql_content(response)
+    data = content['data']['customerRegister']
+    assert not data['errors']
+    assert User.objects.filter(email=email).exists()
+
+    response = user_api_client.post(
+        reverse('api'), {'query': query, 'variables': variables})
+    content = get_graphql_content(response)
+    data = content['data']['customerRegister']
+    assert data['errors']
+    assert data['errors'][0]['field'] == 'email'
+    assert data['errors'][0]['message'] == (
+        'User with this Email already exists.')
+
+
 @patch('saleor.account.emails.send_password_reset_email.delay')
 def test_customer_create(
         send_password_reset_mock, admin_api_client, user_api_client, address):