Skip to content

Commit

Permalink
Merge pull request #2787 from GSA-TTS/main
Browse files Browse the repository at this point in the history
  • Loading branch information
jadudm authored Nov 10, 2023
2 parents b2319ff + 5a8ec7f commit af86e78
Show file tree
Hide file tree
Showing 22 changed files with 267 additions and 173 deletions.
10 changes: 5 additions & 5 deletions backend/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def access_and_submission_check(user, data):
Access.objects.create(
sac=sac,
role="editor",
email=user.email,
email=str(user.email).lower(),
user=user,
event_user=user,
event_type=SubmissionEvent.EventType.ACCESS_GRANTED,
Expand All @@ -132,15 +132,15 @@ def access_and_submission_check(user, data):
sac=sac,
role="certifying_auditee_contact",
fullname=serializer.data.get("certifying_auditee_contact_fullname"),
email=serializer.data.get("certifying_auditee_contact_email"),
email=serializer.data.get("certifying_auditee_contact_email").lower(),
event_user=user,
event_type=SubmissionEvent.EventType.ACCESS_GRANTED,
)
Access.objects.create(
sac=sac,
role="certifying_auditor_contact",
fullname=serializer.data.get("certifying_auditor_contact_fullname"),
email=serializer.data.get("certifying_auditor_contact_email"),
email=serializer.data.get("certifying_auditor_contact_email").lower(),
event_user=user,
event_type=SubmissionEvent.EventType.ACCESS_GRANTED,
)
Expand All @@ -160,7 +160,7 @@ def access_and_submission_check(user, data):
sac=sac,
role="editor",
fullname=name,
email=email,
email=str(email).lower(),
event_user=user,
event_type=SubmissionEvent.EventType.ACCESS_GRANTED,
)
Expand All @@ -169,7 +169,7 @@ def access_and_submission_check(user, data):
sac=sac,
role="editor",
fullname=name,
email=email,
email=str(email).lower(),
event_user=user,
event_type=SubmissionEvent.EventType.ACCESS_GRANTED,
)
Expand Down
1 change: 1 addition & 0 deletions backend/audit/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class AccessAdmin(admin.ModelAdmin):

list_display = ("sac", "role", "email")
list_filter = ["role"]
readonly_fields = ("sac",)


class ExcelFileAdmin(admin.ModelAdmin):
Expand Down
8 changes: 0 additions & 8 deletions backend/audit/modellib/__init__.py

This file was deleted.

32 changes: 32 additions & 0 deletions backend/audit/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from .access import Access
from .models import (
ExcelFile,
GeneralInformationMixin,
LateChangeError,
SingleAuditChecklist,
SingleAuditChecklistManager,
SingleAuditReportFile,
User,
excel_file_path,
generate_sac_report_id,
single_audit_report_path,
)
from .submission_event import SubmissionEvent

# In case we want to iterate through all the models for some reason:
_models = [
Access,
ExcelFile,
GeneralInformationMixin,
SubmissionEvent,
LateChangeError,
SingleAuditChecklist,
SingleAuditChecklistManager,
SingleAuditReportFile,
User,
]
_functions = [
excel_file_path,
generate_sac_report_id,
single_audit_report_path,
]
97 changes: 97 additions & 0 deletions backend/audit/models/access.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from django.contrib.auth import get_user_model
from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from .models import (
SingleAuditChecklist,
SubmissionEvent,
)


User = get_user_model()


class AccessManager(models.Manager):
"""Custom manager for Access."""

def create(self, **obj_data):
"""
Check for existing users and add them at access creation time.
Not doing this would mean that users logged in at time of Access
instance creation would have to log out and in again to get the new
access.
"""

# remove event_user & event_type keys so that they're not passed into super().create below
event_user = obj_data.pop("event_user", None)
event_type = obj_data.pop("event_type", None)

if obj_data["email"]:
try:
acc_user = User.objects.get(email=obj_data["email"])
except User.DoesNotExist:
acc_user = None
if acc_user:
obj_data["user"] = acc_user
result = super().create(**obj_data)

if event_user and event_type:
SubmissionEvent.objects.create(
sac=result.sac,
user=event_user,
event=event_type,
)

return result


class Access(models.Model):
"""
Email addresses which have been granted access to SAC instances.
An email address may be associated with a User ID if an FAC account exists.
"""

objects = AccessManager()

ROLES = (
("certifying_auditee_contact", _("Auditee Certifying Official")),
("certifying_auditor_contact", _("Auditor Certifying Official")),
("editor", _("Audit Editor")),
)
sac = models.ForeignKey(SingleAuditChecklist, on_delete=models.CASCADE)
role = models.CharField(
choices=ROLES,
help_text="Access type granted to this user",
max_length=50,
)
fullname = models.CharField(blank=True)
email = models.EmailField()
user = models.ForeignKey(
User,
null=True,
help_text="User ID associated with this email address, empty if no FAC account exists",
on_delete=models.PROTECT,
)

def __str__(self):
return f"{self.email} as {self.get_role_display()}"

class Meta:
"""Constraints for certifying roles"""

verbose_name_plural = "accesses"

constraints = [
# a SAC cannot have multiple certifying auditees
models.UniqueConstraint(
fields=["sac"],
condition=Q(role="certifying_auditee_contact"),
name="%(app_label)s_$(class)s_single_certifying_auditee",
),
# a SAC cannot have multiple certifying auditors
models.UniqueConstraint(
fields=["sac"],
condition=Q(role="certifying_auditor_contact"),
name="%(app_label)s_%(class)s_single_certifying_auditor",
),
]
95 changes: 7 additions & 88 deletions backend/audit/models.py → backend/audit/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import logging

from django.db import models
from django.db.models import Q
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.postgres.fields import ArrayField
Expand All @@ -15,7 +14,6 @@

import audit.cross_validation
from audit.intake_to_dissemination import IntakeToDissemination
from audit.modellib import SubmissionEvent
from audit.validators import (
validate_additional_ueis_json,
validate_additional_eins_json,
Expand All @@ -35,6 +33,7 @@
validate_component_page_numbers,
)
from support.cog_over import compute_cog_over, record_cog_assignment
from .submission_event import SubmissionEvent

User = get_user_model()

Expand Down Expand Up @@ -147,7 +146,10 @@ def inner(self):


class LateChangeError(Exception):
pass
"""
Exception covering attempts to change submissions that don't have the in_progress
status.
"""


class SingleAuditChecklist(models.Model, GeneralInformationMixin): # type: ignore
Expand Down Expand Up @@ -586,90 +588,6 @@ def get_transition_date(self, status):
return None


class AccessManager(models.Manager):
"""Custom manager for Access."""

def create(self, **obj_data):
"""
Check for existing users and add them at access creation time.
Not doing this would mean that users logged in at time of Access
instance creation would have to log out and in again to get the new
access.
"""

# remove event_user & event_type keys so that they're not passed into super().create below
event_user = obj_data.pop("event_user", None)
event_type = obj_data.pop("event_type", None)

if obj_data["email"]:
try:
acc_user = User.objects.get(email=obj_data["email"])
except User.DoesNotExist:
acc_user = None
if acc_user:
obj_data["user"] = acc_user
result = super().create(**obj_data)

if event_user and event_type:
SubmissionEvent.objects.create(
sac=result.sac,
user=event_user,
event=event_type,
)

return result


class Access(models.Model):
"""
Email addresses which have been granted access to SAC instances.
An email address may be associated with a User ID if an FAC account exists.
"""

objects = AccessManager()

ROLES = (
("certifying_auditee_contact", _("Auditee Certifying Official")),
("certifying_auditor_contact", _("Auditor Certifying Official")),
("editor", _("Audit Editor")),
)
sac = models.ForeignKey(SingleAuditChecklist, on_delete=models.CASCADE)
role = models.CharField(
choices=ROLES,
help_text="Access type granted to this user",
max_length=50,
)
fullname = models.CharField(blank=True)
email = models.EmailField()
user = models.ForeignKey(
User,
null=True,
help_text="User ID associated with this email address, empty if no FAC account exists",
on_delete=models.PROTECT,
)

def __str__(self):
return f"{self.email} as {self.get_role_display()}"

class Meta:
verbose_name_plural = "accesses"

constraints = [
# a SAC cannot have multiple certifying auditees
models.UniqueConstraint(
fields=["sac"],
condition=Q(role="certifying_auditee_contact"),
name="%(app_label)s_$(class)s_single_certifying_auditee",
),
# a SAC cannot have multiple certifying auditors
models.UniqueConstraint(
fields=["sac"],
condition=Q(role="certifying_auditor_contact"),
name="%(app_label)s_%(class)s_single_certifying_auditor",
),
]


def excel_file_path(instance, _filename):
"""
We want the actual filename in the filesystem to be unique and determined
Expand Down Expand Up @@ -719,7 +637,8 @@ def single_audit_report_path(instance, _filename):

class SingleAuditReportFile(models.Model):
"""
Data model to track uploaded Single Audit report PDFs and associate them with SingleAuditChecklists
Data model to track uploaded Single Audit report PDFs and associate them
with SingleAuditChecklists
"""

file = models.FileField(
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,6 @@
# before filling in the XLSX workbooks.
FieldMap = NT("FieldMap", "in_sheet in_db default type")

templates = {
"AdditionalUEIs": "additional-ueis-workbook.xlsx",
"AdditionalEINs": "additional-eins-workbook.xlsx",
"AuditFindingsText": "audit-findings-text-workbook.xlsx",
"CAP": "corrective-action-plan-workbook.xlsx",
"AuditFindings": "federal-awards-audit-findings-workbook.xlsx",
"FederalAwards": "federal-awards-workbook.xlsx",
"SEFA": "notes-to-sefa-workbook.xlsx",
"SecondaryAuditors": "secondary-auditors-workbook.xlsx",
}


def set_single_cell_range(wb, range_name, value):
the_range = wb.defined_names[range_name]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
from census_historical_migration.workbooklib.excel_creation import (
FieldMap,
WorkbookFieldInDissem,
templates,
set_uei,
map_simple_columns,
generate_dissemination_test_table,
)


from census_historical_migration.workbooklib.templates import sections_to_template_paths
from census_historical_migration.workbooklib.census_models.census import dynamic_import
from audit.fixtures.excel import FORM_SECTIONS

import openpyxl as pyxl

Expand All @@ -25,7 +24,7 @@ def generate_additional_eins(dbkey, year, outfile):
logger.info(f"--- generate additional eins {dbkey} {year} ---")
Gen = dynamic_import("Gen", year)
Eins = dynamic_import("Eins", year)
wb = pyxl.load_workbook(templates["AdditionalEINs"])
wb = pyxl.load_workbook(sections_to_template_paths[FORM_SECTIONS.ADDITIONAL_EINS])

g = set_uei(Gen, wb, dbkey)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
from census_historical_migration.workbooklib.excel_creation import (
FieldMap,
WorkbookFieldInDissem,
templates,
set_uei,
map_simple_columns,
generate_dissemination_test_table,
)


from census_historical_migration.workbooklib.templates import sections_to_template_paths
from census_historical_migration.workbooklib.census_models.census import dynamic_import
from audit.fixtures.excel import FORM_SECTIONS

import openpyxl as pyxl

Expand All @@ -25,7 +24,7 @@
def generate_additional_ueis(dbkey, year, outfile):
logger.info(f"--- generate additional ueis {dbkey} {year} ---")
Gen = dynamic_import("Gen", year)
wb = pyxl.load_workbook(templates["AdditionalUEIs"])
wb = pyxl.load_workbook(sections_to_template_paths[FORM_SECTIONS.ADDITIONAL_UEIS])
g = set_uei(Gen, wb, dbkey)
if int(year) >= 22:
Ueis = dynamic_import("Ueis", year)
Expand Down
Loading

0 comments on commit af86e78

Please sign in to comment.