Fix client, refactor user handling, fix tests

This commit is contained in:
Christian Cueni 2020-01-30 14:46:13 +01:00
parent 45f887287f
commit 773547c883
7 changed files with 152 additions and 149 deletions

View File

@ -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?

View File

@ -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'
}
]

View File

@ -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)

View File

@ -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

View File

@ -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=[])

View File

@ -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()

View File

@ -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