diff --git a/members/test_resources/multi_line_import.csv b/members/test_resources/multi_line_import.csv new file mode 100644 index 0000000..3974655 --- /dev/null +++ b/members/test_resources/multi_line_import.csv @@ -0,0 +1,3 @@ +Testi;Ukkeli;testi@ukkeli.fi;Espoo;1;0 +Jäbä;Kakkeli;jaba@kakkeli.fi;Hamina;0;1 +Kolmas;Kaveri;kolmas@kaveri.com;Mesta;1;1 \ No newline at end of file diff --git a/members/test_resources/single_line_import.csv b/members/test_resources/single_line_import.csv new file mode 100644 index 0000000..1a65674 --- /dev/null +++ b/members/test_resources/single_line_import.csv @@ -0,0 +1 @@ +Testi;Ukkeli;testi@ukkeli.fi;Espoo;1;0 \ No newline at end of file diff --git a/members/tests.py b/members/tests.py index 622fbf6..645a1ee 100644 --- a/members/tests.py +++ b/members/tests.py @@ -3,10 +3,12 @@ from django.test import TestCase, Client from django.contrib.auth.models import User from members.management.commands.createsahkopiikkiuser import Command as SahkopiikkiCommand -from members.models import Member +from members.models import Member, Payment, Request from rest_framework.authtoken.models import Token import logging +import os +import pyexcel class MemberRegisterTestCase(TestCase): @@ -14,7 +16,13 @@ class MemberRegisterTestCase(TestCase): def setUp(self): """Setup testing environment by creating member and admin.""" - memb = Member.objects.create(first_name="Tidus", last_name="Tester") + memb = Member.objects.create(first_name="Tidus", last_name="Tester", email="tidus@tester.fi") + payment = Payment.objects.create(member=memb, source='AYY') + appl = Request.objects.create( + first_name="Liisa", last_name="Mattila", + email="liisa.mattila@pylly.com", POR="Kouvola", + AYY=True, jas=False) + username, password = 'test_admin', 'password123' test_admin = User.objects.create_superuser( username, 'myemail@test.com', password) @@ -31,16 +39,27 @@ class MemberRegisterTestCase(TestCase): def test_import_csv_single_line(self): """Test csv import only with single line in csv file.""" - data = 'Teppo, Tulppu, teppo@tulppu.fi, Ankkalinna, 0, 0' - response = self.c.post('/members/import_csv', {'textarea': data}, follow=True) + + current_dir = os.path.dirname(os.path.abspath(__file__)) + with open(os.path.join(current_dir, 'test_resources', 'single_line_import.csv')) as csvFile: + response = self.c.post('/members/import_csv', { + 'csvFile': csvFile, + 'delimiter': ';', + 'payment_source': 'AYY' + }, follow=True) self.assertEqual(response.status_code, 200) def test_import_csv_multi_line(self): """Test csv import with multilined csv.""" - data = ('Teppo, Tulppu, teppo@tulppu.fi, Ankkalinna, 0, 0\n' - 'Reiska, Remontti, remontti@reiska.fi, Värisilmä, 1, 1') - response = self.c.post('/members/import_csv', {'textarea': data}, follow=True) + current_dir = os.path.dirname(os.path.abspath(__file__)) + with open(os.path.join(current_dir, 'test_resources', 'multi_line_import.csv')) as csvFile: + response = self.c.post('/members/import_csv', { + 'csvFile': csvFile, + 'delimiter': ';', + 'payment_source': 'AYY' + }, follow=True) + self.assertEqual(response.status_code, 200) def test_autocomplete_search_found(self): @@ -87,3 +106,50 @@ class MemberRegisterTestCase(TestCase): response = self.c.get('/members/check?email={}'.format(email), follow=True) self.assertEqual(response.status_code, 401) + + def test_export_members_excel(self): + """Test if the user can download an excel file of the member register""" + resp = self.c.get('/members/export_members') + content_type = 'application/vnd.ms-excel' + self.assertIn(content_type, resp['Content-Type']) + + content = resp.content + arrays = pyexcel.get_array(file_content=content, file_type='xlsx') + tidus_array = ['Tidus', 'Tester', 'tidus@tester.fi', '', '0', '0'] + self.assertIn(tidus_array, arrays) + + def test_export_payments_excel(self): + """Test if the user can download an excel file of the payment register""" + resp = self.c.get('/members/export_payments') + content_type = 'application/vnd.ms-excel' + self.assertIn(content_type, resp['Content-Type']) + + content = resp.content + arrays = pyexcel.get_array(file_content=content, file_type='xlsx') + created = Payment.objects.get(member__email='tidus@tester.fi').date.strftime('%Y-%m-%d %H:%M:%S') + tidus_array = ['Tidus Tester', created, 'AYY'] + self.assertIn(tidus_array, arrays) + + def test_export_applications_excel(self): + """Test if the user can download an excel file of the member application register""" + resp = self.c.get('/members/export_applications') + content_type = 'application/vnd.ms-excel' + self.assertIn(content_type, resp['Content-Type']) + + content = resp.content + arrays = pyexcel.get_array(file_content=content, file_type='xlsx') + submitted = Request.objects.get(email='liisa.mattila@pylly.com').submitted.strftime('%Y-%m-%d %H:%M:%S') + liisa_array = ['Liisa', 'Mattila', 'liisa.mattila@pylly.com', 'Kouvola', '1', '0', submitted] + self.assertIn(liisa_array, arrays) + + def test_submit_member_application(self): + """Test if submitting a member application works""" + data = { + 'first_name': 'Seppo', 'last_name': 'Saastamoinen', + 'email': 'seppo@saastamoin.en', 'jas': 'on', + 'POR': 'Dipolin viinibaari' + } + resp = self.c.post('/members/submit_application', data=data) + self.assertEqual(resp.status_code, 200) + + self.assertTrue(Request.objects.filter(email='seppo@saastamoin.en').exists()) diff --git a/members/views/applications.py b/members/views/applications.py index 3fb0cef..f1b5321 100644 --- a/members/views/applications.py +++ b/members/views/applications.py @@ -14,6 +14,7 @@ import html from members.views.utils import * from members.tables import RequestTable from members.forms import ApplicationForm +from members.views import error_view @ensure_csrf_cookie @@ -47,8 +48,7 @@ def application_edit(request, *args, **kwargs): """Edit member request information.""" i = kwargs.pop('index', None) if i is None: - return render( - request, 'error.html', {'error': _('No application id specified')}) + return error_view(request, _('No application id specified')) else: application = Request.objects.get(id=i) form = ApplicationForm(instance=application) @@ -68,9 +68,7 @@ def application_accept(request, *args, **kwargs): if id is not None: application = Request.objects.get(id=id) else: - return render(request, - 'error.html', - {'error': _("Application missing 'id' field.")}) + return error_view(request, _("Application missing 'id' field.")) form = ApplicationForm(request.POST, instance=application) if form.is_valid(): @@ -78,9 +76,9 @@ def application_accept(request, *args, **kwargs): application = form.save() if Member.objects.filter(email=application.email).exists(): - return render(request, - 'error.html', - {'error': _('Email {} is already in use by a member. Application cannot be accepted.').format(application.email)}) + return error_view(request, _( + 'Email {} is already in use by a member. Application cannot be accepted.' + ).format(application.email)) member = application.to_member() member.save() @@ -96,14 +94,10 @@ def application_accept(request, *args, **kwargs): '/members/list?notification={}'.format(html.escape(notification))) except Exception as ex: logging.exception('Exception while accepting application') - return render(request, - 'error.html', - {'error': str(ex)}) + return error_view(request, str(ex)) else: logging.info(form) - return render(request, - 'error.html', - {'error': form.errors}) + return error_view(request, form.errors) @ensure_csrf_cookie @@ -115,8 +109,7 @@ def application_delete(request, *args, **kwargs): try: id = request.POST['id'] except KeyError: - return render( - request, 'error.html', {'error': _('No application id specified')}) + return error_view(request, _('No application id specified')) try: application = Request.objects.get(id=id) @@ -130,9 +123,7 @@ def application_delete(request, *args, **kwargs): '/members/applications?notification={}' .format(html.escape(notification))) except: - return render(request, - 'error.html', - {'error': _('Could not delete application object')}) + return error_view(request, _('Could not delete application object')) @ensure_csrf_cookie @@ -143,9 +134,7 @@ def application_delete_confirm(request, *args, **kwargs): """Confirm application deletion.""" i = kwargs.pop('index', None) if i is None: - return render(request, - 'error.html', - {'error': _('No application id specified')}) + return error_view(request, _('No application id specified')) else: application = Request.objects.get(id=i) form = ApplicationForm(instance=application) @@ -172,6 +161,4 @@ def application_submit(request, *args, **kwargs): form.save() return render(request, 'application_success.html', {}) else: - return render(request, - 'error.html', - {'error': form.errors}) + return error_view(request, form.errors) diff --git a/members/views/members.py b/members/views/members.py index ada6953..4ae9a6b 100644 --- a/members/views/members.py +++ b/members/views/members.py @@ -70,8 +70,7 @@ def member_delete_confirm(request, *args, **kwargs): """Render member deletion confirmation page.""" i = kwargs.pop('index', None) if i is None: - return render(request, 'error.html', - {'error': _('No member id specified')}) + return error_view(request, _('No member id specified')) else: member = Member.objects.get(id=i) form = MemberForm(instance=member) @@ -133,7 +132,7 @@ def member_submit(request, *args, **kwargs): return HttpResponseRedirect( '/members/list?notification={}'.format(html.escape(notification))) else: - return render(request, 'error.html', {'error': form.errors}) + return error_view(request, form.errors) @ensure_csrf_cookie @@ -147,10 +146,7 @@ def member_update(request, *args, **kwargs): if id is not None: member = Member.objects.get(id=id) else: - return render(request, - 'error.html', - {'error': _("Member missing 'id' field.")}) - logging.debug(member) + return error_view(request, _("Member missing 'id' field.")) form = MemberForm(request.POST, instance=member) if form.is_valid(): @@ -164,10 +160,7 @@ def member_update(request, *args, **kwargs): return HttpResponseRedirect( '/members/list?notification={}'.format(html.escape(notification))) else: - return render( - request, - 'error.html', - {'error': form.errors}) + return error_view(request, form.errors) @ensure_csrf_cookie @@ -179,8 +172,7 @@ def member_delete(request, *args, **kwargs): try: id = request.POST['id'] except KeyError: - return render(request, - 'error.html', {'error': _('No member id specified')}) + return error_view(request, _('No member id specified')) try: member = Member.objects.get(id=id) @@ -193,9 +185,7 @@ def member_delete(request, *args, **kwargs): return HttpResponseRedirect( '/members/list?notification={}'.format(html.escape(notification))) except: - return render(request, - 'error.html', - {'error': _('Could not delete member object')}) + return error_view(request, _('Could not delete member object')) @ensure_csrf_cookie @@ -206,8 +196,7 @@ def member_edit(request, *args, **kwargs): """Edit member information.""" i = kwargs.pop('index', None) if i is None: - return render( - request, 'error.html', {'error': _('No member id specified')}) + return error_view(request, _('No member id specified')) else: member = Member.objects.get(id=i) form = MemberForm(instance=member) diff --git a/members/views/payments.py b/members/views/payments.py index 4c9a587..11db4db 100644 --- a/members/views/payments.py +++ b/members/views/payments.py @@ -14,6 +14,7 @@ import html from members.views.utils import * from members.tables import PaymentTable from members.forms import PaymentForm +from members.views import error_view @ensure_csrf_cookie @@ -73,7 +74,7 @@ def payment_submit(request, *args, **kwargs): '/members/payments?notification={}' .format(html.escape(notification))) else: - return render(request, 'error.html', {'error': form.errors}) + return error_view(request, form.errors) @ensure_csrf_cookie @@ -84,9 +85,7 @@ def payment_edit(request, *args, **kwargs): """Edit payment.""" i = kwargs.pop('index', None) if i is None: - return render(request, - 'error.html', - {'error': _('No payment id specified')}) + return error_view(request, _('No payment id specified')) else: payment = Payment.objects.get(id=i) form = PaymentForm(instance=payment) @@ -103,9 +102,7 @@ def payment_delete_confirm(request, *args, **kwargs): """Render payment delete confirmation page.""" i = kwargs.pop('index', None) if i is None: - return render(request, - 'error.html', - {'error': _('No payment id specified')}) + return error_view(request, _('No payment id specified')) else: payment = Payment.objects.get(id=i) form = PaymentForm(instance=payment) @@ -123,9 +120,7 @@ def payment_delete(request, *args, **kwargs): try: id = request.POST['id'] except KeyError: - return render(request, - 'error.html', - {'error': _('No payment id specified')}) + return error_view(request, _('No payment id specified')) try: payment = Payment.objects.get(id=id) @@ -138,9 +133,7 @@ def payment_delete(request, *args, **kwargs): '/members/payments?notification={}' .format(html.escape(notification))) except: - return render(request, - 'error.html', - {'error': _('Could not delete payment object')}) + return error_view(request, _('Could not delete payment object')) @ensure_csrf_cookie @@ -165,6 +158,4 @@ def payment_update(request, *args, **kwargs): '/members/payments?notification={}' .format(html.escape(notification))) else: - return render(request, - 'error.html', - {'error': _('Could not update payment object')}) + return error_view(request, _('Could not update payment object')) diff --git a/members/views/utils.py b/members/views/utils.py index 8b26496..773be1d 100644 --- a/members/views/utils.py +++ b/members/views/utils.py @@ -35,8 +35,8 @@ class MemberDetail(generics.RetrieveAPIView): throttle_classes = (BurstRateThrottle, SustainedRateThrottle, ) -def error_view(request, message): - return render(request, 'error.html', {'error': str(message)}) +def error_view(request, message, status=400): + return render(request, 'error.html', {'error': message}, status=400) def validate_recaptcha(response): @@ -116,9 +116,7 @@ def import_csv(request, *args, **kwargs): delimiter = request.POST.get('delimiter', ',') payment_source = request.POST['payment_source'] except: - return render(request, - 'error.html', - {'error': _('Missing CSV file')}) + return error_view(request, _('Missing CSV file')) try: result = MemberForm.csv_to_models(data, payment_source=payment_source, delimiter=delimiter) @@ -127,7 +125,7 @@ def import_csv(request, *args, **kwargs): return error_view(request, ex.form_errors) except Exception as ex: logging.exception('Other error in CSV import') - return error_view(request, ex) + return error_view(request, str(ex)) member_table = MemberTable(result.members, request=request,