codeforamerica/intake

View on GitHub
intake/views/base_views.py

Summary

Maintainability
A
1 hr
Test Coverage
from django.shortcuts import redirect
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.urls import reverse
from django.contrib import messages
from project import alerts
from project.services import query_params
from project.exceptions import InvalidQueryParamsError
from intake import permissions
from intake.models import County
from user_accounts.models import Organization


class GlobalTemplateContextMixin:

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)
        context.update(
            counties=County.objects.get_county_choices_query()
        )
        return context


class ViewAppDetailsMixin(PermissionRequiredMixin):
    permission_required = 'intake.' + permissions.CAN_SEE_APP_DETAILS

    def handle_no_permission(self):
        return not_allowed(self.request)


class NoBrowserCacheOnGetMixin:
    """Sets the 'Cache-Control' response header to
        'no-cache, max-age=0, must-revalidate, no-store'
    on GET requests.

    This is useful if you would like the browser to refetch
    the page when a user navigates to it using the Back button.
    """
    def get(self, *args, **kwargs):
        response = super().get(*args, **kwargs)
        response['Cache-Control'] = \
            'no-cache, max-age=0, must-revalidate, no-store'
        return response


class AppIDQueryParamMixin:
    """
    A base view for ApplicationsListViews that retrieve resources using a list
    of Application IDs in query params.
        /some_url?ids=12,43,23,54,43
    """
    def request_valid(self, request, *args, **kwargs):
        return super().get(request, *args, **kwargs)

    def handle_empty_list_request(self, request, *args, **kwargs):
        redirect_url = reverse('intake-app_index')
        alert_subject = \
            'Warning: "{}" ({}) accessed with no application IDs'.format(
                request.get_full_path(), self.__class__.__name__)
        alert_message = '{} <{}> was redirected to "{}"'.format(
            request.user.profile.name, request.user.email, redirect_url)
        alerts.send_email_to_admins(
            subject=alert_subject, message=alert_message)
        return redirect(reverse('intake-app_index'))

    def get(self, request, *args, **kwargs):
        try:
            self.app_ids = query_params.get_ids_from_query_params(request)
        except InvalidQueryParamsError as err:
            return not_allowed(request)
        self.request = request
        self.profile = request.user.profile
        linked_organizations = list(Organization.objects.filter(
            applications__id__in=self.app_ids).distinct())
        if len(linked_organizations) != 1:
            return not_allowed(request)
        self.organization = linked_organizations[0]
        has_access = request.user.is_staff or (
            self.profile.organization == self.organization)
        if not has_access:
            return not_allowed(request)
        else:
            if not self.app_ids:
                return self.handle_empty_list_request(request, *args, **kwargs)
            return self.request_valid(request, *args, **kwargs)


NOT_ALLOWED_MESSAGE = str(
    "Sorry, there was something wrong with that link. "
    "If you have any questions, please contact us at "
    "clearmyrecord@codeforamerica.org")

NOT_ALLOWED_ADMIN_ALERT_MESSAGE = str(
    "{user_email} attempted to access {url}, "
    "which they are not currently permitted to view. "
    "They were redirected to '{redirect_view}' and given the "
    "error message:\n\n{flash_message}\n\n"
    "Additional Error Info:\n{error_messages}")


def not_allowed(
        request, redirect_view='user_accounts-profile', error_messages='None'):
    messages.error(request, NOT_ALLOWED_MESSAGE)
    alerts.send_email_to_admins(
        subject="A user attempted to access an unpermitted URL",
        message=NOT_ALLOWED_ADMIN_ALERT_MESSAGE.format(
            user_email=getattr(request.user, 'email', 'No email'),
            url=request.get_full_path(),
            redirect_view=redirect_view,
            flash_message=NOT_ALLOWED_MESSAGE,
            error_messages=error_messages))
    return redirect(redirect_view)