Fix client, refactor user handling, fix tests
This commit is contained in:
parent
45f887287f
commit
773547c883
|
|
@ -102,6 +102,12 @@ class HepClient:
|
|||
response = self._call('/rest/V1/customers/me', additional_headers={'authorization': 'Bearer {}'.format(token)})
|
||||
return response.json()
|
||||
|
||||
def customer_activate(self, confirmation_key):
|
||||
response = self._call('/rest/V1/customers/me/activate', method='post', data={
|
||||
'confirmationKey': confirmation_key
|
||||
})
|
||||
return response.json()
|
||||
|
||||
def _customer_orders(self, admin_token, customer_id):
|
||||
url = ("/rest/V1/orders/?searchCriteria[filterGroups][0][filters][0]["
|
||||
"field]=customer_id&searchCriteria[filterGroups][0][filters][0][value]={}".format(customer_id))
|
||||
|
|
@ -126,11 +132,18 @@ class HepClient:
|
|||
products = []
|
||||
|
||||
for order_item in orders['items']:
|
||||
|
||||
status = ''
|
||||
if 'status' in order_item:
|
||||
status = order_item['status']
|
||||
|
||||
for item in order_item['items']:
|
||||
if item['sku'] == MYSKILLBOX_TEACHER_EDITION_ISBN or item['sku'] == MYSKILLBOX_STUDENT_EDITION_ISBN:
|
||||
|
||||
product = {
|
||||
'raw': item,
|
||||
'activated': self._get_item_activation(order_item)
|
||||
'activated': self._get_item_activation(order_item),
|
||||
'status': status
|
||||
}
|
||||
|
||||
if item['sku'] == MYSKILLBOX_TEACHER_EDITION_ISBN:
|
||||
|
|
@ -144,14 +157,16 @@ class HepClient:
|
|||
return products
|
||||
|
||||
def _get_item_activation(self, item):
|
||||
for history in item['status_histories']:
|
||||
# todo can there be no date?
|
||||
if history['comment'] == 'payed by couponcode':
|
||||
return datetime.strptime(history['created_at'], '%Y-%m-%d %H:%M:%S')
|
||||
if 'created_at' in item:
|
||||
return datetime.strptime(item['created_at'], '%Y-%m-%d %H:%M:%S')
|
||||
|
||||
def _get_relevant_product(self, products):
|
||||
|
||||
def filter_inactive_products(product):
|
||||
def filter_valid_products(product):
|
||||
|
||||
if product['status'] != 'complete':
|
||||
return False
|
||||
|
||||
if product['edition'] == 'teacher':
|
||||
expiry_delta = product['activated'] + timedelta(TEACHER_EDITION_DURATION)
|
||||
else:
|
||||
|
|
@ -162,7 +177,7 @@ class HepClient:
|
|||
else:
|
||||
return False
|
||||
|
||||
active_products = list(filter(filter_inactive_products, products))
|
||||
active_products = list(filter(filter_valid_products, products))
|
||||
print(active_products)
|
||||
|
||||
# todo can a teacher have multiple licenses?
|
||||
|
|
|
|||
|
|
@ -24,17 +24,33 @@ class HepClientTestCases(TestCase):
|
|||
{
|
||||
'edition': 'teacher',
|
||||
'raw': {},
|
||||
'activated': self.now - timedelta(2*TEACHER_EDITION_DURATION)
|
||||
'activated': self.now - timedelta(2*TEACHER_EDITION_DURATION),
|
||||
'status': 'complete'
|
||||
},
|
||||
{
|
||||
'edition': 'teacher',
|
||||
'raw': {},
|
||||
'activated': self.now - timedelta(3 * TEACHER_EDITION_DURATION)
|
||||
'activated': self.now - timedelta(3 * TEACHER_EDITION_DURATION),
|
||||
'status': 'complete'
|
||||
},
|
||||
{
|
||||
'edition': 'teacher',
|
||||
'raw': {},
|
||||
'activated': self.now - timedelta(4 * TEACHER_EDITION_DURATION)
|
||||
'activated': self.now - timedelta(4 * TEACHER_EDITION_DURATION),
|
||||
'status': 'complete'
|
||||
}
|
||||
]
|
||||
|
||||
relevant_product = self.hep_client._get_relevant_product(products)
|
||||
self.assertIsNone(relevant_product)
|
||||
|
||||
def test_has_no_not_completed_product(self):
|
||||
products = [
|
||||
{
|
||||
'edition': 'teacher',
|
||||
'raw': {},
|
||||
'activated': self.now - timedelta(7),
|
||||
'status': 'not'
|
||||
}
|
||||
]
|
||||
|
||||
|
|
@ -48,21 +64,24 @@ class HepClientTestCases(TestCase):
|
|||
'raw': {
|
||||
'id': 0
|
||||
},
|
||||
'activated': self.now - timedelta(7)
|
||||
'activated': self.now - timedelta(7),
|
||||
'status': 'complete'
|
||||
},
|
||||
{
|
||||
'edition': 'teacher',
|
||||
'raw': {
|
||||
'id': 1
|
||||
},
|
||||
'activated': self.now - timedelta(3 * TEACHER_EDITION_DURATION)
|
||||
'activated': self.now - timedelta(3 * TEACHER_EDITION_DURATION),
|
||||
'status': 'complete'
|
||||
},
|
||||
{
|
||||
'edition': 'teacher',
|
||||
'raw': {
|
||||
'id': 2
|
||||
},
|
||||
'activated': self.now - timedelta(4 * TEACHER_EDITION_DURATION)
|
||||
'activated': self.now - timedelta(4 * TEACHER_EDITION_DURATION),
|
||||
'status': 'complete'
|
||||
}
|
||||
]
|
||||
|
||||
|
|
@ -76,21 +95,24 @@ class HepClientTestCases(TestCase):
|
|||
'raw': {
|
||||
'id': 0
|
||||
},
|
||||
'activated': self.now - timedelta(7)
|
||||
'activated': self.now - timedelta(7),
|
||||
'status': 'complete'
|
||||
},
|
||||
{
|
||||
'edition': 'teacher',
|
||||
'raw': {
|
||||
'id': 1
|
||||
},
|
||||
'activated': self.now - timedelta(3 * TEACHER_EDITION_DURATION)
|
||||
'activated': self.now - timedelta(3 * TEACHER_EDITION_DURATION),
|
||||
'status': 'complete'
|
||||
},
|
||||
{
|
||||
'edition': 'teacher',
|
||||
'raw': {
|
||||
'id': 2
|
||||
},
|
||||
'activated': self.now - timedelta(4 * TEACHER_EDITION_DURATION)
|
||||
'activated': self.now - timedelta(4 * TEACHER_EDITION_DURATION),
|
||||
'status': 'complete'
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,9 @@ import graphene
|
|||
from django.conf import settings
|
||||
from graphene import relay
|
||||
|
||||
from core.hep_client import HepClient, HepClientException
|
||||
from core.hep_client import HepClient, HepClientException, HepClientUnauthorizedException
|
||||
from core.views import SetPasswordView
|
||||
from registration.models import License
|
||||
from registration.serializers import RegistrationSerializer
|
||||
from users.models import User, Role, UserRole, SchoolClass
|
||||
|
||||
|
||||
|
|
@ -39,51 +38,29 @@ class Registration(relay.ClientIDMutation):
|
|||
|
||||
@classmethod
|
||||
def mutate_and_get_payload(cls, root, info, **kwargs):
|
||||
first_name = kwargs.get('firstname_input')
|
||||
last_name = kwargs.get('lastname_input')
|
||||
email = kwargs.get('email_input')
|
||||
license_key = kwargs.get('license_key_input')
|
||||
registration_data = {
|
||||
'first_name': first_name,
|
||||
'last_name': last_name,
|
||||
'email': email,
|
||||
'license_key': license_key,
|
||||
}
|
||||
confirmation_key = kwargs.get('confirmationKey')
|
||||
|
||||
serializer = RegistrationSerializer(data=registration_data)
|
||||
hep_client = HepClient()
|
||||
|
||||
if serializer.is_valid():
|
||||
try:
|
||||
user_data = hep_client.customer_activate(confirmation_key)
|
||||
except HepClientUnauthorizedException:
|
||||
return cls.return_login_error('invalid_credentials')
|
||||
except HepClientException:
|
||||
return cls.return_login_error('unknown_error')
|
||||
|
||||
if settings.USE_LOCAL_REGISTRATION:
|
||||
return cls.create_local_user(serializer, info)
|
||||
else:
|
||||
hep_client = HepClient()
|
||||
try:
|
||||
user = User.objects.get(hep_id=user_data['id'])
|
||||
except User.DoesNotExist:
|
||||
user = User.objects.create_user_from_hep(user_data)
|
||||
|
||||
try:
|
||||
email_available = hep_client.is_email_available(serializer['email'])
|
||||
except HepClientException:
|
||||
# Todo: handle error from exception (set on object, code & message)
|
||||
return cls(success=False, errors=None)
|
||||
# show verfiy page
|
||||
|
||||
if not email_available:
|
||||
errors = [MutationError(field='email', errors=['already_exists'])]
|
||||
return cls(success=False, errors=errors)
|
||||
|
||||
try:
|
||||
response = hep_client.customer_create(serializer.data, None)
|
||||
except HepClientException:
|
||||
# Todo: handle error from exception (set on object, code & message)
|
||||
return cls(success=False, errors=None)
|
||||
|
||||
# create or update local user
|
||||
|
||||
# show verfiy page
|
||||
|
||||
errors = []
|
||||
for key, value in serializer.errors.items():
|
||||
error = MutationError(field=key, errors=[])
|
||||
for field_error in serializer.errors[key]:
|
||||
error.errors.append(PublicFieldError(code=field_error.code))
|
||||
# errors = []
|
||||
# for key, value in serializer.errors.items():
|
||||
# error = MutationError(field=key, errors=[])
|
||||
# for field_error in serializer.errors[key]:
|
||||
# error.errors.append(PublicFieldError(code=field_error.code))
|
||||
|
||||
errors.append(error)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# ITerativ GmbH
|
||||
# http://www.iterativ.ch/
|
||||
#
|
||||
# Copyright (c) 2019 ITerativ GmbH. All rights reserved.
|
||||
#
|
||||
# Created on 2019-10-08
|
||||
# @author: chrigu <christian.cueni@iterativ.ch>
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from rest_framework import serializers
|
||||
from rest_framework.fields import CharField, EmailField
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from registration.models import License
|
||||
|
||||
|
||||
class RegistrationSerializer(serializers.Serializer):
|
||||
first_name = CharField(allow_blank=False)
|
||||
last_name = CharField(allow_blank=False)
|
||||
email = EmailField(allow_blank=False)
|
||||
license_key = CharField(allow_blank=False)
|
||||
skillbox_license = None
|
||||
|
||||
def validate_email(self, value):
|
||||
|
||||
lower_email = value.lower()
|
||||
|
||||
if not settings.USE_LOCAL_REGISTRATION:
|
||||
return lower_email
|
||||
|
||||
# the email is used as username
|
||||
if len(get_user_model().objects.filter(username=lower_email)) > 0:
|
||||
raise serializers.ValidationError(_(u'Diese E-Mail ist bereits registriert'))
|
||||
elif len(get_user_model().objects.filter(email=lower_email)) > 0:
|
||||
raise serializers.ValidationError(_(u'Dieser E-Mail ist bereits registriert'))
|
||||
else:
|
||||
return lower_email
|
||||
|
||||
def validate_license_key(self, value):
|
||||
return value
|
||||
|
|
@ -14,8 +14,7 @@ from django.contrib.auth import authenticate, login
|
|||
from graphene import relay
|
||||
|
||||
from core.hep_client import HepClient, HepClientUnauthorizedException, HepClientException
|
||||
from registration.models import License
|
||||
from users.models import MagentoToken, User, Role, UserRole, SchoolClass
|
||||
from users.user_signup_login_handler import handle_user_and_verify_products
|
||||
|
||||
|
||||
class LoginError(graphene.ObjectType):
|
||||
|
|
@ -43,7 +42,6 @@ class Login(relay.ClientIDMutation):
|
|||
|
||||
else:
|
||||
hep_client = HepClient()
|
||||
|
||||
token = kwargs.get('token')
|
||||
|
||||
try:
|
||||
|
|
@ -53,45 +51,10 @@ class Login(relay.ClientIDMutation):
|
|||
except HepClientException:
|
||||
return cls.return_login_error('unknown_error')
|
||||
|
||||
try:
|
||||
user = User.objects.get(email=username)
|
||||
except User.DoesNotExist:
|
||||
user = User.objects.create_user_from_hep(user_data)
|
||||
user, error_msg = handle_user_and_verify_products(user_data, token)
|
||||
|
||||
#todo is this needed?
|
||||
magento_token, created = MagentoToken.objects.get_or_create(user=user)
|
||||
magento_token.token = token
|
||||
magento_token.save()
|
||||
|
||||
try:
|
||||
if not hep_client.is_email_verified(user_data):
|
||||
return cls.return_login_error('email_not_verified')
|
||||
except HepClientException:
|
||||
return cls.return_login_error('unknown_error')
|
||||
|
||||
try:
|
||||
license = License.objects.get(licensee=user)
|
||||
# Todo how handle invalid license? Cron Job? How to select correct license? Save all licenses? History?
|
||||
except License.DoesNotExist:
|
||||
try:
|
||||
product = hep_client.myskillbox_product_for_customer(settings.HEP_ADMIN_TOKEN, user.hep_id)
|
||||
except HepClientException:
|
||||
return cls.return_login_error('unknown_error')
|
||||
|
||||
if product:
|
||||
license = License.objects.create_license_for_role(user, product['activated'],
|
||||
product['raw'], product['edition'])
|
||||
# todo handle no license case
|
||||
else:
|
||||
return cls.return_login_error('no_valid_license')
|
||||
|
||||
UserRole.objects.create_role_for_user(user, license.for_role.key)
|
||||
|
||||
if license.for_role.key == Role.objects.TEACHER_KEY:
|
||||
SchoolClass.create_default_group_for_teacher(user)
|
||||
|
||||
if not license.is_valid():
|
||||
return cls.return_login_error('no_valid_license')
|
||||
if error_msg:
|
||||
return cls.return_login_error(error_msg)
|
||||
|
||||
login(info.context, user)
|
||||
return cls(success=True, errors=[])
|
||||
|
|
|
|||
|
|
@ -31,10 +31,9 @@ TOKEN = 'abcd12345!'
|
|||
|
||||
def make_orders_valid(order_items):
|
||||
for order_item in order_items['items']:
|
||||
for status in order_item['status_histories']:
|
||||
if status['comment'] == 'payed by couponcode':
|
||||
yesterday = datetime.now() - timedelta(1)
|
||||
status['created_at'] = datetime.strftime(yesterday, '%Y-%m-%d %H:%M:%S')
|
||||
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
|
||||
|
||||
|
|
@ -109,6 +108,9 @@ class PasswordResetTests(TestCase):
|
|||
@patch.object(HepClient, 'customer_me', return_value=ME_DATA)
|
||||
def test_user_can_login_with_local_user_and_valid_local_license(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()
|
||||
|
|
@ -120,7 +122,7 @@ class PasswordResetTests(TestCase):
|
|||
|
||||
@patch.object(HepClient, '_customer_orders', return_value=VALID_TEACHERS_ORDERS)
|
||||
@patch.object(HepClient, 'customer_me', return_value=ME_DATA)
|
||||
def test_teacher_can_login_with_local_user_and_remote_license(self, order_mock, me_token):
|
||||
def test_teacher_can_login_with_remote_user_and_remote_license(self, order_mock, me_token):
|
||||
result = self.make_login_mutation(ME_DATA['email'], TOKEN)
|
||||
|
||||
user = User.objects.get(email=ME_DATA['email'])
|
||||
|
|
@ -139,9 +141,9 @@ class PasswordResetTests(TestCase):
|
|||
|
||||
@patch.object(HepClient, '_customer_orders', return_value=VALID_STUDENT_ORDERS)
|
||||
@patch.object(HepClient, 'customer_me', return_value=ME_DATA)
|
||||
def test_student_can_login_with_local_user_and_remote_license(self, order_mock, me_token):
|
||||
result = self.make_login_mutation(ME_DATA['email'], TOKEN)
|
||||
def test_student_can_login_with_remote_user_and_remote_license(self, order_mock, me_token):
|
||||
|
||||
result = self.make_login_mutation(ME_DATA['email'], TOKEN)
|
||||
user = User.objects.get(email=ME_DATA['email'])
|
||||
|
||||
user_role_key = user.user_roles.get(user=user).role.key
|
||||
|
|
@ -165,7 +167,7 @@ class PasswordResetTests(TestCase):
|
|||
def test_user_with_unconfirmed_email_cannot_login(self, me_mock, post_mock):
|
||||
result = self.make_login_mutation(ME_DATA['email'], TOKEN)
|
||||
|
||||
user = User.objects.get(email=ME_DATA['email'])
|
||||
User.objects.get(email=ME_DATA['email'])
|
||||
|
||||
self.assertFalse(result.get('data').get('login').get('success'))
|
||||
self.assertEqual(result.get('data').get('login').get('errors')[0].get('field'), 'email_not_verified')
|
||||
|
|
@ -178,8 +180,9 @@ class PasswordResetTests(TestCase):
|
|||
self.assertFalse(result.get('data').get('login').get('success'))
|
||||
self.assertEqual(result.get('data').get('login').get('errors')[0].get('field'), 'no_valid_license')
|
||||
|
||||
@patch.object(HepClient, 'myskillbox_product_for_customer', return_value=None)
|
||||
@patch.object(HepClient, 'customer_me', return_value=ME_DATA)
|
||||
def test_user_cannot_login_local_license_invalid(self, me_mock):
|
||||
def test_user_cannot_login_local_license_invalid(self, product_mock, me_mock):
|
||||
now = timezone.now()
|
||||
expiry_date = now - timedelta(1)
|
||||
LicenseFactory(expire_date=expiry_date, licensee=self.user, for_role=self.teacher_role).save()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# ITerativ GmbH
|
||||
# http://www.iterativ.ch/
|
||||
#
|
||||
# Copyright (c) 2020 ITerativ GmbH. All rights reserved.
|
||||
#
|
||||
# Created on 30.01.20
|
||||
# @author: chrigu <christian.cueni@iterativ.ch>
|
||||
from django.conf import settings
|
||||
|
||||
from core.hep_client import HepClient, HepClientException
|
||||
from registration.models import License
|
||||
from users.models import User, MagentoToken, UserRole, Role, SchoolClass
|
||||
|
||||
|
||||
def handle_user_and_verify_products(user_data, token):
|
||||
|
||||
hep_client = HepClient()
|
||||
|
||||
try:
|
||||
user = User.objects.get(hep_id=user_data['id'])
|
||||
except User.DoesNotExist:
|
||||
user = User.objects.create_user_from_hep(user_data)
|
||||
|
||||
# todo check if email has changed
|
||||
|
||||
# todo is this needed?
|
||||
magento_token, created = MagentoToken.objects.get_or_create(user=user)
|
||||
magento_token.token = token
|
||||
magento_token.save()
|
||||
|
||||
try:
|
||||
if not hep_client.is_email_verified(user_data):
|
||||
return user, 'email_not_verified'
|
||||
except HepClientException:
|
||||
return user, 'unknown_error'
|
||||
|
||||
try:
|
||||
license = License.objects.get(licensee=user)
|
||||
# Todo how handle invalid license? Cron Job? How to select correct license? Save all licenses? History?
|
||||
except License.DoesNotExist:
|
||||
try:
|
||||
# todo is admin token valid, save it? do we need it?
|
||||
product = hep_client.myskillbox_product_for_customer(settings.HEP_ADMIN_TOKEN, user.hep_id)
|
||||
except HepClientException:
|
||||
return user, 'unknown_error'
|
||||
|
||||
if product:
|
||||
license = License.objects.create_license_for_role(user, product['activated'],
|
||||
product['raw'], product['edition'])
|
||||
# todo handle no license case
|
||||
else:
|
||||
return user, 'no_valid_license'
|
||||
|
||||
UserRole.objects.create_role_for_user(user, license.for_role.key)
|
||||
|
||||
if license.for_role.key == Role.objects.TEACHER_KEY:
|
||||
SchoolClass.create_default_group_for_teacher(user)
|
||||
|
||||
if not license.is_valid():
|
||||
return user, 'no_valid_license'
|
||||
|
||||
return user, None
|
||||
Loading…
Reference in New Issue