Skip to content

Commit

Permalink
Merge pull request #4663 from GSA-TTS/main
Browse files Browse the repository at this point in the history
  • Loading branch information
asteel-gsa authored Jan 25, 2025
2 parents 62769b7 + 32d112e commit 0bcebcb
Show file tree
Hide file tree
Showing 23 changed files with 192 additions and 146 deletions.
10 changes: 10 additions & 0 deletions backend/audit/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class SessionExpiredException(Exception):
def __init__(self, message="Your session has expired. Please log in again."):
self.message = message
super().__init__(self.message)


class SessionWarningException(Exception):
def __init__(self, message="Your session is about to expire."):
self.message = message
super().__init__(self.message)
13 changes: 7 additions & 6 deletions backend/audit/mixins.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from typing import Any

from audit.exceptions import SessionExpiredException
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied
from django.http.request import HttpRequest
from django.http.response import HttpResponse
from django.core.exceptions import PermissionDenied
from django.conf import settings

from .models import Access, SingleAuditChecklist

Expand All @@ -22,12 +24,10 @@ def __init__(self, message, eligible_users):


def check_authenticated(request):
if not hasattr(request, "user"):
raise PermissionDenied(PERMISSION_DENIED_MESSAGE)
if not request.user:
if not hasattr(request, "user") or not request.user:
raise PermissionDenied(PERMISSION_DENIED_MESSAGE)
if not request.user.is_authenticated:
raise PermissionDenied(PERMISSION_DENIED_MESSAGE)
raise SessionExpiredException()


def has_access(sac, user):
Expand Down Expand Up @@ -100,6 +100,7 @@ class CertifyingAuditorRequiredMixin(LoginRequiredMixin):
def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
role = "certifying_auditor_contact"
try:

check_authenticated(request)

sac = SingleAuditChecklist.objects.get(report_id=kwargs["report_id"])
Expand Down
6 changes: 4 additions & 2 deletions backend/audit/test_manage_submission_access_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ def test_login_required(self):
)
)

self.assertEqual(response.status_code, 403)
self.assertTemplateUsed(response, "home.html")
self.assertTrue(response.context["session_expired"])

def test_bad_report_id_returns_403(self):
"""
Expand Down Expand Up @@ -267,7 +268,8 @@ def test_login_required(self):
)
)

self.assertEqual(response.status_code, 403)
self.assertTemplateUsed(response, "home.html")
self.assertTrue(response.context["session_expired"])

def test_bad_report_id_returns_403(self):
"""
Expand Down
3 changes: 2 additions & 1 deletion backend/audit/test_manage_submission_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ def test_login_required(self):
)
)

self.assertEqual(response.status_code, 403)
self.assertTemplateUsed(response, "home.html")
self.assertTrue(response.context["session_expired"])

def test_bad_report_id_returns_403(self):
"""
Expand Down
7 changes: 4 additions & 3 deletions backend/audit/test_mixins.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from audit.exceptions import SessionExpiredException
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import PermissionDenied
Expand Down Expand Up @@ -56,7 +57,7 @@ def test_anonymous_raises(self):

view = self.ViewStub()
self.assertRaises(
PermissionDenied, view.dispatch, request, report_id="not-logged-in"
SessionExpiredException, view.dispatch, request, report_id="not-logged-in"
)

def test_no_access_raises(self):
Expand Down Expand Up @@ -122,7 +123,7 @@ def test_anonymous_raises(self):

view = self.ViewStub()
self.assertRaises(
PermissionDenied, view.dispatch, request, report_id="not-logged-in"
SessionExpiredException, view.dispatch, request, report_id="not-logged-in"
)

def test_no_access_raises(self):
Expand Down Expand Up @@ -217,7 +218,7 @@ def test_anonymous_raises(self):

view = self.ViewStub()
self.assertRaises(
PermissionDenied, view.dispatch, request, report_id="not-logged-in"
SessionExpiredException, view.dispatch, request, report_id="not-logged-in"
)

def test_no_access_raises(self):
Expand Down
3 changes: 2 additions & 1 deletion backend/audit/test_submission_progress_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ def test_login_required(self):
)
)

self.assertEqual(response.status_code, 403)
self.assertTemplateUsed(response, "home.html")
self.assertTrue(response.context["session_expired"])

def test_phrase_in_page(self):
"""Check for 'General Information form'."""
Expand Down
12 changes: 8 additions & 4 deletions backend/audit/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@ def test_get_access_denied_for_unauthorized_user(self):
"""Test that GET returns 403 if user is unauthorized"""
self.client.logout()
response = self.client.get(self.url)
self.assertEqual(response.status_code, 403)
self.assertTemplateUsed(response, "home.html")
self.assertTrue(response.context["session_expired"])

@patch("audit.models.SingleAuditChecklist.validate_full")
@patch("audit.views.views.sac_transition")
Expand Down Expand Up @@ -888,7 +889,8 @@ def test_login_required(self):
)
)

self.assertEqual(response.status_code, 403)
self.assertTemplateUsed(response, "home.html")
self.assertTrue(response.context["session_expired"])

def test_bad_report_id_returns_403(self):
"""When a request is made for a malformed or nonexistent report_id, a 403 error should be returned"""
Expand Down Expand Up @@ -1525,7 +1527,8 @@ def test_get_login_required(self):
kwargs={"report_id": "12345", "form_section": form_section},
)
)
self.assertEqual(response.status_code, 403)
self.assertTemplateUsed(response, "home.html")
self.assertTrue(response.context["session_expired"])

def test_get_bad_report_id_returns_403(self):
"""Test that uploading with a malformed or nonexistant report_id reutrns 403"""
Expand Down Expand Up @@ -1556,7 +1559,8 @@ def test_login_required(self):
)
)

self.assertEqual(response.status_code, 403)
self.assertTemplateUsed(response, "home.html")
self.assertTrue(response.context["session_expired"])

def test_bad_report_id_returns_403(self):
"""When a request is made for a malformed or nonexistent report_id, a 403 error should be returned"""
Expand Down
3 changes: 2 additions & 1 deletion backend/config/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from config import settings
from datetime import datetime, timezone

from config import settings


def static_site_url(request):
"""
Expand Down
23 changes: 21 additions & 2 deletions backend/config/middleware.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import boto3
from audit.exceptions import SessionExpiredException, SessionWarningException
from dissemination.file_downloads import file_exists
from django.conf import settings
from django.shortcuts import redirect
import boto3
from django.shortcuts import redirect, render

LOCAL_FILENAME = "./runtime/MAINTENANCE_MODE"
S3_FILENAME = "runtime/MAINTENANCE_MODE"
Expand Down Expand Up @@ -77,3 +78,21 @@ def __call__(self, request):

response = self.get_response(request)
return response


class HandleSessionException:
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
response = self.get_response(request)
return response

def process_exception(self, request, exception):
if isinstance(exception, SessionExpiredException):
context = {"session_expired": True}
return render(request, "home.html", context)
elif isinstance(exception, SessionWarningException):
context = {"show_session_warning_banner": True}
return render(request, "home.html", context)
return None
19 changes: 11 additions & 8 deletions backend/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@
https://docs.djangoproject.com/en/4.0/ref/settings/
"""

from base64 import b64decode
from datetime import datetime, timezone
import json
import logging
import os
import sys
import logging
import json
from .db_url import get_db_url_from_vcap_services
import environs
from cfenv import AppEnv
from audit.get_agency_names import get_agency_names, get_audit_info_lists
from base64 import b64decode
from datetime import datetime, timezone

import dj_database_url
import environs
import newrelic.agent
from audit.get_agency_names import get_agency_names, get_audit_info_lists
from cfenv import AppEnv

from .db_url import get_db_url_from_vcap_services

newrelic.agent.initialize()

Expand Down Expand Up @@ -141,6 +143,7 @@
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"config.middleware.HandleSessionException",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"config.middleware.MaintenanceCheck",
Expand Down
5 changes: 0 additions & 5 deletions backend/dissemination/api/api_historic_v0_1_0_alpha/base.sql

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

49 changes: 0 additions & 49 deletions backend/dissemination/api/api_historic_v0_1_0_alpha/views.py

This file was deleted.

15 changes: 15 additions & 0 deletions backend/static/js/session-expired-modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
document.addEventListener("DOMContentLoaded", function () {

const modalTrigger = document.createElement("a");
modalTrigger.setAttribute("href", `#session-expired-modal`);
modalTrigger.setAttribute("data-open-modal", "");
modalTrigger.setAttribute("aria-controls", 'session-expired-modal');
modalTrigger.setAttribute("role", "button");
modalTrigger.className = "sign-in display-flex flex-row";
document.body.appendChild(modalTrigger);

setTimeout(() => {
modalTrigger.click();
modalTrigger.remove();
}, 100);
});
14 changes: 14 additions & 0 deletions backend/static/js/session-warning-modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
document.addEventListener("DOMContentLoaded", function () {
const modalTrigger = document.createElement("a");
modalTrigger.setAttribute("href", `#session-warning-modal`);
modalTrigger.setAttribute("data-open-modal", "");
modalTrigger.setAttribute("aria-controls", 'session-warning-modal');
modalTrigger.setAttribute("role", "button");
modalTrigger.className = "sign-in display-flex flex-row";
document.body.appendChild(modalTrigger);

setTimeout(() => {
modalTrigger.click();
modalTrigger.remove();
}, 100);
});
Loading

0 comments on commit 0bcebcb

Please sign in to comment.