connect/utils.py
def send_connect_email(subject, template, recipient, site, sender='',
                       url='', comments='', logged_against=''):
    """
    Sends an email to notify users and moderators of relevant events.
    Generates a plain text email from html template counterpart.
    """

    email_header_url = site.config.email_header.url
    email_header = ''.join(['http://', site.domain, email_header_url])

    template_vars = {
        'recipient': recipient,
        'site_name': site.name,
        'url': url,
        'sender': sender,
        'comments': comments,
        'logged_against': logged_against,
        'contact_email':  site.config.email,
        'email_header': email_header,
        # TODO: dynamically retrieve color from CSS
        'link_color': 'e51e41'
    }

    # Render HTML email:
    html_body = render_to_string(template, template_vars)

    # Render plain text email:
    text_body = html_body

    # Strip out HTML head section:
    p = re.compile('<head>(.|\s)*?</head>')
    text_body = p.sub('', text_body)
    # Strip out excessive whitespace:
    text_body = strip_tags(text_body).strip()
    p = re.compile('(\r|\n)(\x20|\t)+')
    text_body = p.sub('\n', text_body)
    p = re.compile('(\r|\n)(\r|\n)+')
    text_body = p.sub('\n\n', text_body)

    email = send_mail(subject=subject,
                      message=text_body,
                      from_email=site.config.email,
                      recipient_list=[recipient.email],
                      html_message=html_body)

    return email
connect/moderation/models.py
class ModerationLogMsg(models.Model):
    """
    Log a moderation event, e.g. when a new user is invited, approved, etc.
    Or when an abuse report is dealt with
    """
    INVITATION = 'INVITATION'
    REINVITATION = 'REINVITATION'
    APPROVAL = 'APPROVAL'
    REJECTION = 'REJECTION'
    DISMISSAL = 'DISMISSAL'
    WARNING = 'WARNING'
    BANNING = 'BANNING'

    MSG_TYPE_CHOICES = [
        (INVITATION, _('Invitation')),
        (REINVITATION, _('Invitation Resent')),
        (APPROVAL, _('Application Approved')),
        (REJECTION, _('Application Rejected')),
        (DISMISSAL, _('Abuse Report Dismissed')),
        (WARNING, _('Official Warning')),
        (BANNING, _('Ban User')),
    ]

    msg_datetime = models.DateTimeField(_('date and time recorded'),
                                        default=timezone.now)
    msg_type = models.CharField(_('message type'), max_length=20,
                                choices=MSG_TYPE_CHOICES)
    comment = models.TextField(_('log comment'))
    pertains_to = models.ForeignKey(User, verbose_name=_('pertains to'),
                                    related_name='log_messages_about',
                                    help_text=_('User who moderation '
                                                'log is about'))
    logged_by = models.ForeignKey(User, verbose_name=_('logged by'),
                                  related_name='log_messages_by',
                                  help_text=_('Moderator who created the log'))

    class Meta:
        verbose_name = _('log entry')
        verbose_name_plural = _('log entries')

    def __str__(self):
        return '{}: {}'.format(self.get_msg_type_display(),
                               truncatewords(self.comment, 20))
connect/moderation/forms.py
class ReInviteMemberForm(forms.Form):
    """
    Form for moderators to reinvite new users.
    Asks moderator to confirm they have sent the email to the correct address.
    """
    def __init__(self, *args, **kwargs):
        self.logged_in_moderator = kwargs.pop('moderator', None)
        super(ReInviteMemberForm, self).__init__(*args, **kwargs)

    email = forms.EmailField(
        error_messages={
            'required': _('Please enter an email address.'),
            'invalid': _('Please enter a valid email address.')
        })

    user_id = forms.IntegerField(widget=forms.HiddenInput)

    def clean(self):
        """
        - Check that the user id is valid.

        - If the moderator changes the email, make sure the new
        email is not already in the system.
        """
        cleaned_data = super(ReInviteMemberForm, self).clean()
        email = cleaned_data.get('email')
        user_id = cleaned_data.get('user_id')

        user = get_object_or_404(User, id=user_id)

        if (user.moderator != self.logged_in_moderator or not user.is_invited_pending_activation()):
            raise Http404

        # If this email is not already registered to this user
        if email != user.email:
            validate_email_availability(email)

        return cleaned_data
connect/moderation/forms.py
class FilterLogsForm(forms.Form):
    """
    Form for a moderator to filter moderation logs by date, type and
    who the report has been logged against and logged by.
    """
    ALL = 'ALL'
    TODAY = 'TODAY'
    YESTERDAY = 'YESTERDAY'
    THIS_WEEK = 'THIS_WEEK'
    CUSTOM = 'CUSTOM'

    DATE_CHOICES = (
        (ALL, _('All')),
        (TODAY, _('Today')),
        (YESTERDAY, _('Yesterday')),
        (THIS_WEEK, _('This Week (Last 7 days)')),
        (CUSTOM, _('Custom Date Range')),
    )

    MSG_FILTER_CHOICES = ModerationLogMsg.MSG_TYPE_CHOICES
    MSG_FILTER_CHOICES.insert(0, (ALL, 'All'))

    msg_type = forms.ChoiceField(choices=MSG_FILTER_CHOICES,
                                 required=False)
    period = forms.ChoiceField(choices=DATE_CHOICES)

    start_date = forms.DateTimeField(
        required=False,
        initial=lambda: date.today().replace(
            year=date.today().year - 1),
        input_formats=('%d/%m/%Y',),
        widget=forms.DateInput(
            format='%d/%m/%Y',
            attrs={
                'class': 'start-date',
                'placeholder': _('Start Date'),
                # Disable by default (unless shown)
                'disabled': 'True',
            }))

    end_date = forms.DateTimeField(required=False,
                                   initial=date.today,
                                   input_formats=('%d/%m/%Y',),
                                   widget=forms.DateInput(
                                       format='%d/%m/%Y',
                                       attrs={
                                           'class': 'end-date',
                                           'placeholder': _('End Date'),
                                           # Disable by default (unless shown)
                                           'disabled': 'True',
                                       }))

    def clean(self):
        """
        If 'CUSTOM' is selected, check that both start_date and end_date
        have a value
        """
        cleaned_data = super(FilterLogsForm, self).clean()
        period = cleaned_data.get('period')

        if period == 'CUSTOM':

            start_date = cleaned_data.get('start_date')
            end_date = cleaned_data.get('end_date')

            if not start_date or not end_date:
                raise forms.ValidationError(
                    _('To filter by date, please provide a '
                      'start and end date.'),
                    code='missing_date')

        return cleaned_data
connect/accounts/models.py
class AbuseReport(models.Model):
    """
    Record an abuse report and a moderator's response.
    """
    DISMISS = 'DISMISS'
    WARN = 'WARN'
    BAN = 'BAN'

    ABUSE_REPORT_CHOICES = (
        (DISMISS, _('Dismiss Report')),
        (WARN, _('Warn User')),
        (BAN, _('Ban User')),
    )

    logged_against = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        verbose_name=_('logged against'),
        related_name='abuse_reports_about',
        help_text=_('User who is subject of abuse report'))

    logged_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        verbose_name=_('logged by'),
        related_name='abuse_reports_by',
        help_text=_('User who logged the abuse report'))

    logged_datetime = models.DateTimeField(_('date and time logged'),
                                           default=timezone.now)

    abuse_comment = models.TextField(_('abuse comment'),
                                     help_text=_('Content of abuse report'))

    moderator = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        related_name='abuse_reports_moderated_by',
        verbose_name=_('moderator'),
        blank=True,
        null=True,
        help_text=_('Moderator who has decided on report'))

    moderator_decision = models.CharField(_('moderator decision'),
                                          max_length=20,
                                          choices=ABUSE_REPORT_CHOICES,
                                          blank=True)

    moderator_comment = models.TextField(_('moderator comment'), blank=True)

    decision_datetime = models.DateTimeField(
        _('decision datetime'),
        blank=True, null=True,
        help_text=_('Time and date when moderator made a decision on the '
                    'report'))

    class Meta:
        verbose_name = _('abuse report')
        verbose_name_plural = _('abuse reports')

    def __str__(self):
        return 'Reported by {} against {}'.format(
            self.logged_by.get_full_name(),
            self.logged_against.get_full_name())
connect/moderation/forms.py
class InviteMemberForm(forms.Form):
    """
    Form for moderator to invite a new member.
    """
    full_name = forms.CharField(
        max_length=100,
        error_messages={
            'required': _('Please enter a full name.')
        })

    email = forms.EmailField(
        error_messages={
            'required': _('Please enter an email address.'),
            'invalid': _('Please enter a valid email address.')
        })

    def clean(self):
        """
        Make sure email is not already in the system.
        """
        cleaned_data = super(InviteMemberForm, self).clean()
        email = cleaned_data.get('email')
        validate_email_availability(email)

        return cleaned_data
connect/moderation/forms.py
class ReportAbuseForm(forms.Form):
    """
    Form for a user to report abusive bahaviour of another user.
    """
    comments = forms.CharField(
        widget=forms.Textarea(),
        error_messages={
            'required': _('Please describe your complaint.'),
        })
connect/moderation/forms.py
class ModerateAbuseForm(forms.Form):
    """
    Form for a moderator to:
    - Dismiss an abuse report
    - Issue a warning
    - Remove abuser
    """
    report_id = forms.IntegerField(widget=forms.HiddenInput)
    decision = forms.ChoiceField(choices=AbuseReport.ABUSE_REPORT_CHOICES,
                                 widget=forms.HiddenInput)
    comments = forms.CharField(
        widget=forms.Textarea(attrs={
            'placeholder': _('Please explain your decision. '
                             'This information will be sent to both users '
                             'and recorded in the moderation logs.'),
        }),
        error_messages={
            'required': _('Please explain your decision.'),
        })
connect/moderation/forms.py
class RevokeInvitationForm(forms.Form):
    """
    Form for moderator to revoke membership invitation.
    Requires moderator to confirm their action.
    """
    user_id = forms.IntegerField(widget=forms.HiddenInput)
    confirm = forms.BooleanField(error_messages={
        'required': _(
            'Please confirm that you wish to revoke this invitation.')
    })
connect/moderation/utils.py
def get_date_limits(start_date, end_date=None):
    """
    Return first and last UTC moments of given date(s),
    to the nearest microsecond.

    `start_date` and `end_date` must be aware datetime objects.

    If only one date is specified, the first and last moments of this date
    will be returned.
    """
    if not end_date:
        end_date = start_date

    start_date_tz = start_date.tzinfo
    end_date_tz = end_date.tzinfo

    start = datetime.datetime.combine(start_date, datetime.time.min)
    start_local = timezone.make_aware(start, start_date_tz)
    start_utc = start_local.astimezone(pytz.UTC)

    end = datetime.datetime.combine(end_date, datetime.time.max)
    end_local = timezone.make_aware(end, end_date_tz)
    end_utc = end_local.astimezone(pytz.UTC)

    return (start_utc, end_utc)
connect/moderation/utils.py
def log_moderator_event(msg_type, user, moderator, comment=''):
    """
    Log a moderation event.
    """
    message = ModerationLogMsg.objects.create(
        msg_type=msg_type,
        comment=comment,
        pertains_to=user,
        logged_by=moderator,
    )

    return message
connect/moderation/forms.py
class ModerateApplicationForm(forms.Form):
    """
    Form for moderators to approve or reject an account application.
    """
    user_id = forms.IntegerField(widget=forms.HiddenInput)
    decision = forms.ChoiceField(choices=User.MODERATOR_CHOICES[1:],
                                 widget=forms.HiddenInput)
    comments = forms.CharField(
        widget=forms.Textarea(attrs={
            'placeholder': _('Please explain your decision. '
                             'This information will not be sent to the user, '
                             'but will be recorded in the moderation logs.'),
        }), error_messages={
            'required': _('Please explain your decision.'),
        })


Question: from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone
from django.utils.translation import ugettext as _
from django.views.decorators.http import require_POST
from connect.accounts.models import AbuseReport
from connect.utils import send_connect_email
from connect.moderation.forms import (
    FilterLogsForm, InviteMemberForm, ModerateApplicationForm,
    ModerateAbuseForm, ReInviteMemberForm,
    ReportAbuseForm, RevokeInvitationForm
)
from connect.moderation.models import ModerationLogMsg
from connect.moderation.utils import get_date_limits, log_moderator_event
    revocation_form = RevokeInvitationForm(request.POST)

    if revocation_form.is_valid():

        user_id = revocation_form.cleaned_data['user_id']
        user = get_object_or_404(User, id=user_id)

        if user.is_invited_pending_activation \
           and user.moderator == request.user:
            messages.success(request, _(
                '{} has been uninvited from {}.'.format(
                    user.get_full_name(), site.name)))

            # Delete the user rather than deactivate it.
            # Removing the email address from the system altogether means
            # that the same email can later be used to create a new account
            # (e.g. if the user applies or is invited by another moderator).
            # Logs related to this user are also removed,
            # resulting in less junk to filter in that view.
            user.delete()
        else:
            raise PermissionDenied

        return redirect('moderation:moderators')

    else:
        return moderation_home(request, revocation_form=revocation_form)


@login_required
@permission_required(['accounts.access_moderators_section',
                      'accounts.approve_user_application',
                      'accounts.reject_user_application'])
def review_applications(request):
    """
    Review all pending applications.
    """
    moderator = request.user
    site = get_current_site(request)

    pending = User.objects.filter(registration_method='REQ',
                                  decision_datetime=None,
                                  is_active=False)

    form = ModerateApplicationForm()

    if request.method == 'POST':

        form = ModerateApplicationForm(request.POST)
        user = get_object_or_404(User, id=request.POST['user_id'])

        if form.is_valid():
            decision = form.cleaned_data['decision']
            comments = form.cleaned_data['comments']

            if decision == 'APP':
                confirmation_message = _("{}'s account application "
                                         "has been approved.".format(
                                             user.get_full_name().title()))

                moderator.approve_user_application(user)

                # Set log and email settings
                msg_type = ModerationLogMsg.APPROVAL
                url = request.build_absolute_uri(
                    reverse('accounts:activate-account',
                            args=[user.auth_token]))
                subject = _('Welcome to {}'.format(site.name))
                template = 'moderation/emails/approve_user.html'

            elif decision == 'REJ':
                confirmation_message = _("{}'s account application "
                                         "has been rejected.".format(
                                             user.get_full_name().title()))

                moderator.reject_user_application(user)

                # Set log and email settings
                msg_type = ModerationLogMsg.REJECTION
                url = ''
                subject = _(('Unfortunately, your application to {} '
                             'was not successful').format(site.name))
                template = 'moderation/emails/reject_user.html'

            # Log moderation event
            log_comment = '{}'.format(comments)
            log_moderator_event(msg_type=msg_type,
                                user=user,
                                moderator=moderator,
                                comment=log_comment)

            # Send moderation email
            send_connect_email(subject=subject,
                               template=template,
                               recipient=user,
                               sender=moderator,
                               site=site,
                               url=url)

            messages.success(request, confirmation_message)

            return redirect('moderation:review-applications')

    context = {
        'pending': pending,
        'form': form,
    }

    return render(request, 'moderation/review_applications.html', context)


@login_required
def report_abuse(request, user_id):
    """
    Allow any user to report another user for abusive behaviour.
    """
    logged_against = get_object_or_404(User, id=user_id)
    logged_by = request.user

    if request.POST:

Answer:         form = ReportAbuseForm(request.POST)