From e219c6c323ef0754aa00c5c26106faac2f24e5dc Mon Sep 17 00:00:00 2001 From: Claire Peters Date: Mon, 11 Sep 2023 10:22:05 -0700 Subject: [PATCH 01/10] minor linting of send_expiry_emails --- coldfront/core/allocation/tasks.py | 108 ++++++++++++++--------------- 1 file changed, 52 insertions(+), 56 deletions(-) diff --git a/coldfront/core/allocation/tasks.py b/coldfront/core/allocation/tasks.py index e1a37fc05..4f3b548cf 100644 --- a/coldfront/core/allocation/tasks.py +++ b/coldfront/core/allocation/tasks.py @@ -48,20 +48,18 @@ def send_expiry_emails(): email_receiver_list = [] for days_remaining in sorted(set(EMAIL_ALLOCATION_EXPIRING_NOTIFICATION_DAYS)): - expring_in_days = (datetime.datetime.today( - ) + datetime.timedelta(days=days_remaining)).date() - + expring_in_days = (datetime.datetime.today() + datetime.timedelta(days=days_remaining)).date() + for allocationuser in user.allocationuser_set.all(): allocation = allocationuser.allocation - if (((allocation.status.name in ['Active', 'Payment Pending', 'Payment Requested', 'Unpaid']) and (allocation.end_date == expring_in_days))): - + if (allocation.status.name in ['Active', 'Payment Pending', 'Payment Requested', 'Unpaid'] and allocation.end_date == expring_in_days): + project_url = f'{CENTER_BASE_URL.strip("/")}/{"project"}/{allocation.project.pk}/' - if (allocation.status.name in ['Payment Pending', 'Payment Requested', 'Unpaid']): - allocation_renew_url = f'{CENTER_BASE_URL.strip("/")}/{"allocation"}/{allocation.pk}/' - else: - allocation_renew_url = f'{CENTER_BASE_URL.strip("/")}/{"allocation"}/{allocation.pk}/{"renew"}/' + allocation_renew_url = f'{CENTER_BASE_URL.strip("/")}/{"allocation"}/{allocation.pk}/' + if allocation.status.name == 'Active': + allocation_renew_url = allocation_renew_url + '{"renew"}/' resource_name = allocation.get_parent_resource.name @@ -75,7 +73,7 @@ def send_expiry_emails(): 'opt_out_instruction_url': EMAIL_OPT_OUT_INSTRUCTION_URL, 'signature': EMAIL_SIGNATURE } - + expire_notification = allocation.allocationattribute_set.filter( allocation_attribute_type__name='EXPIRE NOTIFICATION').first() if expire_notification and expire_notification.value == 'No': @@ -86,22 +84,21 @@ def send_expiry_emails(): if cloud_usage_notification and cloud_usage_notification.value == 'No': continue - for projectuser in allocation.project.projectuser_set.filter(user=user, status__name='Active'): - if ((projectuser.enable_notifications) and - (allocationuser.user == user and allocationuser.status.name == 'Active')): + for projectuser in allocation.project.projectuser_set.filter(user=user, status__name='Active'): + if not (projectuser.enable_notifications and + allocationuser.user == user and allocationuser.status.name == 'Active'): + continue - if (user.email not in email_receiver_list): - email_receiver_list.append(user.email) + if user.email not in email_receiver_list: + email_receiver_list.append(user.email) - if days_remaining not in expirationdict: - expirationdict[days_remaining] = [] - expirationdict[days_remaining].append((project_url, allocation_renew_url, resource_name)) - else: - expirationdict[days_remaining].append((project_url, allocation_renew_url, resource_name)) + if days_remaining not in expirationdict: + expirationdict[days_remaining] = [] + expirationdict[days_remaining].append((project_url, allocation_renew_url, resource_name)) + + if allocation.project.title not in projectdict: + projectdict[allocation.project.title] = (project_url, allocation.project.pi.username) - if allocation.project.title not in projectdict: - projectdict[allocation.project.title] = (project_url, allocation.project.pi.username,) - if email_receiver_list: send_email_template(f'Your access to {CENTER_NAME}\'s resources is expiring soon', @@ -109,7 +106,7 @@ def send_expiry_emails(): template_context, EMAIL_SENDER, email_receiver_list - ) + ) logger.debug(f'Allocation(s) expiring in soon, email sent to user {user}.') @@ -120,14 +117,14 @@ def send_expiry_emails(): projectdict = {} allocationdict = {} email_receiver_list = [] - + expring_in_days = (datetime.datetime.today() + datetime.timedelta(days=-1)).date() - + for allocationuser in user.allocationuser_set.all(): allocation = allocationuser.allocation if (allocation.end_date == expring_in_days): - + project_url = f'{CENTER_BASE_URL.strip("/")}/{"project"}/{allocation.project.pk}/' allocation_renew_url = f'{CENTER_BASE_URL.strip("/")}/{"allocation"}/{allocation.pk}/{"renew"}/' @@ -148,38 +145,36 @@ def send_expiry_emails(): expire_notification = allocation.allocationattribute_set.filter( allocation_attribute_type__name='EXPIRE NOTIFICATION').first() - for projectuser in allocation.project.projectuser_set.filter(user=user, status__name='Active'): - if ((projectuser.enable_notifications) and - (allocationuser.user == user and allocationuser.status.name == 'Active')): + for projectuser in allocation.project.projectuser_set.filter(user=user, status__name='Active'): + if not (expire_notification and expire_notification.value == 'Yes'): + continue + + if not (projectuser.enable_notifications and + allocationuser.user == user and allocationuser.status.name == 'Active'): + continue + + if user.email not in email_receiver_list: + email_receiver_list.append(user.email) - if expire_notification and expire_notification.value == 'Yes': + if project_url not in allocationdict: + allocationdict[project_url] = [] + if {allocation_renew_url : resource_name} not in allocationdict[project_url]: + allocationdict[project_url].append({allocation_renew_url : resource_name}) - if (user.email not in email_receiver_list): - email_receiver_list.append(user.email) + if allocation.project.title not in projectdict: + projectdict[allocation.project.title] = (project_url, allocation.project.pi.username) - if project_url not in allocationdict: - allocationdict[project_url] = [] - allocationdict[project_url].append({allocation_renew_url : resource_name}) - else: - if {allocation_renew_url : resource_name} not in allocationdict[project_url]: - allocationdict[project_url].append({allocation_renew_url : resource_name}) + if EMAIL_ADMINS_ON_ALLOCATION_EXPIRE: - if allocation.project.title not in projectdict: - projectdict[allocation.project.title] = (project_url, allocation.project.pi.username) + if project_url not in admin_allocationdict: + admin_allocationdict[project_url] = [] + if {allocation_url : resource_name} not in admin_allocationdict[project_url]: + admin_allocationdict[project_url].append({allocation_url : resource_name}) - if EMAIL_ADMINS_ON_ALLOCATION_EXPIRE: - - if project_url not in admin_allocationdict: - admin_allocationdict[project_url] = [] - admin_allocationdict[project_url].append({allocation_url : resource_name}) - else: - if {allocation_url : resource_name} not in admin_allocationdict[project_url]: - admin_allocationdict[project_url].append({allocation_url : resource_name}) + if allocation.project.title not in admin_projectdict: + admin_projectdict[allocation.project.title] = (project_url, allocation.project.pi.username) - if allocation.project.title not in admin_projectdict: - admin_projectdict[allocation.project.title] = (project_url, allocation.project.pi.username) - if email_receiver_list: send_email_template('Your access to resource(s) have expired', @@ -187,10 +182,11 @@ def send_expiry_emails(): template_context, EMAIL_SENDER, email_receiver_list - ) + ) logger.debug(f'Allocation(s) expired email sent to user {user}.') + # produce "allocations have expired" list and send emails if EMAIL_ADMINS_ON_ALLOCATION_EXPIRE: if admin_projectdict: @@ -199,11 +195,11 @@ def send_expiry_emails(): 'project_dict': admin_projectdict, 'allocation_dict': admin_allocationdict, 'signature': EMAIL_SIGNATURE - } - + } + send_email_template('Allocation(s) have expired', 'email/admin_allocation_expired.txt', admin_template_context, EMAIL_SENDER, [EMAIL_ADMIN_LIST,] - ) \ No newline at end of file + ) From ce1cd0ff2d59ae35a23f16973f6cd56b85c24dd3 Mon Sep 17 00:00:00 2001 From: Claire Peters Date: Mon, 11 Sep 2023 15:13:13 -0700 Subject: [PATCH 02/10] handle absence of parent resource name for allocationchangerequest strings --- coldfront/core/allocation/models.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coldfront/core/allocation/models.py b/coldfront/core/allocation/models.py index 3af543b26..eee9c2f22 100644 --- a/coldfront/core/allocation/models.py +++ b/coldfront/core/allocation/models.py @@ -419,7 +419,7 @@ def has_perm(self, user, perm): def __str__(self): tmp = self.get_parent_resource if tmp is None: - return 'no parent resource' + return '%s' % (self.project.pi) return '%s (%s)' % (self.get_parent_resource.name, self.project.pi) class AllocationAdminNote(TimeStampedModel): @@ -738,6 +738,9 @@ def get_parent_resource(self): return self.allocation.resources.filter(is_allocatable=True).first() def __str__(self): + tmp = self.get_parent_resource + if tmp is None: + return '(%s)' % (self.allocation.project.pi) return '%s (%s)' % (self.get_parent_resource.name, self.allocation.project.pi) class AllocationAttributeChangeRequest(TimeStampedModel): From 9e314744118b61e5bc757f22e925dcbe824daa1d Mon Sep 17 00:00:00 2001 From: Claire Peters Date: Mon, 11 Sep 2023 15:15:21 -0700 Subject: [PATCH 03/10] bit more refactoring; add send_request_reminder_emails task --- coldfront/core/allocation/tasks.py | 217 ++++++++++++++++++----------- 1 file changed, 136 insertions(+), 81 deletions(-) diff --git a/coldfront/core/allocation/tasks.py b/coldfront/core/allocation/tasks.py index 4f3b548cf..ac9face92 100644 --- a/coldfront/core/allocation/tasks.py +++ b/coldfront/core/allocation/tasks.py @@ -2,11 +2,17 @@ # import the logging library import logging -from coldfront.core.allocation.models import (Allocation, - AllocationStatusChoice) -from coldfront.core.user.models import User +from django.utils import timezone +from django.contrib.auth import get_user_model + +from coldfront.core.allocation.models import ( + Allocation, + AllocationStatusChoice, + AllocationChangeRequest, + AllocationAttributeChangeRequest, +) from coldfront.core.utils.common import import_from_settings -from coldfront.core.utils.mail import send_email_template +from coldfront.core.utils.mail import send_email_template, send_admin_email_template # Get an instance of a logger logger = logging.getLogger(__name__) @@ -28,102 +34,83 @@ def update_statuses(): - expired_status_choice = AllocationStatusChoice.objects.get( - name='Expired') + expired_status_choice = AllocationStatusChoice.objects.get(name='Expired') allocations_to_expire = Allocation.objects.filter( - status__name__in=['Active','Payment Pending','Payment Requested', 'Unpaid',], end_date__lt=datetime.datetime.now().date()) + status__name__in=['Active', 'Payment Pending', 'Payment Requested', 'Unpaid'], + end_date__lt=timezone.now().date() + ) for sub_obj in allocations_to_expire: sub_obj.status = expired_status_choice sub_obj.save() - logger.info('Allocations set to expired: {}'.format( - allocations_to_expire.count())) + logger.info('Allocations set to expired: %s', allocations_to_expire.count()) + + +def send_request_reminder_emails(): + """ + Send reminders to admins about active allocation requests and + allocation update requests that have existed for more than a week + """ + req_alert_date = timezone.now().date() - datetime.timedelta(days=7) + # Allocation Change Requests are separate items. + # if any that are more than a week old and "pending", send an email digest to admins + pending_changerequests = { + change_request: AllocationAttributeChangeRequest.objects.filter( + allocation_change_request=change_request, + ) + for change_request in AllocationChangeRequest.objects.filter( + status__name='Pending', created__lte=req_alert_date + ) + } + if pending_changerequests: + allocation_change_template_context = { + 'center_name': CENTER_NAME, + 'pending_changerequests': pending_changerequests, + 'signature': EMAIL_SIGNATURE, + 'url_base': f'{CENTER_BASE_URL.strip("/")}/allocation/change-request/' + } + send_admin_email_template( + 'Pending Allocation Changes', + 'email/pending_allocation_changes.txt', + allocation_change_template_context, + ) + + # Allocation Requests are allocations marked as "new" + pending_allocations = Allocation.objects.filter( + status__name = 'New', created__lte=req_alert_date + ) + if pending_allocations: + + new_allocation_template_context = { + 'center_name': CENTER_NAME, + 'pending_allocations': pending_allocations, + 'signature': EMAIL_SIGNATURE, + 'url_base': f'{CENTER_BASE_URL.strip("/")}/allocation/' + } + send_admin_email_template( + 'Pending Allocations', + 'email/pending_allocations.txt', + new_allocation_template_context, + ) + # return statement for testing + return (pending_changerequests, pending_allocations) def send_expiry_emails(): #Allocations expiring soon - for user in User.objects.all(): - projectdict = {} - expirationdict = {} - email_receiver_list = [] - for days_remaining in sorted(set(EMAIL_ALLOCATION_EXPIRING_NOTIFICATION_DAYS)): - - expring_in_days = (datetime.datetime.today() + datetime.timedelta(days=days_remaining)).date() - - for allocationuser in user.allocationuser_set.all(): - allocation = allocationuser.allocation - - if (allocation.status.name in ['Active', 'Payment Pending', 'Payment Requested', 'Unpaid'] and allocation.end_date == expring_in_days): - - project_url = f'{CENTER_BASE_URL.strip("/")}/{"project"}/{allocation.project.pk}/' - - allocation_renew_url = f'{CENTER_BASE_URL.strip("/")}/{"allocation"}/{allocation.pk}/' - if allocation.status.name == 'Active': - allocation_renew_url = allocation_renew_url + '{"renew"}/' - - resource_name = allocation.get_parent_resource.name - - template_context = { - 'center_name': CENTER_NAME, - 'expring_in_days': days_remaining, - 'project_dict': projectdict, - 'expiration_dict': expirationdict, - 'expiration_days': sorted(set(EMAIL_ALLOCATION_EXPIRING_NOTIFICATION_DAYS)), - 'project_renewal_help_url': CENTER_PROJECT_RENEWAL_HELP_URL, - 'opt_out_instruction_url': EMAIL_OPT_OUT_INSTRUCTION_URL, - 'signature': EMAIL_SIGNATURE - } - - expire_notification = allocation.allocationattribute_set.filter( - allocation_attribute_type__name='EXPIRE NOTIFICATION').first() - if expire_notification and expire_notification.value == 'No': - continue - - cloud_usage_notification = allocation.allocationattribute_set.filter( - allocation_attribute_type__name='CLOUD_USAGE_NOTIFICATION').first() - if cloud_usage_notification and cloud_usage_notification.value == 'No': - continue - - for projectuser in allocation.project.projectuser_set.filter(user=user, status__name='Active'): - if not (projectuser.enable_notifications and - allocationuser.user == user and allocationuser.status.name == 'Active'): - continue - - if user.email not in email_receiver_list: - email_receiver_list.append(user.email) - - if days_remaining not in expirationdict: - expirationdict[days_remaining] = [] - expirationdict[days_remaining].append((project_url, allocation_renew_url, resource_name)) - - if allocation.project.title not in projectdict: - projectdict[allocation.project.title] = (project_url, allocation.project.pi.username) - - if email_receiver_list: - - send_email_template(f'Your access to {CENTER_NAME}\'s resources is expiring soon', - 'email/allocation_expiring.txt', - template_context, - EMAIL_SENDER, - email_receiver_list - ) - - logger.debug(f'Allocation(s) expiring in soon, email sent to user {user}.') - - #Allocations expired admin_projectdict = {} admin_allocationdict = {} - for user in User.objects.all(): + for user in get_user_model().objects.all(): projectdict = {} allocationdict = {} email_receiver_list = [] - expring_in_days = (datetime.datetime.today() + datetime.timedelta(days=-1)).date() + expring_in_days = timezone.now().date() + datetime.timedelta(days=1) for allocationuser in user.allocationuser_set.all(): allocation = allocationuser.allocation - if (allocation.end_date == expring_in_days): + if allocation.end_date == expring_in_days: project_url = f'{CENTER_BASE_URL.strip("/")}/{"project"}/{allocation.project.pk}/' @@ -186,6 +173,74 @@ def send_expiry_emails(): logger.debug(f'Allocation(s) expired email sent to user {user}.') + projectdict = {} + expirationdict = {} + email_receiver_list = [] + for days_remaining in sorted(set(EMAIL_ALLOCATION_EXPIRING_NOTIFICATION_DAYS)): + + expring_in_days = timezone.now().date() + datetime.timedelta(days=days_remaining) + + for allocationuser in user.allocationuser_set.all(): + allocation = allocationuser.allocation + + if (allocation.status.name in ['Active', 'Payment Pending', 'Payment Requested', 'Unpaid'] and allocation.end_date == expring_in_days): + + project_url = f'{CENTER_BASE_URL.strip("/")}/{"project"}/{allocation.project.pk}/' + + allocation_renew_url = f'{CENTER_BASE_URL.strip("/")}/{"allocation"}/{allocation.pk}/' + if allocation.status.name == 'Active': + allocation_renew_url = allocation_renew_url + '{"renew"}/' + + resource_name = allocation.get_parent_resource.name + + template_context = { + 'center_name': CENTER_NAME, + 'expring_in_days': days_remaining, + 'project_dict': projectdict, + 'expiration_dict': expirationdict, + 'expiration_days': sorted(set(EMAIL_ALLOCATION_EXPIRING_NOTIFICATION_DAYS)), + 'project_renewal_help_url': CENTER_PROJECT_RENEWAL_HELP_URL, + 'opt_out_instruction_url': EMAIL_OPT_OUT_INSTRUCTION_URL, + 'signature': EMAIL_SIGNATURE + } + + expire_notification = allocation.allocationattribute_set.filter( + allocation_attribute_type__name='EXPIRE NOTIFICATION').first() + if expire_notification and expire_notification.value == 'No': + continue + + cloud_usage_notification = allocation.allocationattribute_set.filter( + allocation_attribute_type__name='CLOUD_USAGE_NOTIFICATION').first() + if cloud_usage_notification and cloud_usage_notification.value == 'No': + continue + + for projectuser in allocation.project.projectuser_set.filter(user=user, status__name='Active'): + if not (projectuser.enable_notifications and + allocationuser.user == user and allocationuser.status.name == 'Active'): + continue + + if user.email not in email_receiver_list: + email_receiver_list.append(user.email) + + if days_remaining not in expirationdict: + expirationdict[days_remaining] = [] + expirationdict[days_remaining].append((project_url, allocation_renew_url, resource_name)) + + if allocation.project.title not in projectdict: + projectdict[allocation.project.title] = (project_url, allocation.project.pi.username) + + if email_receiver_list: + + send_email_template(f"Your access to {CENTER_NAME}'s resources is expiring soon", + 'email/allocation_expiring.txt', + template_context, + EMAIL_SENDER, + email_receiver_list + ) + + logger.debug(f'Allocation(s) expiring in soon, email sent to user {user}.') + + # produce "allocations have expired" list and send emails if EMAIL_ADMINS_ON_ALLOCATION_EXPIRE: From 7ca6286583914865e732f7387de7a6d581050ce6 Mon Sep 17 00:00:00 2001 From: Claire Peters Date: Mon, 11 Sep 2023 15:16:03 -0700 Subject: [PATCH 04/10] minor reformat of utils.mail --- coldfront/core/utils/mail.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/coldfront/core/utils/mail.py b/coldfront/core/utils/mail.py index 452023a94..5a653f7d9 100644 --- a/coldfront/core/utils/mail.py +++ b/coldfront/core/utils/mail.py @@ -91,10 +91,15 @@ def build_link(url_path, domain_url=''): def send_admin_email_template(subject, template_name, template_context): """Helper function for sending admin emails using a template """ - send_email_template(subject, template_name, template_context, EMAIL_SENDER, [EMAIL_TICKET_SYSTEM_ADDRESS,]) + send_email_template( + subject, template_name, template_context, EMAIL_SENDER, [EMAIL_TICKET_SYSTEM_ADDRESS,] + ) -def send_allocation_admin_email(allocation_obj, subject, template_name, url_path='', domain_url='', other_vars=None): +def send_allocation_admin_email( + allocation_obj, subject, template_name, + url_path='', domain_url='', other_vars=None +): """Send allocation admin emails """ if not url_path: @@ -118,7 +123,10 @@ def send_allocation_admin_email(allocation_obj, subject, template_name, url_path ctx, ) -def send_allocation_customer_email(allocation_obj, subject, template_name, url_path='', domain_url=''): +def send_allocation_customer_email( + allocation_obj, subject, template_name, + url_path='', domain_url='' +): """Send allocation customer emails """ if not url_path: From a6342be460c68ce31b049a914763fbbc26653527 Mon Sep 17 00:00:00 2001 From: Claire Peters Date: Mon, 11 Sep 2023 15:19:53 -0700 Subject: [PATCH 05/10] add templates for allocation and allocation change backlog reminder emails --- .../email/pending_allocation_changes.txt | 21 +++++++++++++++++++ .../templates/email/pending_allocations.txt | 20 ++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 coldfront/templates/email/pending_allocation_changes.txt create mode 100644 coldfront/templates/email/pending_allocations.txt diff --git a/coldfront/templates/email/pending_allocation_changes.txt b/coldfront/templates/email/pending_allocation_changes.txt new file mode 100644 index 000000000..1bfe123b8 --- /dev/null +++ b/coldfront/templates/email/pending_allocation_changes.txt @@ -0,0 +1,21 @@ +Greetings, {{center_name}} admins! + +This is a notice about allocation change requests on Coldfront that have been pending +for the past week: +--------------------- +{% for change_request, change_attrs in pending_allocation_change_requests.items %} + +Allocation: {{change_request.allocation}} + +Change it here: {{url_base}}{{change_request.pk}}/ + +Requested changes: +{% for change_attr in change_attrs %} +{{change_attr.allocation_attribute.allocation_attribute_type.name}} - change to {{change_attr.new_value}} +{% endfor %} + +--------------------- +{% endfor %} + +Thank you, +{{ signature }} diff --git a/coldfront/templates/email/pending_allocations.txt b/coldfront/templates/email/pending_allocations.txt new file mode 100644 index 000000000..985445b20 --- /dev/null +++ b/coldfront/templates/email/pending_allocations.txt @@ -0,0 +1,20 @@ +Greetings, {{center_name}} admins! + +This is a notice about allocation change requests on Coldfront that have been pending +for the past week: +--------------------- +{% for allocation in new_allocations %} + +Allocation: {{allocation}} + +Review the request here: {{url_base}}{{allocation.pk}}/ + +Requested changes: +{{allocation}} +--------------------- + +{% endfor %} + + +Thank you, +{{ signature }} From 7bfe6e210b168bbce4ef3e62c2baa3deeb0afaa3 Mon Sep 17 00:00:00 2001 From: Claire Peters Date: Mon, 11 Sep 2023 15:23:10 -0700 Subject: [PATCH 06/10] add minimal test for send_request_reminder_emails --- coldfront/core/allocation/tests/test_tasks.py | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 coldfront/core/allocation/tests/test_tasks.py diff --git a/coldfront/core/allocation/tests/test_tasks.py b/coldfront/core/allocation/tests/test_tasks.py new file mode 100644 index 000000000..6ebed0e8c --- /dev/null +++ b/coldfront/core/allocation/tests/test_tasks.py @@ -0,0 +1,61 @@ + +from django.test import TestCase + +from django.utils import timezone + + +from coldfront.core.test_helpers import utils +from coldfront.core.allocation.models import ( + Allocation, + AllocationUserNote, + AllocationAttribute, + AllocationChangeRequest, + AllocationStatusChoice, +) +from coldfront.core.test_helpers.factories import ( + setup_models, + AllocationFactory, + AllocationChangeRequestFactory, +) +from coldfront.core.allocation.tasks import send_request_reminder_emails + +UTIL_FIXTURES = [ + "coldfront/core/test_helpers/test_data/test_fixtures/ifx.json", +] + +class RequestReminderEmails(TestCase): + + fixtures = UTIL_FIXTURES + + def setUp(self): + """set up test data""" + setup_models(self) + + # create Allocations with status "new" and "created" dates of 5, 7, and 9 days ago + self.allocation1 = AllocationFactory( + status=AllocationStatusChoice.objects.get(name="New"), + created=timezone.now() - timezone.timedelta(days=5), + ) + self.allocation2 = AllocationFactory( + status=AllocationStatusChoice.objects.get(name="New"), + created=timezone.now() - timezone.timedelta(days=7) + ) + self.allocation3 = AllocationFactory( + status=AllocationStatusChoice.objects.get(name="New"), + created=timezone.now() - timezone.timedelta(days=9) + ) + + # create AllocationChangeRequests with status "pending" and "created" dates of 5, 7, and 9 days ago + self.acr1 = AllocationChangeRequestFactory( + created=timezone.now() - timezone.timedelta(days=5), + ) + self.acr2 = AllocationChangeRequestFactory( + created=timezone.now() - timezone.timedelta(days=7) + ) + self.acr3 = AllocationChangeRequestFactory( + created=timezone.now() - timezone.timedelta(days=9) + ) + + def test_send_request_reminder_emails(self): + """test send_request_reminder_emails task""" + pending_changerequests, pending_allocations = send_request_reminder_emails() From 1bc59eecf1f48e7d730a46081cfc29f670da0818 Mon Sep 17 00:00:00 2001 From: Claire Peters Date: Mon, 11 Sep 2023 15:48:56 -0700 Subject: [PATCH 07/10] remove unneeded imports from test_tasks, fix template var names --- coldfront/core/allocation/tests/test_tasks.py | 10 +--------- .../templates/email/pending_allocation_changes.txt | 2 +- coldfront/templates/email/pending_allocations.txt | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/coldfront/core/allocation/tests/test_tasks.py b/coldfront/core/allocation/tests/test_tasks.py index 6ebed0e8c..5edae3d70 100644 --- a/coldfront/core/allocation/tests/test_tasks.py +++ b/coldfront/core/allocation/tests/test_tasks.py @@ -3,15 +3,7 @@ from django.utils import timezone - -from coldfront.core.test_helpers import utils -from coldfront.core.allocation.models import ( - Allocation, - AllocationUserNote, - AllocationAttribute, - AllocationChangeRequest, - AllocationStatusChoice, -) +from coldfront.core.allocation.models import AllocationStatusChoice from coldfront.core.test_helpers.factories import ( setup_models, AllocationFactory, diff --git a/coldfront/templates/email/pending_allocation_changes.txt b/coldfront/templates/email/pending_allocation_changes.txt index 1bfe123b8..5a3c6e93d 100644 --- a/coldfront/templates/email/pending_allocation_changes.txt +++ b/coldfront/templates/email/pending_allocation_changes.txt @@ -3,7 +3,7 @@ Greetings, {{center_name}} admins! This is a notice about allocation change requests on Coldfront that have been pending for the past week: --------------------- -{% for change_request, change_attrs in pending_allocation_change_requests.items %} +{% for change_request, change_attrs in pending_changerequests.items %} Allocation: {{change_request.allocation}} diff --git a/coldfront/templates/email/pending_allocations.txt b/coldfront/templates/email/pending_allocations.txt index 985445b20..f6e140aff 100644 --- a/coldfront/templates/email/pending_allocations.txt +++ b/coldfront/templates/email/pending_allocations.txt @@ -3,7 +3,7 @@ Greetings, {{center_name}} admins! This is a notice about allocation change requests on Coldfront that have been pending for the past week: --------------------- -{% for allocation in new_allocations %} +{% for allocation in pending_allocations %} Allocation: {{allocation}} From 278dd7b5dfbc9cabc673a1bf542989d512e79756 Mon Sep 17 00:00:00 2001 From: Claire Peters Date: Wed, 25 Oct 2023 17:27:07 -0700 Subject: [PATCH 08/10] update pending allocation email templates --- .../management/commands/import_add_allocations.py | 4 ++-- .../templates/email/pending_allocation_changes.txt | 13 ++++--------- coldfront/templates/email/pending_allocations.txt | 13 ++----------- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/coldfront/core/utils/management/commands/import_add_allocations.py b/coldfront/core/utils/management/commands/import_add_allocations.py index 703a62651..ef9af34b8 100644 --- a/coldfront/core/utils/management/commands/import_add_allocations.py +++ b/coldfront/core/utils/management/commands/import_add_allocations.py @@ -105,10 +105,10 @@ def handle(self, *args, **options): 'status': AllocationUserStatusChoice.objects.get(name='Active')} ) except ValidationError: - logger.debug('adding PI %s to allocation %s failed', pi_obj.pi.username, allocation.pk) + logger.debug('adding PI %s to allocation %s failed', pi_obj.username, allocation.pk) created = None if created: - print('PI added: ' + project_obj.pi.username) + print('PI added: ' + pi_obj.username) missing_projects = [{'title': title} for title in command_report['missing_projects']] if not added_allocations_df.empty: added_allocations_df['billing_code'] = None diff --git a/coldfront/templates/email/pending_allocation_changes.txt b/coldfront/templates/email/pending_allocation_changes.txt index 5a3c6e93d..c5bff928a 100644 --- a/coldfront/templates/email/pending_allocation_changes.txt +++ b/coldfront/templates/email/pending_allocation_changes.txt @@ -1,21 +1,16 @@ -Greetings, {{center_name}} admins! - -This is a notice about allocation change requests on Coldfront that have been pending -for the past week: +This is a notice about pending allocation change requests on Coldfront that are +at least a week old: --------------------- {% for change_request, change_attrs in pending_changerequests.items %} Allocation: {{change_request.allocation}} -Change it here: {{url_base}}{{change_request.pk}}/ - Requested changes: {% for change_attr in change_attrs %} {{change_attr.allocation_attribute.allocation_attribute_type.name}} - change to {{change_attr.new_value}} {% endfor %} +Change it here: {{url_base}}{{change_request.pk}}/ + --------------------- {% endfor %} - -Thank you, -{{ signature }} diff --git a/coldfront/templates/email/pending_allocations.txt b/coldfront/templates/email/pending_allocations.txt index f6e140aff..7cc3f8a9d 100644 --- a/coldfront/templates/email/pending_allocations.txt +++ b/coldfront/templates/email/pending_allocations.txt @@ -1,7 +1,5 @@ -Greetings, {{center_name}} admins! - -This is a notice about allocation change requests on Coldfront that have been pending -for the past week: +This is a notice about pending allocation requests on Coldfront that are at +least a week old: --------------------- {% for allocation in pending_allocations %} @@ -9,12 +7,5 @@ Allocation: {{allocation}} Review the request here: {{url_base}}{{allocation.pk}}/ -Requested changes: -{{allocation}} --------------------- - {% endfor %} - - -Thank you, -{{ signature }} From 3096a45554b90d66235116af363425620257092e Mon Sep 17 00:00:00 2001 From: Claire Peters Date: Wed, 25 Oct 2023 17:47:04 -0700 Subject: [PATCH 09/10] update pending allocation email templates --- coldfront/templates/email/pending_allocation_changes.txt | 3 --- coldfront/templates/email/pending_allocations.txt | 3 --- 2 files changed, 6 deletions(-) diff --git a/coldfront/templates/email/pending_allocation_changes.txt b/coldfront/templates/email/pending_allocation_changes.txt index c5bff928a..98533af00 100644 --- a/coldfront/templates/email/pending_allocation_changes.txt +++ b/coldfront/templates/email/pending_allocation_changes.txt @@ -2,15 +2,12 @@ This is a notice about pending allocation change requests on Coldfront that are at least a week old: --------------------- {% for change_request, change_attrs in pending_changerequests.items %} - Allocation: {{change_request.allocation}} Requested changes: {% for change_attr in change_attrs %} {{change_attr.allocation_attribute.allocation_attribute_type.name}} - change to {{change_attr.new_value}} {% endfor %} - Change it here: {{url_base}}{{change_request.pk}}/ - --------------------- {% endfor %} diff --git a/coldfront/templates/email/pending_allocations.txt b/coldfront/templates/email/pending_allocations.txt index 7cc3f8a9d..bb1036c36 100644 --- a/coldfront/templates/email/pending_allocations.txt +++ b/coldfront/templates/email/pending_allocations.txt @@ -2,10 +2,7 @@ This is a notice about pending allocation requests on Coldfront that are at least a week old: --------------------- {% for allocation in pending_allocations %} - Allocation: {{allocation}} - Review the request here: {{url_base}}{{allocation.pk}}/ - --------------------- {% endfor %} From 49691d8650afaa74f195c4ce4c4308dc72cdf185 Mon Sep 17 00:00:00 2001 From: Claire Peters Date: Wed, 25 Oct 2023 18:17:51 -0700 Subject: [PATCH 10/10] add send_request_reminder_emails to scheduled tasks --- .../core/utils/management/commands/add_scheduled_tasks.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/coldfront/core/utils/management/commands/add_scheduled_tasks.py b/coldfront/core/utils/management/commands/add_scheduled_tasks.py index c89de8345..ec7f61e27 100644 --- a/coldfront/core/utils/management/commands/add_scheduled_tasks.py +++ b/coldfront/core/utils/management/commands/add_scheduled_tasks.py @@ -39,3 +39,11 @@ def handle(self, *args, **options): next_run=date, schedule_type=Schedule.DAILY, **kwargs) + + if f'coldfront.core.allocation.tasks.send_request_reminder_emails' not in scheduled: + schedule( + f'coldfront.core.allocation.tasks.send_request_reminder_emails', + next_run=date, + schedule_type=Schedule.WEEKLY, + **kwargs + )