Test coupon redemption

This commit is contained in:
Christian Cueni 2021-05-26 14:28:39 +02:00
parent bd110cc1fb
commit 3e64d1c51f
7 changed files with 177 additions and 116 deletions

View File

@ -10,7 +10,7 @@ from assignments.schema.queries import AssignmentsQuery, StudentSubmissionQuery
from basicknowledge.queries import BasicKnowledgeQuery
from books.schema.mutations import BookMutations
from books.schema.queries import BookQuery
from core.schema.mutations.coupon import CouponMutations
from oauth.mutations import CouponMutations
from core.schema.mutations.main import CoreMutations
from notes.mutations import NoteMutations
from objectives.mutations import ObjectiveMutations

View File

@ -1,13 +1,4 @@
# -*- coding: utf-8 -*-
#
# ITerativ GmbH
# http://www.iterativ.ch/
#
# Copyright (c) 2018 ITerativ GmbH. All rights reserved.
#
# Created on 22.10.18
# @author: chrigu <christian.cueni@iterativ.ch>
from core.schema.mutations.coupon import Coupon
from oauth.mutations import Coupon
from core.schema.mutations.logout import Logout

View File

@ -1,88 +0,0 @@
# -*- coding: utf-8 -*-
#
# ITerativ GmbH
# http://www.iterativ.ch/
#
# Copyright (c) 2020 ITerativ GmbH. All rights reserved.
#
# Created on 03.02.20
# @author: chrigu <christian.cueni@iterativ.ch>
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.factories import UserFactory
from oauth.hep_client import HepClient
from users.tests.mock_hep_data_factory import MockResponse, VALID_TEACHERS_ORDERS
from users.models import License, Role, SchoolClass, UserRole
class CouponTests(TestCase):
def setUp(self):
Role.objects.create_default_roles()
self.user = UserFactory(username='aschi@iterativ.ch', email='aschi@iterativ.ch', hep_id=3)
Role.objects.create_default_roles()
self.teacher_role = Role.objects.get_default_teacher_role()
# adding session
request = RequestFactory().post('/')
middleware = SessionMiddleware()
middleware.process_request(request)
request.user = self.user
request.session.save()
self.client = Client(schema=schema, context_value=request)
def make_coupon_mutation(self, coupon_code, client):
mutation = '''
mutation Coupon($input: CouponInput!){
coupon(input: $input) {
success
}
}
'''
return client.execute(mutation, variables={
'input': {
'couponCode': coupon_code
}
})
@patch.object(requests, 'put', return_value=MockResponse(200, data=['200', 'Coupon successfully redeemed']))
@patch.object(HepClient, '_customer_orders', return_value=VALID_TEACHERS_ORDERS)
def test_user_has_valid_coupon(self, orders_mock, response_mock):
result = self.make_coupon_mutation('COUPON--1234', self.client)
user_role_key = self.user.user_roles.get(user=self.user).role.key
self.assertEqual(user_role_key, Role.objects.TEACHER_KEY)
license = License.objects.get(licensee=self.user)
self.assertIsNotNone(license)
school_class = SchoolClass.objects.get(users__in=[self.user])
self.assertIsNotNone(school_class)
self.assertTrue(result.get('data').get('coupon').get('success'))
self.assertTrue(self.user.is_authenticated)
@patch.object(requests, 'put', return_value=MockResponse(200, data=['201', 'Invalid Coupon']))
def test_user_has_invalid_coupon(self, response_mock):
result = self.make_coupon_mutation('COUPON--1234', self.client)
self.assertEqual(result.get('errors')[0].get('message'), 'invalid_coupon')
@patch.object(requests, 'put', return_value=MockResponse(200, data=['201', 'Invalid Coupon']))
def test_unauthenticated_user_cannot_redeem(self, response_mock):
request = RequestFactory().post('/')
middleware = SessionMiddleware()
middleware.process_request(request)
request.session.save()
client = Client(schema=schema, context_value=request)
result = self.make_coupon_mutation('COUPON--1234', client)
self.assertEqual(result.get('errors')[0].get('message'), 'not_authenticated')

View File

@ -137,10 +137,10 @@ class HepClient:
return None
response_data = response.json()
if response_data[0] == '200':
return None
return response_data[0]
# todo handle 404, 402
return response_data
def _extract_myskillbox_products(self, eorders):
products = []
@ -152,19 +152,25 @@ class HepClient:
status = eorder['status']
for entry in eorder['entries']:
product = self.entry_to_product(entry, self._get_item_activation(eorder), status)
if product:
products.append(product)
return products
def entry_to_product(self, entry, activation_date, status):
if is_myskillbox_product(entry['isbn']):
product = {
return {
'raw': entry,
'activated': self._get_item_activation(eorder),
'activated': activation_date,
'status': status,
'order_id': entry['id'],
'license': MYSKILLBOX_LICENSES[entry['isbn']],
'isbn': entry['isbn']
}
products.append(product)
return products
return None
def _get_item_activation(self, eorder):
if 'created_at' in eorder:

View File

@ -1,8 +1,10 @@
import graphene
from django.utils.timezone import now
from graphene import relay
from oauth.hep_client import HepClient, HepClientException
from oauth.user_signup_login_handler import check_and_create_licenses, create_role_for_user
from oauth.user_signup_login_handler import create_role_for_user
from users.models import License
class Coupon(relay.ClientIDMutation):
@ -22,18 +24,21 @@ class Coupon(relay.ClientIDMutation):
raise Exception('not_authenticated')
try:
response = hep_client.coupon_redeem(coupon_code, hep_id)
response = hep_client.redeem_coupon(coupon_code, hep_id, request=info)
except HepClientException:
raise Exception('unknown_error')
if not response:
raise Exception('invalid_coupon')
license, error_msg = check_and_create_licenses(hep_client, info.context.user)
product = hep_client.entry_to_product(response['data'], now(), 'coupon')
# todo fail if no license
if error_msg:
raise Exception(error_msg)
if not product:
raise Exception('non_myskillbox_product')
license = License.objects.create_license_for_role(info.context.user, product['activated'], product['raw'],
product['license']['edition'],
product['order_id'], product['isbn'])
create_role_for_user(info.context.user, license.for_role.key)

View File

@ -0,0 +1,149 @@
from unittest.mock import patch
import requests
from django.contrib.auth.models import AnonymousUser
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.factories import UserFactory
from oauth.factories import Oauth2TokenFactory
from users.tests.mock_hep_data_factory import MockResponse, VALID_TEACHERS_ORDERS
from users.models import License, Role, SchoolClass
REDEEM_MYSKILLBOX_SUCCESS_RESPONSE = {
"data": {
"id": 3433,
"uri": "\/products\/myskillbox-lehrpersonen",
"url": None,
"title": "mySkillbox für Lehrpersonen ",
"subtitle": "Lizenz gültig für 1 Jahr",
"isbn": "978-3-0355-1861-0",
"slug": "myskillbox-lehrpersonen",
"product_type": "eLehrmittel",
"product_form": "",
"cover": "https:\/\/hep-verlag.fra1.digitaloceanspaces.com\/staging\/products\/2921\/978-3-0355-1861-0.jpg",
"price": 100,
"price_total": 100,
"amount": 1,
"authors": []
}
}
REDEEM_OTHER_LICENSE_RESPONSE = {
"data": {
"id": 3433,
"uri": "\/products\/someothe",
"url": None,
"title": "Ein e-Lehrmittel",
"subtitle": "Lizenz gültig für 1 Jahr",
"isbn": "111-2-3333-4444-0",
"slug": "some-other",
"product_type": "eLehrmittel",
"product_form": "",
"cover": "https:\/\/hep-verlag.fra1.digitaloceanspaces.com\/staging\/products\/2921\/978-3-0355-123.jpg",
"price": 100,
"price_total": 100,
"amount": 1,
"authors": []
}
}
INVALID_LICENSE = {
"message": "The given data was invalid.",
"errors": {
"code": [
"The coupons was already redeemed."
]
}
}
class CouponTests(TestCase):
def setUp(self):
self.user = UserFactory(username='aschi@iterativ.ch', email='aschi@iterativ.ch', hep_id=3)
Role.objects.create_default_roles()
self.teacher_role = Role.objects.get_default_teacher_role()
Oauth2TokenFactory(user=self.user)
# adding session
request = RequestFactory().post('/')
middleware = SessionMiddleware()
middleware.process_request(request)
request.user = self.user
request.session.save()
self.client = Client(schema=schema, context_value=request)
def make_coupon_mutation(self, coupon_code, client):
mutation = '''
mutation Coupon($input: CouponInput!){
coupon(input: $input) {
success
}
}
'''
return client.execute(mutation, variables={
'input': {
'couponCode': coupon_code
}
})
@patch.object(requests, 'post', return_value=MockResponse(200, data=REDEEM_MYSKILLBOX_SUCCESS_RESPONSE))
def test_user_has_valid_skillbox_coupon(self, response_mock):
result = self.make_coupon_mutation('COUPON--1234', self.client)
user_role_key = self.user.user_roles.get(user=self.user).role.key
self.assertEqual(user_role_key, Role.objects.TEACHER_KEY)
license = License.objects.get(licensee=self.user)
self.assertIsNotNone(license)
school_class = SchoolClass.objects.get(users__in=[self.user])
self.assertIsNotNone(school_class)
self.assertTrue(result.get('data').get('coupon').get('success'))
self.assertTrue(self.user.is_authenticated)
@patch.object(requests, 'post', return_value=MockResponse(200, data=REDEEM_OTHER_LICENSE_RESPONSE))
def test_user_has_valid_non_skillbox_coupon(self, response_mock):
result = self.make_coupon_mutation('COUPON--1234', self.client)
try:
self.user.user_roles.get(user=self.user).role.key
self.fail("CouponTests.test_user_has_valid_non_skillbox_coupon: Should not have created user role")
except:
pass
try:
License.objects.get(licensee=self.user)
self.fail("CouponTests.test_user_has_valid_non_skillbox_coupon: License should not exist")
except License.DoesNotExist:
pass
self.assertEqual(result.get('errors')[0].get('message'), 'non_myskillbox_product')
self.assertTrue(self.user.is_authenticated)
@patch.object(requests, 'post', return_value=MockResponse(404, data=INVALID_LICENSE))
def test_user_has_invalid_coupon(self, response_mock):
result = self.make_coupon_mutation('COUPON--1234', self.client)
self.assertEqual(result.get('errors')[0].get('message'), 'invalid_coupon')
@patch.object(requests, 'post', return_value=MockResponse(422, data=INVALID_LICENSE))
def test_user_has_already_used_coupon(self, response_mock):
result = self.make_coupon_mutation('COUPON--1234', self.client)
self.assertEqual(result.get('errors')[0].get('message'), 'invalid_coupon')
@patch.object(requests, 'put', return_value=MockResponse(200, data=['201', 'Invalid Coupon']))
def test_unauthenticated_user_cannot_redeem(self, response_mock):
request = RequestFactory().post('/')
middleware = SessionMiddleware()
middleware.process_request(request)
request.session.save()
client = Client(schema=schema, context_value=request)
result = self.make_coupon_mutation('COUPON--1234', client)
self.assertEqual(result.get('errors')[0].get('message'), 'not_authenticated')

View File

@ -46,14 +46,12 @@ def check_and_create_licenses(hep_client, user, token):
license = License.objects.create_license_for_role(user, product['activated'], product['raw'],
product['license']['edition'],
product['order_id'], product['isbn'])
# todo handle no license case
else:
return None, NO_VALID_LICENSE
return license, None
def create_role_for_user(user, role_key):
UserRole.objects.get_or_create_role_for_user(user, role_key)