From f628966ae99b705d3deb07cd07cee5cac898b8d4 Mon Sep 17 00:00:00 2001 From: Christian Cueni Date: Mon, 3 Feb 2020 13:30:19 +0100 Subject: [PATCH] Add registration, implement tests --- .../mock_data}/email_not_confirmed_me.json | 0 .../tests/mock_data}/me_data.json | 0 .../mock_data}/valid_student_orders.json | 0 .../mock_data}/valid_teacher_orders.json | 0 server/core/tests/mock_hep_data_factory.py | 57 ++++++++ server/registration/mutations_public.py | 34 ++--- .../registration/tests/test_registration.py | 126 ++++++------------ server/users/tests/test_login.py | 47 +------ server/users/user_signup_login_handler.py | 2 +- 9 files changed, 123 insertions(+), 143 deletions(-) rename server/{users/tests/test_data => core/tests/mock_data}/email_not_confirmed_me.json (100%) rename server/{users/tests/test_data => core/tests/mock_data}/me_data.json (100%) rename server/{users/tests/test_data => core/tests/mock_data}/valid_student_orders.json (100%) rename server/{users/tests/test_data => core/tests/mock_data}/valid_teacher_orders.json (100%) create mode 100644 server/core/tests/mock_hep_data_factory.py diff --git a/server/users/tests/test_data/email_not_confirmed_me.json b/server/core/tests/mock_data/email_not_confirmed_me.json similarity index 100% rename from server/users/tests/test_data/email_not_confirmed_me.json rename to server/core/tests/mock_data/email_not_confirmed_me.json diff --git a/server/users/tests/test_data/me_data.json b/server/core/tests/mock_data/me_data.json similarity index 100% rename from server/users/tests/test_data/me_data.json rename to server/core/tests/mock_data/me_data.json diff --git a/server/users/tests/test_data/valid_student_orders.json b/server/core/tests/mock_data/valid_student_orders.json similarity index 100% rename from server/users/tests/test_data/valid_student_orders.json rename to server/core/tests/mock_data/valid_student_orders.json diff --git a/server/users/tests/test_data/valid_teacher_orders.json b/server/core/tests/mock_data/valid_teacher_orders.json similarity index 100% rename from server/users/tests/test_data/valid_teacher_orders.json rename to server/core/tests/mock_data/valid_teacher_orders.json diff --git a/server/core/tests/mock_hep_data_factory.py b/server/core/tests/mock_hep_data_factory.py new file mode 100644 index 00000000..0a02827e --- /dev/null +++ b/server/core/tests/mock_hep_data_factory.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# +# ITerativ GmbH +# http://www.iterativ.ch/ +# +# Copyright (c) 2020 ITerativ GmbH. All rights reserved. +# +# Created on 03.02.20 +# @author: chrigu + +## Mocks +import json +import os +from datetime import datetime, timedelta + + +class MockResponse: + def __init__(self, status_code): + self.status_code = status_code + + def json(self): + return {} + + +## Setup json data + +def make_orders_valid(order_items): + for order_item in order_items['items']: + if 'created_at' in order_item: + yesterday = datetime.now() - timedelta(1) + order_item['created_at'] = datetime.strftime(yesterday, '%Y-%m-%d %H:%M:%S') + + return order_items + +# Load data +dir_path = os.path.dirname(os.path.realpath(__file__)) + +with open('{}/mock_data/valid_teacher_orders.json'.format(dir_path), 'r') as file: + valid_teacher_order_data = file.read() + +with open('{}/mock_data/valid_student_orders.json'.format(dir_path), 'r') as file: + valid_student_order_data = file.read() + +with open('{}/mock_data/me_data.json'.format(dir_path), 'r') as file: + me_data = file.read() + +with open('{}/mock_data/email_not_confirmed_me.json'.format(dir_path), 'r') as file: + not_confirmed_email_me_data = file.read() + +ME_DATA = json.loads(me_data) +NOT_CONFIRMED_ME = json.loads(not_confirmed_email_me_data) + +valid_teacher_order_items = json.loads(valid_teacher_order_data) +VALID_TEACHERS_ORDERS = make_orders_valid(valid_teacher_order_items) + +valid_student_order_items = json.loads(valid_student_order_data) +VALID_STUDENT_ORDERS = make_orders_valid(valid_student_order_items) diff --git a/server/registration/mutations_public.py b/server/registration/mutations_public.py index 32e600fb..687812c9 100644 --- a/server/registration/mutations_public.py +++ b/server/registration/mutations_public.py @@ -8,52 +8,54 @@ # Created on 2019-10-08 # @author: chrigu import graphene -from django.conf import settings +from django.contrib.auth import login from graphene import relay from core.hep_client import HepClient, HepClientException, HepClientUnauthorizedException from users.user_signup_login_handler import handle_user_and_verify_products -class PublicFieldError(graphene.ObjectType): - code = graphene.String() - - class RegistrationError(graphene.ObjectType): field = graphene.String() class Registration(relay.ClientIDMutation): class Input: - confirmation_key = graphene.String() + confirmation_key_input = graphene.String() success = graphene.Boolean() + message = graphene.String() errors = graphene.List(RegistrationError) # todo: change for consistency @classmethod def mutate_and_get_payload(cls, root, info, **kwargs): - confirmation_key = kwargs.get('confirmation_key') + confirmation_key = kwargs.get('confirmation_key_input') hep_client = HepClient() try: user_data = hep_client.customer_activate(confirmation_key) except HepClientUnauthorizedException: - return cls.return_login_error('invalid_credentials') + return cls.return_registration_msg('invalid_key') except HepClientException: - return cls.return_login_error('unknown_error') + return cls.return_registration_msg('unknown_error') - user, error_msg = handle_user_and_verify_products(user_data) + user, status_msg = handle_user_and_verify_products(user_data) - if error_msg: - return cls.return_login_error(error_msg) + if status_msg: + return cls.return_registration_msg(status_msg) - return cls(success=False, errors=[]) + login(info.context, user) + return cls(success=True, errors=[], message='success') @classmethod - def return_login_error(cls, message): - error = RegistrationError(field=message) - return cls(success=False, errors=[error]) + def return_registration_msg(cls, message): + # even if the user has no valid license treat it like a success + if message == 'unknown_error': + error = RegistrationError(field=message) + return cls(success=False, errors=[error], message='') + + return cls(success=True, errors=[], message=message) class RegistrationMutations: diff --git a/server/registration/tests/test_registration.py b/server/registration/tests/test_registration.py index 77a5be5c..bee2bf9c 100644 --- a/server/registration/tests/test_registration.py +++ b/server/registration/tests/test_registration.py @@ -7,33 +7,26 @@ # # Created on 2019-10-08 # @author: chrigu -from django.core import mail +from unittest.mock import patch + +import requests from django.contrib.sessions.middleware import SessionMiddleware from django.test import TestCase, RequestFactory from graphene.test import Client from api.schema import schema from core.hep_client import HepClient -from registration.factories import LicenseTypeFactory, LicenseFactory +from core.tests.mock_hep_data_factory import MockResponse, ME_DATA, VALID_TEACHERS_ORDERS from registration.models import License -from users.managers import RoleManager -from users.models import Role, User, UserRole, SchoolClass +from users.models import User, Role, SchoolClass class RegistrationTests(TestCase): def setUp(self): - - self.teacher_role = Role.objects.create(key=Role.objects.TEACHER_KEY, name="Teacher Role") - self.student_role = Role.objects.create(key=Role.objects.STUDENT_KEY, name="Student Role") - - self.teacher_license_type = LicenseTypeFactory(for_role=self.teacher_role) - self.student_license_type = LicenseTypeFactory(for_role=self.student_role) - - self.teacher_license = LicenseFactory(license_type=self.teacher_license_type) - self.student_license = LicenseFactory(license_type=self.student_license_type) - request = RequestFactory().post('/') + Role.objects.create_default_roles() + self.email = 'sepp@skillbox.iterativ.ch' self.first_name = 'Sepp' self.last_name = 'Feuz' @@ -49,6 +42,7 @@ class RegistrationTests(TestCase): mutation Registration($input: RegistrationInput!){ registration(input: $input) { success + message errors { field } @@ -62,72 +56,40 @@ class RegistrationTests(TestCase): } }) - # @patch.object(HepClient, 'customer_me', return_value=ME_DATA) - # def test_user_can_register_with_valid_confirmation_key(self, me_mock): - # - # self.user.hep_id = ME_DATA['id'] - # self.user.save() - # - # now = timezone.now() - # expiry_date = now + timedelta(365) - # LicenseFactory(expire_date=expiry_date, licensee=self.user, for_role=self.teacher_role).save() - # - # result = self.make_login_mutation(self.user.email, TOKEN) - # - # self.assertTrue(result.get('data').get('login').get('success')) - # self.assertTrue(self.user.is_authenticated) + @patch.object(HepClient, 'customer_activate', return_value=ME_DATA) + @patch.object(HepClient, 'myskillbox_product_for_customer', return_value=None) + @patch.object(HepClient, 'fetch_admin_token', return_value={'token': 'AABBCCDDEE**44566'}) + def test_user_can_register_with_valid_confirmation_key_and_no_license(self, admin_mock, product_mock, customer_mock): - # def _assert_user_registration(self, count, email, role_key): - # users = User.objects.filter(username=self.email) - # self.assertEqual(len(users), count) - # user_roles = UserRole.objects.filter(user__email=email, role__key=role_key) - # self.assertEqual(len(user_roles), count) - # licenses = License.objects.filter(licensee__email=email, license_type__for_role__key=role_key) - # self.assertEqual(len(licenses), count) - # - # def test_user_can_register_as_teacher(self): - # self._assert_user_registration(0, self.email, RoleManager.TEACHER_KEY) - # school_classes = SchoolClass.objects.filter(name__startswith='Meine Klasse') - # self.assertEqual(len(school_classes), 0) - # result = self.make_register_mutation(self.first_name, self.last_name, self.email, self.teacher_license_type.key) - # self.assertTrue(result.get('data').get('registration').get('success')) - # self._assert_user_registration(1, self.email, RoleManager.TEACHER_KEY) - # school_classes = SchoolClass.objects.filter(name__startswith='Meine Klasse') - # self.assertEqual(len(school_classes), 1) - # user = User.objects.get(email=self.email) - # self.assertTrue(school_classes[0].is_user_in_schoolclass(user)) - # self.assertEqual(len(mail.outbox), 1) - # self.assertEqual(mail.outbox[0].subject, 'Myskillbox: E-Mail bestätigen und Passwort setzen') - # - # def test_user_can_register_as_student(self): - # self._assert_user_registration(0, self.email, RoleManager.STUDENT_KEY) - # result = self.make_register_mutation(self.first_name, self.last_name, self.email, self.student_license_type.key) - # self.assertTrue(result.get('data').get('registration').get('success')) - # self._assert_user_registration(1, self.email, RoleManager.STUDENT_KEY) - # - # def test_existing_user_cannot_register(self): - # self._assert_user_registration(0, self.email, RoleManager.STUDENT_KEY) - # self.make_register_mutation(self.first_name, self.last_name, self.email, self.student_license_type.key) - # result = self.make_register_mutation(self.first_name, self.last_name, self.email, self.student_license_type.key) - # self.assertEqual(result.get('data').get('registration').get('errors')[0].get('field'), 'email') - # - # def test_existing_user_cannot_register_with_uppercase_email(self): - # self._assert_user_registration(0, self.email, RoleManager.STUDENT_KEY) - # self.make_register_mutation(self.first_name, self.last_name, self.email.upper(), self.student_license_type.key) - # result = self.make_register_mutation(self.first_name, self.last_name, self.email, self.student_license_type.key) - # self.assertEqual(result.get('data').get('registration').get('errors')[0].get('field'), 'email') - # - # def test_user_cannot_register_if_firstname_is_missing(self): - # result = self.make_register_mutation('', self.last_name, self.email, self.teacher_license_type.key) - # self.assertEqual(result.get('data').get('registration').get('errors')[0].get('field'), 'first_name') - # self.assertFalse(result.get('data').get('registration').get('success')) - # - # def test_user_cannot_register_if_lastname_is_missing(self): - # result = self.make_register_mutation(self.first_name, '', self.email, self.teacher_license_type.key) - # self.assertEqual(result.get('data').get('registration').get('errors')[0].get('field'), 'last_name') - # self.assertFalse(result.get('data').get('registration').get('success')) - # - # def test_user_cannot_register_if_email_is_missing(self): - # result = self.make_register_mutation(self.first_name, self.last_name, '', self.teacher_license_type.key) - # self.assertEqual(result.get('data').get('registration').get('errors')[0].get('field'), 'email') - # self.assertFalse(result.get('data').get('registration').get('success')) + result = self.make_register_mutation('CONFIRMATION_KEY') + + self.assertTrue(result.get('data').get('registration').get('success')) + self.assertEqual(result.get('data').get('registration').get('message'), 'no_valid_license') + + @patch.object(requests, 'post', return_value=MockResponse(401)) + def test_user_cannot_register_with_invalid_key(self, confirmation_mock): + + result = self.make_register_mutation('CONFIRMATION_KEY') + + self.assertTrue(result.get('data').get('registration').get('success')) + self.assertEqual(result.get('data').get('registration').get('message'), 'invalid_key') + + @patch.object(HepClient, '_customer_orders', return_value=VALID_TEACHERS_ORDERS) + @patch.object(HepClient, 'customer_activate', return_value=ME_DATA) + @patch.object(HepClient, 'fetch_admin_token', return_value={'token': 'AABBCCDDEE**44566'}) + def test_teacher_can_register_with_remote_license(self, order_mock, me_mock, admin_token_mock): + result = self.make_register_mutation('CONFIRMATION_KEY') + + user = User.objects.get(email=ME_DATA['email']) + + user_role_key = user.user_roles.get(user=user).role.key + self.assertEqual(user_role_key, Role.objects.TEACHER_KEY) + + license = License.objects.get(licensee=user) + self.assertEqual(license.for_role.key, Role.objects.TEACHER_KEY) + + school_class = SchoolClass.objects.get(users__in=[user]) + self.assertIsNotNone(school_class) + + self.assertTrue(result.get('data').get('registration').get('success')) + self.assertTrue(user.is_authenticated) diff --git a/server/users/tests/test_login.py b/server/users/tests/test_login.py index 912178de..5d02c59d 100644 --- a/server/users/tests/test_login.py +++ b/server/users/tests/test_login.py @@ -21,55 +21,14 @@ from graphene.test import Client from api.schema_public import schema from core.factories import UserFactory from core.hep_client import HepClient +from core.tests.mock_hep_data_factory import MockResponse, ME_DATA, VALID_STUDENT_ORDERS, VALID_TEACHERS_ORDERS, \ + NOT_CONFIRMED_ME from registration.factories import LicenseFactory from registration.models import License -from users.models import Role, MagentoToken, User, SchoolClass +from users.models import Role, User, SchoolClass TOKEN = 'abcd12345!' -## Setup json data - -def make_orders_valid(order_items): - for order_item in order_items['items']: - if 'created_at' in order_item: - yesterday = datetime.now() - timedelta(1) - order_item['created_at'] = datetime.strftime(yesterday, '%Y-%m-%d %H:%M:%S') - - return order_items - -# Load data - -dir_path = os.path.dirname(os.path.realpath(__file__)) - -with open('{}/test_data/valid_teacher_orders.json'.format(dir_path), 'r') as file: - valid_teacher_order_data = file.read() - -with open('{}/test_data/valid_student_orders.json'.format(dir_path), 'r') as file: - valid_student_order_data = file.read() - -with open('{}/test_data/me_data.json'.format(dir_path), 'r') as file: - me_data = file.read() - -with open('{}/test_data/email_not_confirmed_me.json'.format(dir_path), 'r') as file: - not_confirmed_email_me_data = file.read() - -ME_DATA = json.loads(me_data) -NOT_CONFIRMED_ME = json.loads(not_confirmed_email_me_data) - -valid_teacher_order_items = json.loads(valid_teacher_order_data) -VALID_TEACHERS_ORDERS = make_orders_valid(valid_teacher_order_items) - -valid_student_order_items = json.loads(valid_student_order_data) -VALID_STUDENT_ORDERS = make_orders_valid(valid_student_order_items) - - -## Mocks -class MockResponse: - def __init__(self, status_code): - self.status_code = status_code - - def json(self): - return {} class PasswordResetTests(TestCase): diff --git a/server/users/user_signup_login_handler.py b/server/users/user_signup_login_handler.py index 8fc1cf1d..12bcc74e 100644 --- a/server/users/user_signup_login_handler.py +++ b/server/users/user_signup_login_handler.py @@ -24,7 +24,7 @@ def handle_user_and_verify_products(user_data): except User.DoesNotExist: user = User.objects.create_user_from_hep(user_data) - # todo check if email has changed + # todo check if email has changed, any impact on our system? try: if not hep_client.is_email_verified(user_data):