Skip to content

Commit

Permalink
Merge branch 'develop' into 3243-promtail-pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
ADPennington authored Dec 18, 2024
2 parents 476c4d7 + 62fde87 commit c129e03
Show file tree
Hide file tree
Showing 19 changed files with 386 additions and 29 deletions.
5 changes: 2 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ compliance/opencontrols/
compliance/exports/
tdrs-backend/tdpservice/static/*
*gunicorn.log
*.log

# don't ignore requirements.txt
!requirements.txt
Expand Down Expand Up @@ -115,6 +116,4 @@ cypress.env.json

# DB seeds
tdrs-backend/*.pg

# Log files
*.log
tdrs-backend/django.log
2 changes: 1 addition & 1 deletion tdrs-backend/tdpservice/data_files/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def get_has_error(self, obj):

def get_latest_reparse_file_meta(self, instance):
"""Return related reparse_file_metas, ordered by finished_at decending."""
reparse_file_metas = instance.reparse_file_metas.all().order_by('-finished_at')
reparse_file_metas = instance.reparse_file_metas.all().exclude(finished_at=None).order_by('-finished_at')
if reparse_file_metas.count() > 0:
return ReparseFileMetaSerializer(reparse_file_metas.first(), many=False, read_only=True).data
return None
Expand Down
1 change: 1 addition & 0 deletions tdrs-backend/tdpservice/email/email_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ class EmailType(Enum):
ACCOUNT_DEACTIVATED_ADMIN = 'account-deactivated-admin.html'
UPCOMING_SUBMISSION_DEADLINE = 'upcoming-submission-deadline.html'
STUCK_FILE_LIST = 'stuck-file-list.html'
SYSTEM_ADMIN_ROLE_CHANGED = 'system-admin-role-changed.html'
47 changes: 44 additions & 3 deletions tdrs-backend/tdpservice/email/helpers/admin_notifications.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""helper functions to administer user accounts."""
from tdpservice.users.models import User
from tdpservice.email.email_enums import EmailType
from tdpservice.email.email import automated_email, log

def email_admin_deactivated_user(user):
"""Send an email to OFA Admins when a user is deactivated."""
from tdpservice.users.models import User
from tdpservice.email.email_enums import EmailType
from tdpservice.email.email import automated_email, log
from tdpservice.email.tasks import get_ofa_admin_user_emails

recipient_emails = get_ofa_admin_user_emails()
Expand Down Expand Up @@ -33,3 +33,44 @@ def email_admin_deactivated_user(user):
text_message=text_message,
logger_context=logger_context
)

def email_system_owner_system_admin_role_change(user, action):
"""Send an email to the System Owner when a user is assigned or removed from the System Admin role."""
from tdpservice.email.tasks import get_system_owner_email
recipient_email = get_system_owner_email()
logger_context = {
'user_id': user.id,
'object_id': user.id,
'object_repr': user.username,
'content_type': User,
}

template_path = EmailType.SYSTEM_ADMIN_ROLE_CHANGED.value

if action == 'added':
text_message = 'A user has been assigned to OFA System Admin role.'
elif action == 'is_staff_assigned':
text_message = 'A user has been assigned to staff role.'
elif action == 'is_superuser_assigned':
text_message = 'A user has been assigned to superuser role.'
elif action == 'is_staff_removed':
text_message = 'A user has been removed from staff role.'
else:
text_message = 'A user has been removed from OFA System Admin role.'
subject = 'TDP User Role Change: OFA System Admin'
context = {
'user': user,
'action': action,
}

log(f"Preparing email to System Owner for System Admin role change for user {user.username}",
logger_context=logger_context)

automated_email(
email_path=template_path,
recipient_email=recipient_email,
subject=subject,
email_context=context,
text_message=text_message,
logger_context=logger_context
)
10 changes: 10 additions & 0 deletions tdrs-backend/tdpservice/email/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ def get_ofa_admin_user_emails():
groups__in=Group.objects.filter(name__in=('OFA Admin', 'OFA System Admin'))
).values_list('email', flat=True).distinct()

def get_system_owner_email():
"""Return the email of the System Owner."""
try:
user_email = User.objects.filter(groups__name='System Owner').values_list('email', flat=True).distinct()
except User.DoesNotExist:
user_email = [None]
except User.MultipleObjectsReturned:
user_email = user_email[0]
return user_email

def get_num_access_requests():
"""Return the number of users requesting access."""
return User.objects.filter(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{% extends 'base.html' %}
{% block content %}
<!-- Body copy -->
<p style="color: #000000;">

{% if action == "added" %}
<p>The following user account for the TANF Data Portal (TDP) has been assigned to OFA System Admin group:</p>

{% elif action == "removed" %}
<p>The following user account for the TANF Data Portal (TDP) has been removed from OFA System Admin group:</p>

{% elif action == "is_staff_assigned" %}
<p>The following user account for the TANF Data Portal (TDP) has been assigned to OFA Staff group:</p>

{% elif action == "is_staff_removed" %}
<p>The following user account for the TANF Data Portal (TDP) has been removed from OFA Staff group:</p>

{% elif action == "is_superuser_assigned" %}
<p>The following user account for the TANF Data Portal (TDP) has been assigned to OFA Superuser group:</p>

{% elif action == "is_superuser_removed" %}
<p>The following user account for the TANF Data Portal (TDP) has been removed from OFA Superuser group:</p>

{% endif %}

</p>
<p>Account Information:</p>
<ul>
<li>Name: {{ user.first_name }}</li>
<li>Last name: {{ user.last_name }}</li>
<li>Email: {{ user.email }}</li>
</ul>

<p>Thank you,</p>
TDP Team
{% endblock %}
4 changes: 4 additions & 0 deletions tdrs-backend/tdpservice/users/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ class UsersConfig(AppConfig):

name = "tdpservice.users"
verbose_name = "Users"

def ready(self):
"""Import signals."""
import tdpservice.users.signals # noqa
62 changes: 62 additions & 0 deletions tdrs-backend/tdpservice/users/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Signals for the users app."""
from django.db.models.signals import m2m_changed, pre_save, post_save
from django.dispatch import receiver
from tdpservice.users.models import User
from django.contrib.auth.models import Group
from tdpservice.email.helpers.admin_notifications import email_system_owner_system_admin_role_change

import logging
logger = logging.getLogger()

@receiver(m2m_changed, sender=User.groups.through)
def user_group_changed(sender, instance, action, pk_set, **kwargs):
"""Send an email to the System Owner when a user is assigned or removed from the System Admin role."""
ACTIONS = {
'PRE_REMOVE': 'pre_remove',
'PRE_ADD': 'pre_add',
'PRE_CLEAR': 'pre_clear'
}
if pk_set:
ADMIN_GROUP_PK = Group.objects.get(name="OFA System Admin").pk
group_change_list = [pk for pk in pk_set]
if ADMIN_GROUP_PK in group_change_list and action == ACTIONS['PRE_ADD']:
# EMAIL ADMIN GROUP ADDED to OFA ADMIN
email_system_owner_system_admin_role_change(instance, "added")
elif ADMIN_GROUP_PK in group_change_list and action == ACTIONS['PRE_REMOVE']:
# EMAIL ADMIN GROUP REMOVED from OFA ADMIN
email_system_owner_system_admin_role_change(instance, "removed")
elif pk_set is None and action == ACTIONS['PRE_CLEAR']:
# EMAIL ADMIN GROUP REMOVED from OFA ADMIN
email_system_owner_system_admin_role_change(instance, "removed")

@receiver(pre_save, sender=User)
def user_is_staff_superuser_changed(sender, instance, **kwargs):
"""Send an email to the System Owner when a user is assigned or removed from the System Admin role."""
# first get instance from db for existing state
try:
current_user_state = User.objects.get(pk=instance.pk)
except User.DoesNotExist:
return

# check if is_staff is assigned
if instance.is_staff and not current_user_state.is_staff:
email_system_owner_system_admin_role_change(instance, "is_staff_assigned")
# check if is_staff is removed
elif not instance.is_staff and current_user_state.is_staff:
email_system_owner_system_admin_role_change(instance, "is_staff_removed")
# check if is_superuser is assigned
if instance.is_superuser and not current_user_state.is_superuser:
email_system_owner_system_admin_role_change(instance, "is_superuser_assigned")
# check if is_superuser is removed
elif not instance.is_superuser and current_user_state.is_superuser:
email_system_owner_system_admin_role_change(instance, "is_superuser_removed")


@receiver(post_save, sender=User)
def user_is_staff_superuser_created(sender, instance, created, **kwargs):
"""Send an email to the System Owner when a user is assigned or removed from the System Admin role."""
if created:
if instance.is_staff:
email_system_owner_system_admin_role_change(instance, "is_staff_assigned")
if instance.is_superuser:
email_system_owner_system_admin_role_change(instance, "is_superuser_assigned")
41 changes: 41 additions & 0 deletions tdrs-backend/tdpservice/users/test/test_signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""Test signals."""
import pytest
from unittest.mock import patch, call
from tdpservice.users.models import User
from tdpservice.users.test.factories import AdminUserFactory
from django.contrib.auth.models import Group
import logging
import django


logger = logging.getLogger(__name__)


@pytest.mark.django_db
def test_my_signal_receiver(mocker):
"""Test my_signal_receiver."""
with patch("django.db.models.signals.m2m_changed.send") as mock_receiver:
instance = AdminUserFactory.create()
instance.groups.add(Group.objects.get(name="OFA System Admin"))

mock_receiver.assert_called_with(
sender=User.groups.through,
instance=instance,
action="post_add",
pk_set={Group.objects.get(name="OFA System Admin").pk},
reverse=False,
using="default",
model=django.contrib.auth.models.Group,
)
mock_receiver.call_count = 2 # pre_save and post_save

with patch(
"tdpservice.users.signals.email_system_owner_system_admin_role_change"
) as mock_email_system_owner_system_admin_role_change:
instance = AdminUserFactory.create()
instance.groups.add(Group.objects.get(name="OFA System Admin"))
mock_email_system_owner_system_admin_role_change.assert_has_calls([
call(instance, 'is_staff_assigned'),
call(instance, 'is_superuser_assigned'),
call(instance, "added")
])
14 changes: 14 additions & 0 deletions tdrs-frontend/src/assets/Reports.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@
cursor: pointer;
}

.reprocessed {
background-color: transparent;
border: none;
color: #264A64;
text-align: left;
text-decoration: underline;
margin: 0;
padding: 0;
}

.reprocessed:hover {
cursor: pointer;
}

.usa-table caption {
width: 100%;
}
10 changes: 4 additions & 6 deletions tdrs-frontend/src/components/Modal/Modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,17 @@ const Modal = ({ title, message, buttons = [], isVisible = false }) => {
(b) => b.key === selectedButtonKey
)

const btnIdxMinOne = Math.max(0, buttons.length - 1)
if (shiftKey) {
// go backward
const selectedIdxMinOne = Math.max(0, selectedButtonIndex - 1)
nextButtonIndex =
selectedButtonIndex >= 0
? selectedButtonIndex - 1
: buttons.length - 1
selectedButtonIndex >= 0 ? selectedIdxMinOne : btnIdxMinOne
} else {
nextButtonIndex =
selectedButtonIndex < buttons.length - 1 ? selectedButtonIndex + 1 : 0
selectedButtonIndex < btnIdxMinOne ? selectedButtonIndex + 1 : 0
}
}

const nextButtonKey = buttons[nextButtonIndex].key
const nextButton = modalRef.current.querySelector(
`button[buttonkey="${nextButtonKey}"]`
Expand All @@ -45,7 +44,6 @@ const Modal = ({ title, message, buttons = [], isVisible = false }) => {

const onKeyDown = (e) => {
const { key, shiftKey } = e

switch (key) {
case 'Tab':
onTabPressed(shiftKey)
Expand Down
13 changes: 13 additions & 0 deletions tdrs-frontend/src/components/Reports/Reports.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { fetchSttList } from '../../actions/sttList'
import Modal from '../Modal'
import SegmentedControl from '../SegmentedControl'
import SubmissionHistory from '../SubmissionHistory'
import ReprocessedModal from '../SubmissionHistory/ReprocessedModal'
import { selectPrimaryUserRole } from '../../selectors/auth'

/**
Expand Down Expand Up @@ -55,6 +56,9 @@ function Reports() {
const [formValidation, setFormValidationState] = useState({})
const [touched, setTouched] = useState({})

const [reprocessedModalVisible, setReprocessedModalVisible] = useState(false)
const [reprocessedDate, setReprocessedDate] = useState('')

const quarters = {
Q1: 'Quarter 1 (October - December)',
Q2: 'Quarter 2 (January - March)',
Expand Down Expand Up @@ -472,6 +476,10 @@ function Reports() {
stt: stt,
file_type: fileTypeInputValue,
}}
reprocessedState={{
setModalVisible: setReprocessedModalVisible,
setDate: setReprocessedDate,
}}
/>
)}
</>
Expand Down Expand Up @@ -499,6 +507,11 @@ function Reports() {
},
]}
/>
<ReprocessedModal
date={reprocessedDate}
isVisible={reprocessedModalVisible}
setModalVisible={setReprocessedModalVisible}
/>
</>
)
}
Expand Down
Loading

0 comments on commit c129e03

Please sign in to comment.