From 08710b3705cdc018c4a8b9622f2c11f5a9f5aae4 Mon Sep 17 00:00:00 2001 From: henu Date: Wed, 20 Sep 2017 21:00:58 +0300 Subject: [PATCH] Fix members pep8 and add docstrings --- members/admin.py | 2 + members/apps.py | 4 + members/forms.py | 11 ++ members/models.py | 44 +++++--- members/serializers.py | 9 +- members/tables.py | 23 +++- members/tests.py | 12 ++- members/throttles.py | 6 ++ members/urls.py | 8 +- members/views.py | 235 +++++++++++++++++++++++++++++++---------- 10 files changed, 271 insertions(+), 83 deletions(-) diff --git a/members/admin.py b/members/admin.py index b150c1d..6607a19 100644 --- a/members/admin.py +++ b/members/admin.py @@ -1,3 +1,5 @@ +"""Admin site registers for Members app.""" + from django.contrib import admin from members.models import Member, Request, Payment, MemberConflict diff --git a/members/apps.py b/members/apps.py index f773ade..77801d7 100644 --- a/members/apps.py +++ b/members/apps.py @@ -1,5 +1,9 @@ +"""App configurations for members app.""" + from django.apps import AppConfig class MembersConfig(AppConfig): + """Class for Members app configurations.""" + name = 'members' diff --git a/members/forms.py b/members/forms.py index a6e47ce..1ac3a4d 100644 --- a/members/forms.py +++ b/members/forms.py @@ -1,3 +1,5 @@ +"""File containing member forms.""" + from django import forms from django.utils.translation import ugettext_lazy as _ @@ -5,15 +7,21 @@ from members.models import Member, Payment, Request class MemberForm(forms.ModelForm): + """Member model form.""" class Meta: + """Meta for Member model form.""" + model = Member fields = ['first_name', 'last_name', 'email', 'AYY', 'jas', 'POR'] class PaymentForm(forms.ModelForm): + """Payment model form.""" class Meta: + """Meta for Payment model form.""" + model = Payment fields = ['date', 'source', 'member'] labels = { @@ -22,7 +30,10 @@ class PaymentForm(forms.ModelForm): class ApplicationForm(forms.ModelForm): + """Member application model form.""" class Meta: + """Meta for application model form.""" + model = Request fields = ['first_name', 'last_name', 'email', 'AYY', 'jas', 'POR'] diff --git a/members/models.py b/members/models.py index a8c46d0..c845aa2 100644 --- a/members/models.py +++ b/members/models.py @@ -1,31 +1,36 @@ +"""File containing Members app models.""" + from django.db import models from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from datetime import datetime import csv -import logging class BaseMember(models.Model): - ''' - Base model for member. - ''' + """Abstract base model for member.""" + first_name = models.CharField(_("First name"), max_length=127) last_name = models.CharField(_("Last name"), max_length=127) email = models.EmailField(_("Email")) - POR = models.CharField(_("Place of residence"), max_length=255) # place of residence + POR = models.CharField(_("Place of residence"), + max_length=255) # place of residence AYY = models.BooleanField(_("AYY"), default=False) jas = models.BooleanField(_("JAS"), default=False) class Meta: + """Meta for base member model.""" + abstract = True def __str__(self): + """Return member last name, first name and email.""" return "{} {}, {}".format(self.last_name, self.first_name, self.email) @staticmethod def from_csv(data): + """Construct member model from csv data.""" print("Imported CSV data: {}".format(data)) clean_data = data.strip().split('\n') csv_reader = csv.reader(clean_data) @@ -50,6 +55,7 @@ class BaseMember(models.Model): return True def as_array(self): + """Return member model as an array.""" return [ self.first_name, self.last_name, @@ -61,21 +67,20 @@ class BaseMember(models.Model): class Request(BaseMember): - ''' - Member request model represents one member request. - ''' + """Member request model represents one member request.""" + submitted = models.DateTimeField(_('Submitted'), default=timezone.now) def to_member(self): + """Convert array to member model.""" member = Member.from_array(self.as_array()) return member class Payment(models.Model): - ''' - Payment model representing one payment event - ''' + """Payment model representing one payment event.""" + date = models.DateTimeField(_('Date'), default=datetime.now) source = models.CharField(_('Source'), choices=[ ('AYY', _('AYY')), @@ -90,16 +95,17 @@ class Payment(models.Model): related_name='payments') def __str__(self): + """Return payment id and date.""" return 'Payment no. {}, {}'.format(self.id, str(self.date)) class Member(BaseMember): - ''' - Member model represets one member on the registry. - ''' + """Member model represets one member on the registry.""" + created = models.DateTimeField(_('Created'), default=datetime.now) def last_paid(self): + """Return member's last payment.""" try: payments = Payment.objects.filter(member=self) latest = payments.latest('date') @@ -110,6 +116,7 @@ class Member(BaseMember): @staticmethod def from_array(array): + """Create member from array.""" if len(array) != 6: raise Exception("Invalid array length for member instantiation") @@ -124,16 +131,21 @@ class Member(BaseMember): class MemberConflict(models.Model): + """Model representing member conflict situation.""" - first_member = models.ForeignKey('Member', related_name='%(class)s_first_member') - second_member = models.ForeignKey('Member', related_name='%(class)s_second_member') + first_member = models.ForeignKey( + 'Member', related_name='%(class)s_first_member') + second_member = models.ForeignKey( + 'Member', related_name='%(class)s_second_member') @property def first_member_form(self): + """Get first member form.""" return MemberForm(instance=self.first_member) @property def second_member_form(self): + """Get second member form.""" return MemberForm(instance=self.second_member) diff --git a/members/serializers.py b/members/serializers.py index 8273291..9d1ff21 100644 --- a/members/serializers.py +++ b/members/serializers.py @@ -1,10 +1,17 @@ +"""File containing member serializers.""" + from rest_framework import serializers from members.models import Member class MemberSerializer(serializers.ModelSerializer): + """Model serializer for member.""" + paid = serializers.DateTimeField(source='last_paid') class Meta: + """Meta of member serializer.""" + model = Member - fields = ('id', 'first_name', 'last_name', 'email', 'POR', 'AYY', 'jas', 'created', 'paid') + fields = ('id', 'first_name', 'last_name', 'email', + 'POR', 'AYY', 'jas', 'created', 'paid') diff --git a/members/tables.py b/members/tables.py index 1910c2d..a6274ec 100644 --- a/members/tables.py +++ b/members/tables.py @@ -1,3 +1,5 @@ +"""File containing member application django tables.""" + import django_tables2 as tables from django.utils.translation import ugettext as _ @@ -5,43 +7,56 @@ from members.models import Member, Payment, Request class MemberTable(tables.Table): + """Table for member.""" - last_paid = tables.DateTimeColumn(accessor='last_paid', verbose_name=_('Last paid')) + last_paid = tables.DateTimeColumn( + accessor='last_paid', verbose_name=_('Last paid')) options = tables.TemplateColumn( - '' + + ('') + _('Edit') + '', verbose_name=_('Options') ) class Meta: + """Meta for member table.""" + model = Member class PaymentTable(tables.Table): + """Table for payments.""" member = tables.Column(accessor='member', verbose_name=_('Member')) options = tables.TemplateColumn( - '' + + ('') + _('Edit') + '', verbose_name=_('Options') ) class Meta: + """Meta for payment table.""" + model = Payment class RequestTable(tables.Table): + """Table for member applications.""" options = tables.TemplateColumn( - '' + + ('') + _('Edit') + '', verbose_name=_('Options') ) class Meta: + """Meta for request table.""" + model = Request diff --git a/members/tests.py b/members/tests.py index 025c3d9..3987d38 100644 --- a/members/tests.py +++ b/members/tests.py @@ -1,28 +1,34 @@ +"""File containing Member app tests.""" + from django.test import TestCase, Client from django.contrib.auth.models import User -import time - from members.models import Member class MemberRegisterTestCase(TestCase): + """Tests member registration.""" def setUp(self): + """Setup testing environment by creating member and admin.""" memb = Member.objects.create(first_name="Tidus", last_name="Tester") - test_admin = User.objects.create_superuser('test_admin', 'myemail@test.com', 'password123') + test_admin = User.objects.create_superuser( + 'test_admin', 'myemail@test.com', 'password123') self.c = Client() def test_member_created(self): + """Test member creation.""" exists = Member.objects.filter(first_name="Tidus").exists() self.assertTrue(exists) 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}) self.assertIn(response.status_code, [200, 302]) 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') diff --git a/members/throttles.py b/members/throttles.py index 0c1e17b..3004a82 100644 --- a/members/throttles.py +++ b/members/throttles.py @@ -1,9 +1,15 @@ +"""File containing throttle rates for API.""" + from rest_framework.throttling import UserRateThrottle class BurstRateThrottle(UserRateThrottle): + """Class for burst rate throttle.""" + scope = 'burst' class SustainedRateThrottle(UserRateThrottle): + """Class for sustained rate throttle.""" + scope = 'sustained' diff --git a/members/urls.py b/members/urls.py index 9738af6..ad35248 100644 --- a/members/urls.py +++ b/members/urls.py @@ -1,3 +1,5 @@ +"""File containing Member application URLs.""" + from django.conf.urls import url from django.views.generic.base import RedirectView @@ -32,7 +34,8 @@ from members.views import application_form_success # from members.views import validateEmail, validate_success, validate_fail -favicon_view = RedirectView.as_view(url='static/img/favicon.ico', permanent=True) +favicon_view = RedirectView.as_view( + url='static/img/favicon.ico', permanent=True) urlpatterns = [ @@ -75,7 +78,8 @@ urlpatterns = [ url(r'^application/success$', application_form_success), # delete confirmation view for applications - url(r'^delete_application_confirm/(?P\d+)$', application_delete_confirm), + url(r'^delete_application_confirm/(?P\d+)$', + application_delete_confirm), # list all payment events url(r'^payments$', payment_list), diff --git a/members/views.py b/members/views.py index da03f3d..ca976c8 100644 --- a/members/views.py +++ b/members/views.py @@ -1,3 +1,5 @@ +"""File containing Members application views.""" + from django.shortcuts import render from django.contrib.auth.decorators import permission_required from django.views.decorators.http import require_http_methods @@ -33,13 +35,12 @@ from members.tables import MemberTable, PaymentTable, RequestTable def validate_recaptcha(response): - ''' - Recaptcha is used in member applications + """ + Recaptcha is used in member applications. :param response: :return: Boolean, success or not - ''' - + """ values = { 'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY, 'response': response, @@ -56,6 +57,7 @@ def validate_recaptcha(response): def send_mail_wrapper(subject, message): + """Call send_mail function.""" send_mail(subject, message, 'no-reply@sahkoinsinoorikilta.fi', @@ -64,7 +66,9 @@ def send_mail_wrapper(subject, message): def convert_table_to_html(table, request): - ''' + """ + Convert table to html. + This is a horrible hack for converting a table object to raw html. Even with extensive research I wasn't able to find a way to add a path prefix "e.g. /members/list" to the query strings "e.g. ?sort=foo", so I @@ -76,7 +80,7 @@ def convert_table_to_html(table, request): :param table: Table object from members.tables :param request: HttpRequest :return: Raw html string - ''' + """ table_as_html = table.as_html(request) path = request.path @@ -88,6 +92,7 @@ def convert_table_to_html(table, request): @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') def member_list(request, *args, **kwargs): + """Render members list.""" members = Member.objects.all() table = MemberTable(members, @@ -111,6 +116,7 @@ def member_list(request, *args, **kwargs): @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') def member_add(request, *args, **kwargs): + """Render add member page.""" form = MemberForm() return render(request, 'member_add.html', {'form': form}) @@ -119,19 +125,23 @@ def member_add(request, *args, **kwargs): @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') 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 render(request, 'error.html', + {'error': _('No member id specified')}) else: member = Member.objects.get(id=i) form = MemberForm(instance=member) - return render(request, 'member_delete_confirm.html', {'member_id': i, 'form': form}) + return render(request, 'member_delete_confirm.html', + {'member_id': i, 'form': form}) @ensure_csrf_cookie @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') def member_add_many(request, *args, **kwargs): + """Render add multiple members page.""" return render(request, 'member_add_many.html', {}) @@ -139,15 +149,18 @@ def member_add_many(request, *args, **kwargs): @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') def member_submit(request, *args, **kwargs): + """Add member based on data gained from member form.""" form = MemberForm(request.POST) if form.is_valid(): form.save() - logging.info("Saved new member to member register with the following info: {}".format(form)) + logging.info("Saved new member to member register" + "with the following info: {}".format(form)) notification = "{} {} {}.".format(_("Successfully added member"), form.cleaned_data['last_name'], form.cleaned_data['first_name']) - return HttpResponseRedirect('/members/list?notification={}'.format(html.escape(notification))) + return HttpResponseRedirect( + '/members/list?notification={}'.format(html.escape(notification))) else: return render(request, 'error.html', {'error': form.errors}) @@ -156,6 +169,7 @@ def member_submit(request, *args, **kwargs): @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') def member_update(request, *args, **kwargs): + """Update member information.""" form = MemberForm(request.POST) if form.is_valid(): id = request.POST['id'] @@ -163,51 +177,68 @@ def member_update(request, *args, **kwargs): form = MemberForm(request.POST, instance=member) form.save() - logging.info("Updated member in member register with the following info: {}".format(form)) + logging.info( + "Updated member in member register with the following info: {}" + .format(form)) notification = "{} {} {}.".format(_("Successfully updated member"), member.last_name, member.first_name) - return HttpResponseRedirect('/members/list?notification={}'.format(html.escape(notification))) + return HttpResponseRedirect( + '/members/list?notification={}'.format(html.escape(notification))) else: - return render(request, 'error.html', {'error': _('Could not update member object')}) + return render( + request, + 'error.html', + {'error': _('Could not update member object')}) @ensure_csrf_cookie @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') def member_delete(request, *args, **kwargs): + """Delete member.""" try: id = request.POST['id'] except KeyError: - return render(request, 'error.html', {'error': _('No member id specified')}) + return render(request, + 'error.html', {'error': _('No member id specified')}) try: member = Member.objects.get(id=id) notification = "{} {} {}.".format(_("Successfully deleted member"), member.last_name, member.first_name) member.delete() - logging.info("Delete member in member register with the following id: {}".format(id)) - return HttpResponseRedirect('/members/list?notification={}'.format(html.escape(notification))) + logging.info( + "Delete member in member register with the following id: {}" + .format(id)) + return HttpResponseRedirect( + '/members/list?notification={}'.format(html.escape(notification))) except: - return render(request, 'error.html', {'error': _('Could not delete member object')}) + return render(request, + 'error.html', + {'error': _('Could not delete member object')}) @ensure_csrf_cookie @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') 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 render( + request, 'error.html', {'error': _('No member id specified')}) else: member = Member.objects.get(id=i) form = MemberForm(instance=member) - return render(request, 'member_edit.html', {'member_id': i, 'form': form}) + return render( + request, 'member_edit.html', {'member_id': i, 'form': form}) @ensure_csrf_cookie @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') def application_list(request, *args, **kwargs): + """List member applications not yet processed.""" applications = Request.objects.all() application_count = len(applications) table = RequestTable(applications, @@ -229,19 +260,25 @@ def application_list(request, *args, **kwargs): @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') 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 render( + request, 'error.html', {'error': _('No application id specified')}) else: application = Request.objects.get(id=i) form = ApplicationForm(instance=application) - return render(request, 'application_edit.html', {'application_id': i, 'form': form}) + return render( + request, + 'application_edit.html', + {'application_id': i, 'form': form}) @ensure_csrf_cookie @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') def application_accept(request, *args, **kwargs): + """Accept application.""" form = ApplicationForm(request.POST) if form.is_valid(): id = request.POST['id'] @@ -251,52 +288,75 @@ def application_accept(request, *args, **kwargs): member.save() application.delete() - logging.info("Accepted application in member register with the following info: {}".format(form)) - notification = "{} {}.".format(_("Successfully accepted application"), str(application)) - return HttpResponseRedirect('/members/list?notification={}'.format(html.escape(notification))) + logging.info( + "Accepted application in member " + "register with the following info: {}" + .format(form)) + notification = "{} {}.".format(_("Successfully accepted application"), + str(application)) + return HttpResponseRedirect( + '/members/list?notification={}'.format(html.escape(notification))) else: - return render(request, 'error.html', {'error': _('Could not accept application object')}) + return render(request, + 'error.html', + {'error': _('Could not accept application object')}) @ensure_csrf_cookie @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') def application_delete(request, *args, **kwargs): + """Delete member application.""" try: id = request.POST['id'] except KeyError: - return render(request, 'error.html', {'error': _('No application id specified')}) + return render( + request, 'error.html', {'error': _('No application id specified')}) try: application = Request.objects.get(id=id) - notification = "{} {}.".format(_("Successfully deleted application"), str(application)) + notification = "{} {}.".format(_("Successfully deleted application"), + str(application)) application.delete() - logging.info("Delete application in member register with the following id: {}".format(id)) - return HttpResponseRedirect('/members/applications?notification={}'.format(html.escape(notification))) + logging.info( + "Delete application in member register with the following id: {}" + .format(id)) + return HttpResponseRedirect( + '/members/applications?notification={}' + .format(html.escape(notification))) except: - return render(request, 'error.html', {'error': _('Could not delete application object')}) + return render(request, + 'error.html', + {'error': _('Could not delete application object')}) @ensure_csrf_cookie @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') 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 render(request, + 'error.html', + {'error': _('No application id specified')}) else: application = Request.objects.get(id=i) form = ApplicationForm(instance=application) - return render(request, 'application_delete_confirm.html', {'application_id': i, 'form': form}) + return render(request, + 'application_delete_confirm.html', + {'application_id': i, 'form': form}) @ensure_csrf_cookie def application_form(request, *args, **kwargs): + """Render member application form.""" return render(request, 'application_index.html', {}) @ensure_csrf_cookie def application_form_success(request, *args, **kwargs): + """Render application Successfully sent page.""" return render(request, 'application_success.html', {}) @@ -304,6 +364,7 @@ def application_form_success(request, *args, **kwargs): @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') def payment_list(request, *args, **kwargs): + """Render list of payments.""" payments = Payment.objects.all() table = PaymentTable(payments, @@ -326,6 +387,7 @@ def payment_list(request, *args, **kwargs): @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') def payment_add(request, *args, **kwargs): + """Render add payment form.""" form = PaymentForm() return render(request, 'payment_add.html', {'form': form}) @@ -334,13 +396,19 @@ def payment_add(request, *args, **kwargs): @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') def payment_submit(request, *args, **kwargs): + """Submit payment.""" form = PaymentForm(request.POST) if form.is_valid(): form.save() - logging.info("Saved new payment to member register with the following info: {}".format(form)) - notification = "{} {}.".format(_("Successfully added payment for member"), - form.cleaned_data['member']) - return HttpResponseRedirect('/members/payments?notification={}'.format(html.escape(notification))) + logging.info( + "Saved new payment to member register with the following info: {}" + .format(form)) + notification = "{} {}.".format( + _("Successfully added payment for member"), + form.cleaned_data['member']) + return HttpResponseRedirect( + '/members/payments?notification={}' + .format(html.escape(notification))) else: return render(request, 'error.html', {'error': form.errors}) @@ -349,51 +417,71 @@ def payment_submit(request, *args, **kwargs): @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') 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 render(request, + 'error.html', + {'error': _('No payment id specified')}) else: payment = Payment.objects.get(id=i) form = PaymentForm(instance=payment) - return render(request, 'payment_edit.html', {'payment_id': i, 'form': form}) + return render(request, + 'payment_edit.html', + {'payment_id': i, 'form': form}) @ensure_csrf_cookie @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') 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 render(request, + 'error.html', + {'error': _('No payment id specified')}) else: payment = Payment.objects.get(id=i) form = PaymentForm(instance=payment) - return render(request, 'payment_delete_confirm.html', {'payment_id': i, 'form': form}) + return render(request, + 'payment_delete_confirm.html', + {'payment_id': i, 'form': form}) @ensure_csrf_cookie @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') def payment_delete(request, *args, **kwargs): + """Delete payment.""" try: id = request.POST['id'] except KeyError: - return render(request, 'error.html', {'error': _('No payment id specified')}) + return render(request, + 'error.html', + {'error': _('No payment id specified')}) try: payment = Payment.objects.get(id=id) - notification = "{} {}.".format(_("Successfully deleted payment"), str(payment)) + notification = "{} {}.".format( + _("Successfully deleted payment"), str(payment)) payment.delete() - logging.info("Delete payment '{}' in member register".format(str(payment))) - return HttpResponseRedirect('/members/payments?notification={}'.format(html.escape(notification))) + logging.info( + "Delete payment '{}' in member register".format(str(payment))) + return HttpResponseRedirect( + '/members/payments?notification={}' + .format(html.escape(notification))) except: - return render(request, 'error.html', {'error': _('Could not delete payment object')}) + return render(request, + 'error.html', + {'error': _('Could not delete payment object')}) @ensure_csrf_cookie @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') def payment_update(request, *args, **kwargs): + """Update payment information.""" form = PaymentForm(request.POST) if form.is_valid(): id = request.POST['id'] @@ -401,17 +489,25 @@ def payment_update(request, *args, **kwargs): form = PaymentForm(request.POST, instance=payment) form.save() - logging.info("Updated member in member register with the following info: {}".format(form)) - notification = "{} {}.".format(_("Successfully updated payment"), str(payment)) - return HttpResponseRedirect('/members/payments?notification={}'.format(html.escape(notification))) + logging.info( + "Updated member in member register with the following info: {}" + .format(form)) + notification = "{} {}.".format( + _("Successfully updated payment"), str(payment)) + return HttpResponseRedirect( + '/members/payments?notification={}' + .format(html.escape(notification))) else: - return render(request, 'error.html', {'error': _('Could not update payment object')}) + return render(request, + 'error.html', + {'error': _('Could not update payment object')}) @ensure_csrf_cookie @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') def settings_page(request, *args, **kwargs): + """Render member app settings page.""" return render(request, 'settings.html', {}) @@ -419,30 +515,40 @@ def settings_page(request, *args, **kwargs): @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') def import_csv(request, *args, **kwargs): + """Get csv data imported to page and create members based on that.""" try: data = request.POST['textfield'] except: - return render(request, 'error.html', {'error': _('Missing "textfield" POST request field')}) + return render(request, + 'error.html', + {'error': _('Missing "textfield" POST request field')}) success = Member.from_csv(data) if success: logging.info('Imported CSV data:\n'.format(data)) - notification = "{}.".format(_("Successfully imported multiple members")) - return HttpResponseRedirect('/members/list?notification={}'.format(html.escape(notification))) + notification = "{}.".format( + _("Successfully imported multiple members")) + return HttpResponseRedirect( + '/members/list?notification={}' + .format(html.escape(notification))) else: - return render(request, 'error.html', {'error': _('Failed to import members')}) + return render(request, + 'error.html', + {'error': _('Failed to import members')}) @ensure_csrf_cookie @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') def export_csv(request, *args, **kwargs): + """Export members as csv.""" response = HttpResponse() response['Content-type'] = 'text/csv' response['Accept'] = 'text/csv' response['Content-Disposition'] = 'filename; filename=members.csv' writer = csv.writer(response, csv.excel) - response.write(u'\ufeff'.encode('utf8')) # BOM (optional...Excel needs it to open UTF-8 file properly) + # BOM (optional...Excel needs it to open UTF-8 file properly) + response.write(u'\ufeff'.encode('utf8')) for obj in Member.objects.all(): data = obj.as_array() field_list = map(lambda d: str(d), data) @@ -456,6 +562,7 @@ def export_csv(request, *args, **kwargs): @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login') def member_duplicates(request, *args, **kwargs): + """Check for duplicate members.""" conflicts = MemberConflict.objects.all() context = { 'conflicts': conflicts @@ -468,13 +575,19 @@ def member_duplicates(request, *args, **kwargs): @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') def resolve_conflict(request, *args, **kwargs): + """Resolve duplicate member conflict.""" action = request.POST.get('action', None) if action not in ['first', 'second', 'both']: - return render(request, 'error.html', {'error': '{}: {}'.format(('Incorrect action value'), action)}) + return render(request, + 'error.html', + {'error': '{}: {}'.format(('Incorrect action value'), + action)}) id = request.POST.get('id', None) if id is None: - return render(request, 'error.html', {'error': '{}: {}'.format(('Incorrect id value'), id)}) + return render(request, + 'error.html', + {'error': '{}: {}'.format(('Incorrect id value'), id)}) conflict = MemberConflict.objects.get(id=id) first_member = conflict.first_member @@ -497,10 +610,12 @@ def resolve_conflict(request, *args, **kwargs): return HttpResponseRedirect('/members/duplicates') else: notification = _('Successfully resolved all member conflicts.') - return HttpResponseRedirect('/members/list?notification={}'.format(html.escape(notification))) + return HttpResponseRedirect( + '/members/list?notification={}'.format(html.escape(notification))) def send_mail_wrapper(subject, message, email_to): + """Send mail to default email.""" send_mail(subject, message, settings.DEFAULT_EMAIL_FROM, @@ -510,6 +625,7 @@ def send_mail_wrapper(subject, message, email_to): @receiver(post_save, sender=Request) def email_on_request(sender, instance, created, **kwargs): + """Send email validation.""" if not settings.ENABLE_AUTOMATIC_EMAILS: return @@ -524,6 +640,7 @@ def email_on_request(sender, instance, created, **kwargs): @receiver(post_save, sender=Member) def email_on_accept(sender, instance, created, **kwargs): + """Send email to accepted member.""" if not settings.ENABLE_AUTOMATIC_EMAILS: return @@ -537,6 +654,7 @@ def email_on_accept(sender, instance, created, **kwargs): def check_for_duplicates(instance): + """Check for member duplicates.""" name_candidates = Member.objects.filter(first_name=instance.first_name, last_name=instance.last_name) email_candidates = Member.objects.filter(email=instance.email) @@ -552,11 +670,14 @@ def check_for_duplicates(instance): @receiver(post_save, sender=Member) def duplicate_receiver(sender, instance, created, **kwargs): + """Call check_for_duplicates function.""" check_for_duplicates(instance) # Can be used to retrieve single member information via REST API class MemberDetail(generics.RetrieveAPIView): + """Member detail rest API view.""" + queryset = Member.objects.all() serializer_class = MemberSerializer permission_classes = (permissions.IsAdminUser, )