codeforamerica/intake

View on GitHub
intake/views/app_edit_view.py

Summary

Maintainability
A
25 mins
Test Coverage
from django.views.generic.edit import UpdateView
from django.http import HttpResponseRedirect
from django.contrib.auth.models import User
from intake.models import FormSubmission
from django.utils import safestring
from intake.services.edit_form_service import (
    get_edit_form_class_for_user_and_submission,
    SENSITIVE_FIELD_LABELS,
    get_changed_data_from_form
)
from intake.notifications import app_edited_org_email_notification, \
    app_edited_applicant_email_notification, \
    app_edited_applicant_sms_notification
from intake.services.submissions import update_submission_answers
from intake.services.messages_service import flash_success


def remove_sensitive_data_from_data_diff(unsafe_data_diff):
    """Removes 'before' and 'after' data for fields that are sensitive, such
    as social security number and driver's license number
    """
    safe_data_diff = {}
    unsafe_changed_keys = []
    for label, values in unsafe_data_diff.items():
        if label not in SENSITIVE_FIELD_LABELS:
            safe_data_diff[label] = values
        else:
            unsafe_changed_keys.append(label)
    return safe_data_diff, unsafe_changed_keys


def get_emails_to_notify_of_edits(form_submission_id):
    return User.objects.filter(
            profile__should_get_notifications=True,
            profile__organization__submissions__id=form_submission_id
        ).values_list('email', flat=True)


class AppEditView(UpdateView):
    model = FormSubmission
    template_name = "app_edit.jinja"
    pk_url_kwarg = 'submission_id'
    context_object_name = 'submission'

    def get_success_url(self):
        return self.submission.get_absolute_url()

    def get_object(self, queryset=None):
        obj = super().get_object(queryset=queryset)
        self.submission = obj
        return obj

    def get_form_class(self):
        return get_edit_form_class_for_user_and_submission(
            self.request.user, self.submission)

    def get_form_kwargs(self):
        if self.request.method in ('POST', 'PUT'):
            kwargs = {
                'data': self.request.POST}
        else:
            kwargs = {
                'data': self.submission.answers,
                'validate': True}
        return kwargs

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        existing_data_form = context['form'].__class__(
            self.submission.answers, validate=True)
        context['existing_data_form'] = existing_data_form
        return context

    def get_queryset(self):
        if self.request.user.is_staff:
            return self.model.objects.all()

        return self.model.objects.filter(
            organizations__profiles__user=self.request.user)

    def form_valid(self, form):
        unsafe_data_diff = get_changed_data_from_form(form)
        if unsafe_data_diff:
            update_submission_answers(self.submission, form.cleaned_data)
            flash_success(
                self.request,
                'Saved new information for {}'.format(
                    self.submission.get_full_name()))

            self.notify_org(unsafe_data_diff)
            self.notify_applicant(unsafe_data_diff)
        return HttpResponseRedirect(self.get_success_url())

    def notify_org(self, unsafe_data_diff):
        safe_data_diff, unsafe_diff_keys = \
            remove_sensitive_data_from_data_diff(unsafe_data_diff)
        notifiable_emails = get_emails_to_notify_of_edits(
            self.submission.id)
        org_name = self.request.user.profile.organization.name
        for to_email in notifiable_emails:
            app_edited_org_email_notification.send(
                to=[to_email],
                sender_profile=self.request.user.profile,
                editor_email=self.request.user.email,
                editor_org_name=safestring.mark_safe(org_name),
                app_detail_url=self.submission.get_external_url(),
                submission_id=self.submission.id,
                applicant_name=self.submission.get_full_name(),
                safe_data_diff=safe_data_diff,
                unsafe_changed_keys=unsafe_diff_keys)

    def notify_applicant(self, unsafe_data_diff):
        profile = self.request.user.profile
        org = profile.organization
        name = safestring.mark_safe('the ' + org.name if org.slug != 'cfa' else org.name)
        contact_info = safestring.mark_safe(org.get_contact_info_message())
        changed_fields = sorted(list(unsafe_data_diff.keys()))

        if self.submission.email:
            app_edited_applicant_email_notification.send(
                to=[self.submission.email],
                sender_profile=profile,
                org_contact_info=contact_info,
                org_name=name,
                changed_fields=changed_fields,
                is_old_contact_info=False
            )

        if self.submission.phone_number:
            app_edited_applicant_sms_notification.send(
                to=[self.submission.phone_number],
                org_contact_info=contact_info,
                org_name=name,
                changed_fields=changed_fields,
                is_old_contact_info=False
            )

        if 'Email' in unsafe_data_diff and unsafe_data_diff['Email']['before']:
            app_edited_applicant_email_notification.send(
                to=[unsafe_data_diff['Email']['before']],
                sender_profile=profile,
                org_contact_info=org.get_contact_info_message(),
                org_name=name,
                changed_fields=changed_fields,
                is_old_contact_info=True
            )

        if 'Phone number' in unsafe_data_diff and (
                unsafe_data_diff['Phone number']['before']):
            app_edited_applicant_sms_notification.send(
                to=[unsafe_data_diff['Phone number']['before']],
                org_contact_info=org.get_contact_info_message(),
                org_name=name,
                changed_fields=changed_fields,
                is_old_contact_info=True
            )


app_edit = AppEditView.as_view()