From f581bd9f2bc8758a4df7c9455c1be8eae22c5a5f Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Thu, 4 Jun 2020 00:35:59 -0600 Subject: [PATCH] Mails for approval process --- Pipfile | 1 + Pipfile.lock | 39 +++++--- crc/__init__.py | 5 + crc/services/mails.py | 99 +++++++++++++++++++ .../mails/ramp_up_approval_request.html | 1 + .../mails/ramp_up_approval_request.txt | 1 + ...ramp_up_approval_request_first_review.html | 1 + .../ramp_up_approval_request_first_review.txt | 1 + .../templates/mails/ramp_up_approved.html | 1 + .../templates/mails/ramp_up_approved.txt | 1 + .../templates/mails/ramp_up_denied.html | 0 crc/static/templates/mails/ramp_up_denied.txt | 0 .../templates/mails/ramp_up_submission.html | 5 + .../templates/mails/ramp_up_submission.txt | 5 + tests/test_mails.py | 48 +++++++++ 15 files changed, 192 insertions(+), 16 deletions(-) create mode 100644 crc/services/mails.py create mode 100644 crc/static/templates/mails/ramp_up_approval_request.html create mode 100644 crc/static/templates/mails/ramp_up_approval_request.txt create mode 100644 crc/static/templates/mails/ramp_up_approval_request_first_review.html create mode 100644 crc/static/templates/mails/ramp_up_approval_request_first_review.txt create mode 100644 crc/static/templates/mails/ramp_up_approved.html create mode 100644 crc/static/templates/mails/ramp_up_approved.txt create mode 100644 crc/static/templates/mails/ramp_up_denied.html create mode 100644 crc/static/templates/mails/ramp_up_denied.txt create mode 100644 crc/static/templates/mails/ramp_up_submission.html create mode 100644 crc/static/templates/mails/ramp_up_submission.txt create mode 100644 tests/test_mails.py diff --git a/Pipfile b/Pipfile index 6a5e31dd..0079962c 100644 --- a/Pipfile +++ b/Pipfile @@ -39,6 +39,7 @@ ldap3 = "*" gunicorn = "*" werkzeug = "*" sentry-sdk = {extras = ["flask"],version = "==0.14.4"} +flask-mail = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index aca63a57..43163832 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "54d9d51360f54762138a3acc7696badd1d711e7b1dde9e2d82aa706e40c17102" + "sha256": "6c89585086260ebcb41918b8ef3b1d9e189e1b492208d3ff000a138bc2f2fcee" }, "pipfile-spec": 6, "requires": { @@ -104,10 +104,10 @@ }, "celery": { "hashes": [ - "sha256:5147662e23dc6bc39c17a2cbc9a148debe08ecfb128b0eded14a0d9c81fc5742", - "sha256:df2937b7536a2a9b18024776a3a46fd281721813636c03a5177fa02fe66078f6" + "sha256:9ae2e73b93cc7d6b48b56aaf49a68c91752d0ffd7dfdcc47f842ca79a6f13eae", + "sha256:c2037b6a8463da43b19969a0fc13f9023ceca6352b4dd51be01c66fbbb13647e" ], - "version": "==4.4.3" + "version": "==4.4.4" }, "certifi": { "hashes": [ @@ -276,6 +276,13 @@ "index": "pypi", "version": "==3.0.8" }, + "flask-mail": { + "hashes": [ + "sha256:22e5eb9a940bf407bcf30410ecc3708f3c56cc44b29c34e1726fe85006935f41" + ], + "index": "pypi", + "version": "==0.9.1" + }, "flask-marshmallow": { "hashes": [ "sha256:6e6aec171b8e092e0eafaf035ff5b8637bf3a58ab46f568c4c1bab02f2a3c196", @@ -387,10 +394,10 @@ }, "kombu": { "hashes": [ - "sha256:ab0afaa5388dd2979cbc439d3623b86a4f7a58d41f621096bef7767c37bc2505", - "sha256:aece08f48706743aaa1b9d607fee300559481eafcc5ee56451aa0ef867a3be07" + "sha256:437b9cdea193cc2ed0b8044c85fd0f126bb3615ca2f4d4a35b39de7cacfa3c1a", + "sha256:dc282bb277197d723bccda1a9ba30a27a28c9672d0ab93e9e51bb05a37bd29c3" ], - "version": "==4.6.9" + "version": "==4.6.10" }, "ldap3": { "hashes": [ @@ -479,11 +486,11 @@ }, "marshmallow": { "hashes": [ - "sha256:c2673233aa21dde264b84349dc2fd1dce5f30ed724a0a00e75426734de5b84ab", - "sha256:f88fe96434b1f0f476d54224d59333eba8ca1a203a2695683c1855675c4049a7" + "sha256:35ee2fb188f0bd9fc1cf9ac35e45fd394bd1c153cee430745a465ea435514bd5", + "sha256:9aa20f9b71c992b4782dad07c51d92884fd0f7c5cb9d3c737bea17ec1bad765f" ], "index": "pypi", - "version": "==3.6.0" + "version": "==3.6.1" }, "marshmallow-enum": { "hashes": [ @@ -968,11 +975,11 @@ }, "pytest": { "hashes": [ - "sha256:95c710d0a72d91c13fae35dce195633c929c3792f54125919847fdcdf7caa0d3", - "sha256:eb2b5e935f6a019317e455b6da83dd8650ac9ffd2ee73a7b657a30873d67a698" + "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1", + "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8" ], "index": "pypi", - "version": "==5.4.2" + "version": "==5.4.3" }, "six": { "hashes": [ @@ -983,10 +990,10 @@ }, "wcwidth": { "hashes": [ - "sha256:3de2e41158cb650b91f9654cbf9a3e053cee0719c9df4ddc11e4b568669e9829", - "sha256:b651b6b081476420e4e9ae61239ac4c1b49d0c5ace42b2e81dc2ff49ed50c566" + "sha256:980fbf4f3c196c0f329cdcd1e84c554d6a211f18e252e525a0cf4223154a41d6", + "sha256:edbc2b718b4db6cdf393eefe3a420183947d6aa312505ce6754516f458ff8830" ], - "version": "==0.2.2" + "version": "==0.2.3" }, "zipp": { "hashes": [ diff --git a/crc/__init__.py b/crc/__init__.py index e705321b..480ae4b1 100644 --- a/crc/__init__.py +++ b/crc/__init__.py @@ -3,6 +3,7 @@ import os import sentry_sdk import connexion +from jinja2 import Environment, FileSystemLoader from flask_cors import CORS from flask_marshmallow import Marshmallow from flask_migrate import Migrate @@ -48,6 +49,10 @@ if app.config['ENABLE_SENTRY']: integrations=[FlaskIntegration()] ) +# Jinja environment definition, used to render mail templates +template_dir = os.getcwd() + '/crc/static/templates/mails' +env = Environment(loader=FileSystemLoader(template_dir)) + print('=== USING THESE CONFIG SETTINGS: ===') print('DB_HOST = ', ) print('CORS_ALLOW_ORIGINS = ', app.config['CORS_ALLOW_ORIGINS']) diff --git a/crc/services/mails.py b/crc/services/mails.py new file mode 100644 index 00000000..13358768 --- /dev/null +++ b/crc/services/mails.py @@ -0,0 +1,99 @@ +import os + +from crc import app, env +from jinja2 import Environment, FileSystemLoader +from flask import render_template, render_template_string +from flask_mail import Mail, Message + + +# TODO: Extract common mailing code into its own function + +def send_ramp_up_submission_email(sender, recipients, approver_1, approver_2=None): + with app.app_context(): + try: + msg = Message('Research Ramp-up Plan Submitted', + sender=sender, + recipients=recipients) + + template = env.get_template('ramp_up_submission.txt') + template_vars = {'approver_1': approver_1, 'approver_2': approver_2} + msg.body = template.render(template_vars) + template = env.get_template('ramp_up_submission.html') + msg.html = template.render(template_vars) + + mail = Mail(app) + mail.send(msg) + except Exception as e: + app.logger.error(str(e)) + +def send_ramp_up_approval_request_email(sender, recipients, primary_investigator): + with app.app_context(): + try: + msg = Message('Research Ramp-up Plan Approval Request', + sender=sender, + recipients=recipients) + + template = env.get_template('ramp_up_approval_request.txt') + template_vars = {'primary_investigator': primary_investigator} + msg.body = template.render(template_vars) + template = env.get_template('ramp_up_approval_request.html') + msg.html = template.render(template_vars) + + mail = Mail(app) + mail.send(msg) + except Exception as e: + app.logger.error(str(e)) + +def send_ramp_up_approval_request_first_review_email(sender, recipients, primary_investigator, approver): + with app.app_context(): + try: + msg = Message('Research Ramp-up Plan Approval Request', + sender=sender, + recipients=recipients) + + template = env.get_template('ramp_up_approval_request_first_review.txt') + template_vars = {'primary_investigator': primary_investigator, 'approver': approver} + msg.body = template.render(template_vars) + template = env.get_template('ramp_up_approval_request_first_review.html') + msg.html = template.render(template_vars) + + mail = Mail(app) + mail.send(msg) + except Exception as e: + app.logger.error(str(e)) + +def send_ramp_up_approved_email(sender, recipients, approver_1, approver_2=None): + with app.app_context(): + try: + msg = Message('Research Ramp-up Plan Approved', + sender=sender, + recipients=recipients) + + template = env.get_template('ramp_up_approved.txt') + template_vars = {'approver_1': approver_1, 'approver_2': approver_2} + msg.body = template.render(template_vars) + template = env.get_template('ramp_up_approved.html') + msg.html = template.render(template_vars) + + mail = Mail(app) + mail.send(msg) + except Exception as e: + app.logger.error(str(e)) + +def send_ramp_up_denied_email(sender, recipients, approver): + with app.app_context(): + try: + msg = Message('Research Ramp-up Plan Denied', + sender=sender, + recipients=recipients) + + template = env.get_template('ramp_up_denied.txt') + template_vars = {'approver': approver} + msg.body = template.render(template_vars) + template = env.get_template('ramp_up_denied.html') + msg.html = template.render(template_vars) + + mail = Mail(app) + mail.send(msg) + except Exception as e: + app.logger.error(str(e)) diff --git a/crc/static/templates/mails/ramp_up_approval_request.html b/crc/static/templates/mails/ramp_up_approval_request.html new file mode 100644 index 00000000..e78bc6f9 --- /dev/null +++ b/crc/static/templates/mails/ramp_up_approval_request.html @@ -0,0 +1 @@ +

A Research Ramp-up approval request from {{ primary_investigator }} is now available for your review in your [Research Ramp-up Toolkit](https://rrt.uvadcos.io/app/approvals).

\ No newline at end of file diff --git a/crc/static/templates/mails/ramp_up_approval_request.txt b/crc/static/templates/mails/ramp_up_approval_request.txt new file mode 100644 index 00000000..1b7c5a09 --- /dev/null +++ b/crc/static/templates/mails/ramp_up_approval_request.txt @@ -0,0 +1 @@ +A Research Ramp-up approval request from {{ primary_investigator }} is now available for your review in your [Research Ramp-up Toolkit](https://rrt.uvadcos.io/app/approvals). \ No newline at end of file diff --git a/crc/static/templates/mails/ramp_up_approval_request_first_review.html b/crc/static/templates/mails/ramp_up_approval_request_first_review.html new file mode 100644 index 00000000..9d2ac37a --- /dev/null +++ b/crc/static/templates/mails/ramp_up_approval_request_first_review.html @@ -0,0 +1 @@ +

A Research Ramp-up approval request from {{ primary_investigator }} has been approve by {{ approver }} and is now available for your review in your [Research Ramp-up Toolkit](https://rrt.uvadcos.io/app/approvals).

\ No newline at end of file diff --git a/crc/static/templates/mails/ramp_up_approval_request_first_review.txt b/crc/static/templates/mails/ramp_up_approval_request_first_review.txt new file mode 100644 index 00000000..cbe19f87 --- /dev/null +++ b/crc/static/templates/mails/ramp_up_approval_request_first_review.txt @@ -0,0 +1 @@ +A Research Ramp-up approval request from {{ primary_investigator }} has been approve by {{ approver }} and is now available for your review in your [Research Ramp-up Toolkit](https://rrt.uvadcos.io/app/approvals). \ No newline at end of file diff --git a/crc/static/templates/mails/ramp_up_approved.html b/crc/static/templates/mails/ramp_up_approved.html new file mode 100644 index 00000000..57fc1dc4 --- /dev/null +++ b/crc/static/templates/mails/ramp_up_approved.html @@ -0,0 +1 @@ +

Your Research Ramp-up Plan has been approved by {{ approver_1 }} {% if approver_2 %}and {{ approver_2 }} {% endif %}

\ No newline at end of file diff --git a/crc/static/templates/mails/ramp_up_approved.txt b/crc/static/templates/mails/ramp_up_approved.txt new file mode 100644 index 00000000..2eec582b --- /dev/null +++ b/crc/static/templates/mails/ramp_up_approved.txt @@ -0,0 +1 @@ +Your Research Ramp-up Plan has been approved by {{ approver_1 }} {% if approver_2 %}and {{ approver_2 }} {% endif %} \ No newline at end of file diff --git a/crc/static/templates/mails/ramp_up_denied.html b/crc/static/templates/mails/ramp_up_denied.html new file mode 100644 index 00000000..e69de29b diff --git a/crc/static/templates/mails/ramp_up_denied.txt b/crc/static/templates/mails/ramp_up_denied.txt new file mode 100644 index 00000000..e69de29b diff --git a/crc/static/templates/mails/ramp_up_submission.html b/crc/static/templates/mails/ramp_up_submission.html new file mode 100644 index 00000000..2c57c916 --- /dev/null +++ b/crc/static/templates/mails/ramp_up_submission.html @@ -0,0 +1,5 @@ +

Your Research Ramp-up Plan (RRP) has been submitted for review by {{ approver_1 }} {% if approver_2 %}and {{ approver_2 }} {% endif %}. After completion of the review step you will receive email notification of its approval or if additional information and/or modifications are required, along with instructions on how to proceed. Return to the Research Ramp-up Plan application to proceed as instructed.

+ +

In the meantime, please make sure all required training has been completed and needed supplies secured. You will be asked to confirm that both of these requirements have been met before reopening the research space approved in your RRP.

+ +

Additionally, if there are any unknown Area Monitors for the spaces listed in your RRP, please contact your approvers to determine either who they are or how you can find out. Missing Area Monitors will need to be entered before proceeding as well.

diff --git a/crc/static/templates/mails/ramp_up_submission.txt b/crc/static/templates/mails/ramp_up_submission.txt new file mode 100644 index 00000000..14c34500 --- /dev/null +++ b/crc/static/templates/mails/ramp_up_submission.txt @@ -0,0 +1,5 @@ +Your Research Ramp-up Plan (RRP) has been submitted for review by {{ approver_1 }} {% if approver_2 %}and {{ approver_2 }} {% endif %}. After completion of the review step you will receive email notification of its approval or if additional information and/or modifications are required, along with instructions on how to proceed. Return to the Research Ramp-up Plan application to proceed as instructed. + +In the meantime, please make sure all required training has been completed and needed supplies secured. You will be asked to confirm that both of these requirements have been met before reopening the research space approved in your RRP. + +Additionally, if there are any unknown Area Monitors for the spaces listed in your RRP, please contact your approvers to determine either who they are or how you can find out. Missing Area Monitors will need to be entered before proceeding as well. diff --git a/tests/test_mails.py b/tests/test_mails.py new file mode 100644 index 00000000..5e71ecd7 --- /dev/null +++ b/tests/test_mails.py @@ -0,0 +1,48 @@ + +from tests.base_test import BaseTest + +from crc.services.mails import ( + send_ramp_up_submission_email, + send_ramp_up_approval_request_email, + send_ramp_up_approval_request_first_review_email, + send_ramp_up_approved_email, + send_ramp_up_denied_email +) + + +class TestMails(BaseTest): + + def setUp(self): + self.sender = 'sender@sartography.com' + self.recipients = ['recipient@sartography.com'] + self.primary_investigator = 'Dr. Bartlett' + self.approver_1 = 'Max Approver' + self.approver_2 = 'Close Reviewer' + + def test_send_ramp_up_submission_email(self): + send_ramp_up_submission_email(self.sender, self.recipients, self.approver_1) + self.assertTrue(True) + + send_ramp_up_submission_email(self.sender, self.recipients, self.approver_1) + self.assertTrue(True) + + def test_send_ramp_up_approval_request_email(self): + send_ramp_up_approval_request_email(self.sender, self.recipients, self.primary_investigator) + self.assertTrue(True) + + def test_send_ramp_up_approval_request_first_review_email(self): + send_ramp_up_approval_request_first_review_email( + self.sender, self.recipients, self.primary_investigator, self.approver_1 + ) + self.assertTrue(True) + + def test_send_ramp_up_approved_email(self): + send_ramp_up_approved_email(self.sender, self.recipients, self.approver_1) + self.assertTrue(True) + + send_ramp_up_approved_email(self.sender, self.recipients, self.approver_1, self.approver_2) + self.assertTrue(True) + + def test_send_ramp_up_denied_email(self): + send_ramp_up_denied_email(self.sender, self.recipients, self.approver_1) + self.assertTrue(True)