view sat_website/forms.py @ 94:c1b77f07f644

replace shipped file unicodecsv.py with the module of the same name
author souliane <souliane@mailoo.org>
date Tue, 23 Jun 2015 18:34:14 +0200
parents 13ebb548f234
children dc8a30f6c369
line wrap: on
line source

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
SàT website: Salut à Toi's presentation website
Copyright (C) 2012  Jérôme Poisson (goffi@goffi.org)

This file is part of SàT website.

SàT website is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Foobar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
"""

from django.utils.translation import ugettext_lazy as _, ugettext, string_concat, get_language
from django.core.mail import send_mail
from django import forms
from django.conf import settings
from collections import OrderedDict
import unicodecsv
import utils
import re


## Fields ##


class Section(forms.Field):
    def __init__(self, *args, **kwargs):
        kwargs['required'] = False
        super(Section, self).__init__(*args, **kwargs)

class BooleanField(forms.BooleanField):
    def __init__(self, *args, **kwargs):
        super(BooleanField, self).__init__(*args, **kwargs)

class CharField(forms.CharField):
    def __init__(self, label=None, *args, **kwargs):
        try:
            placeholder = kwargs.pop('placeholder')
        except KeyError:
            placeholder = label

        super(CharField, self).__init__(*args, **kwargs)
        self.widget.attrs.update({'class': "form-control",
                                  'placeholder': placeholder})

class EmailField(forms.EmailField):
    def __init__(self, *args, **kwargs):
        super(EmailField, self).__init__(*args, **kwargs)
        self.widget.attrs.update({'class': "form-control",
                                  'placeholder': self.label})

class ChoiceField(forms.ChoiceField):
    def __init__(self, *args, **kwargs):
        super(ChoiceField, self).__init__(*args, **kwargs)
        self.widget.attrs.update({'class': "form-control"})

    def choice_label(self, value):
        """Return the label corresponding to the given value.

        @param value (unicode): a choice value
        @return: unicode
        """
        for current_value, label in self.choices:
            if unicode(current_value) == unicode(value):
                return unicode(label)
        return u''


## Forms ##


class RegistrationForm(forms.Form):

    section_1 = Section(label=_(u'Identity'))
    name = CharField(label=_(u'Given name'))
    surname = CharField(label=_(u'Family name'))
    address = CharField(label=_(u"Address, postal code, municipality"), widget=forms.Textarea(attrs={'rows': 3}))

    section_2 = Section(label=_(u'Contacts'))
    email = EmailField(label=_(u'Email address'))
    email_confirmation = EmailField(label=_(u'Email address confirmation'))
    jid = EmailField(required=False, label=_(u'Jabber ID (for example your SàT login)'))

    section_3 = Section(label=_(u'Subscription'))
    subscription_amount = ChoiceField(choices=[(amount, u"%s €" % amount) for amount in utils.get_asso_subscr_amounts()])

    section_3b = Section(label="")
    payment_method = ChoiceField(choices=[(u"transfer", _(u"Bank transfer")), (u"card", _(u"Credit or debit card"))],
                               help_text=_(u'Choose "Bank transfer" to proceed manually with the association\'s IBAN/BIC numbers. Choose "Credit or debit card" to pay via CB, Visa or Mastercard using a secure banking service. For both methods, we will first send you an email containing all the details.'), widget=forms.RadioSelect)

    section_5 = Section(label=_(u'Reference'))
    reference = CharField(required=False, label=_(u"Reference"), placeholder=_(u"Adherent number in case of a renewal"))

    section_6 = Section(label=_(u'Comment'))
    comment = CharField(required=False, label=_(u"Comment"), placeholder="", widget=forms.Textarea(attrs={'rows': 3}))

    mailing = BooleanField(required=False, label=_(u"I would like to subscribe to the adherents' mailing list."))

    def html_link(url, label):
        return string_concat('<a target="#" href="', url, '">', label, '</a>')

    agreement_label = [_(u"I read the "),
                       html_link(settings.ASSO_URL_STATUTES, _(u"Statutes")),
                       _(u" and "),
                       html_link(settings.ASSO_URL_RULES, _(u"Rules")),
                       _(u" of the association, and agree to both of them."),
                       ]
    agreement_confirmation = BooleanField(label=string_concat(*agreement_label))

    def sections(self):
        """Get the fields grouped in sections.

        @return: OrderedDict binding section name to a list of fields
        """
        sections = OrderedDict()
        current_section = None
        for field in self:
            if isinstance(field.field, Section):
                current_section = sections.setdefault(field.label, [])
            else:
                current_section.append(field)
        return sections

    def clean(self):
        cleaned_data = super(RegistrationForm, self).clean()
        email = cleaned_data.get("email")
        email_confirmation = cleaned_data.get("email_confirmation")

        if email and email_confirmation and email != email_confirmation:
            msg = _(u"Passwords don't match.")
            self.add_error('email_confirmation', msg)


    def results(self, user_readable=True):
        """Get the results submitted by the user as a list.

        @param user_readable: (bool) set to True to prefer the fields' labels
            to their names, also filter out the empty fields.
        @return: list of couple (name, value) or (label, value)
        """
        if not self.is_valid():
            return None
        results = []
        for field in self:
            if isinstance(field.field, Section):
                continue  # filter out section fields
            if field.name in ('email_confirmation', 'agreement_confirmation'):
                continue  # filter out confirmation fields
            if user_readable and not field.value():
                continue  # filter out empty value
            if user_readable and field.name == "payment_method" and self['subscription_amount'].value() == "0":
                continue  # filter out fields that are not pertinent for the user
            key = field.name
            if isinstance(field.field, BooleanField) and user_readable:
                value = ugettext(u"yes") if field.value() else ugettext(u"no")
            else:
                value = re.sub(r"[\n\r]+", ", ", unicode(field.value()))
            if user_readable:
                if isinstance(field.field, BooleanField):
                    key = key.capitalize()  # to get Mailing instead of "I would like..."
                else:
                    key = field.label
                if isinstance(field.field, ChoiceField):
                    value = field.field.choice_label(value)
            results.append((key, value))
        if user_readable:
            results.append((_(u'Language'), utils.get_language_name_local(get_language())))
        else:
            results.append(('lang', get_language()))
        return results

    def result_as_dict(self, user_readable=True):
        """Get the results submitted by the user as an OrderedDict.

        @param user_readable (bool): set to True to prefer the field labels to their names
        @return: dict {name: value} or {label: value}
        """
        return {key: value for key, value in self.results(user_readable)}

    def result_as_string(self, user_readable=True):
        """Get the result as a string to be sent for example via email.

        @param user_readable (bool): set to True to prefer the field labels to their names
        @return: unicode
        """
        return '\n'.join([name + ': ' + value for name, value in self.results(user_readable)])

    def prepareResultForUser(self):
        """Get the email body to send to the subscriber.

        @return: unicode
        """
        ref = self['reference'].value()
        data = {'name': self['name'].value(),
                'surname': self['surname'].value(),
                'amount': self['subscription_amount'].value(),
                'ref_info': '(ref. {ref})'.format(ref=ref) if ref else '',
                'iban': settings.ASSO_IBAN,
                'bic': settings.ASSO_BIC,
                'result': self.result_as_string(True)
                }

        HEADER = ugettext(u"""Thank you, {name}!

We received your submission and we are happy to count you in the members of the association.

""")
        PAYMENT = ugettext(u"""You chose to support Salut à Toi with a subscription of {amount} euros. Please complete your membership with a bank transfer to:

Payee: Salut à Toi
IBAN: {iban}
BIC: {bic}
Reason: subscription of {name} {surname} {ref_info}

Or, if you prefer, you can proceed with a credit or debit card:

https://www.apayer.fr/salut-a-toi

""")
        FOOTER = ugettext(u"""Below a copy of the information we received:

{result}

If you have any question, feel free to contact us.

Association Salut à Toi
http://salut-a-toi.org""")

        return (HEADER + (PAYMENT if int(data['amount']) > 0 else "") + FOOTER).format(**data)

    def prepareResultForAdmin(self):
        """Get the email body to send to the admins.

        @return: unicode
        """
        data = {'name': self['name'].value(),
                'result': self.result_as_string(False)
                }

        MSG = ugettext(u"""New subscription received!

{result}

An email has been automatically sent to {name}, no additional action is required from your side.""")

        return MSG.format(**data)

    def writeResultToCSV(self):
        result = [unicode(value) for key, value in self.results(False)]
        with open(settings.ASSO_SUBSCR_CSV, 'a+') as csvfile:
            writer = unicodecsv.writer(csvfile, delimiter=';')
            writer.writerow(result)

    def process_submitted_data(self):
        """Send emails to the subscriber and the admins."""
        if not self.is_valid():
            return
        # send email to user
        send_mail(_(u'Subscription to Salut à Toi'), self.prepareResultForUser(), settings.FORM_FROM_EMAIL, [self['email'].value()], fail_silently=False)
        # send email to admins
        send_mail(_(u'Subscription to Salut à Toi'), self.prepareResultForAdmin(), settings.FORM_FROM_EMAIL, settings.FORM_TO_EMAILS, fail_silently=False)
        # save to a CSV file
        self.writeResultToCSV()