Modified email script and email_service to accommodate new bcc, reply_to, and attachments arguments

Modified the email script description to add the new arguments
Cleaned up some import statements
This commit is contained in:
mike cullerton 2021-08-19 17:34:55 -04:00
parent ef9fd9514d
commit 32c72c5a40
2 changed files with 79 additions and 22 deletions

View File

@ -1,29 +1,42 @@
import sys
import traceback
from crc import app
from crc import app, session
from crc.api.common import ApiError
from crc.models.file import FileModel, CONTENT_TYPES
from crc.models.workflow import WorkflowModel
from crc.services.document_service import DocumentService
from crc.scripts.script import Script
from crc.services.ldap_service import LdapService
from crc.services.email_service import EmailService
from crc.services.ldap_service import LdapService
from crc.services.study_service import StudyService
class Email(Script):
"""This Script allows to be introduced as part of a workflow and called from there, specifying
recipients and content """
"""Send an email from a script task, as part of a workflow.
You must specify recipients and content.
You can also specify cc, bcc, reply_to, and attachments"""
def get_description(self):
return """
Creates an email, using the provided `subject`, `recipients`, and `cc` arguments.
The recipients and cc arguments can contain an email address or list of email addresses.
Creates an email, using the provided `subject` and `recipients` arguments, which are required.
The `Element Documentation` field in the script task must contain markdown that becomes the body of the email message.
You can also provide `cc`, `bcc`, `reply_to` and `attachments` arguments.
The cc, bcc, reply_to, and attachments arguments are not required.
The recipients, cc, and bcc arguments can contain an email address or list of email addresses.
In place of an email address, we accept the string 'associated', in which case we
look up the users associated with the study who have send_email set to True.
The cc argument is not required.
The "documentation" should contain markdown that will become the body of the email message.
The reply_to argument can contain an email address.
The attachments arguments can contain a doc_code or list of doc_codes.
Examples:
email(subject="My Subject", recipients=["dhf8r@virginia.edu", pi.email, 'associated'])
email (subject="My Subject", recipients=["dhf8r@virginia.edu", pi.email], cc='associated')
email(subject="My Subject", recipients="user@example.com", cc='associated', bcc='test_user@example.com)
email(subject="My Subject", recipients="user@example.com", reply_to="reply_to@example.com")
email(subject="My Subject", recipients="user@example.com", attachments='Study_App_Doc')
email(subject="My Subject", recipients="user@example.com", attachments=['Study_App_Doc','Study_Protocol_Document'])
"""
def do_task_validate_only(self, task, study_id, workflow_id, *args, **kwargs):
@ -37,8 +50,17 @@ email (subject="My Subject", recipients=["dhf8r@virginia.edu", pi.email], cc='as
subject = self.get_subject(kwargs['subject'])
recipients = self.get_email_addresses(kwargs['recipients'], study_id)
cc = []
bcc = []
reply_to = None
files = None
if 'cc' in kwargs and kwargs['cc'] is not None:
cc = self.get_email_addresses(kwargs['cc'], study_id)
if 'bcc' in kwargs and kwargs['bcc'] is not None:
bcc = self.get_email_addresses(kwargs['bcc'], study_id)
if 'reply_to' in kwargs:
reply_to = kwargs['reply_to']
if 'attachments' in kwargs:
files = self.get_files(kwargs['attachments'], study_id)
else:
raise ApiError(code="missing_argument",
@ -56,7 +78,10 @@ email (subject="My Subject", recipients=["dhf8r@virginia.edu", pi.email], cc='as
content=content,
content_html=content_html,
cc=cc,
study_id=study_id
bcc=bcc,
study_id=study_id,
reply_to=reply_to,
attachment_files=files
)
except Exception as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
@ -118,3 +143,31 @@ email (subject="My Subject", recipients=["dhf8r@virginia.edu", pi.email], cc='as
user_info = LdapService.user_info(associate.uid)
associated_emails.append(user_info.email_address)
return associated_emails
@staticmethod
def get_files(attachments, study_id):
files = []
codes = None
if isinstance(attachments, str):
codes = [attachments]
elif isinstance(attachments, list):
codes = attachments
if codes is not None:
for code in codes:
if DocumentService.is_allowed_document(code):
workflows = session.query(WorkflowModel).filter(WorkflowModel.study_id==study_id).all()
for workflow in workflows:
workflow_files = session.query(FileModel).\
filter(FileModel.workflow_id == workflow.id).\
filter(FileModel.irb_doc_code == code).all()
for file in workflow_files:
files.append({'id': file.id, 'name': file.name, 'type': CONTENT_TYPES[file.type.value]})
else:
raise ApiError(code='bad_doc_code',
message=f'The doc_code {code} is not valid.')
else:
raise ApiError(code='bad_argument_type',
message='The attachments argument must be a string or list of strings')
return files

View File

@ -1,25 +1,23 @@
import markdown
import re
from datetime import datetime
from flask import render_template, request
from flask import render_template
from flask_mail import Message
from jinja2 import Template
from sqlalchemy import desc
from crc import app, db, mail, session
from crc.api.common import ApiError
from crc.models.study import StudyModel
from crc.models.email import EmailModel
from crc.models.file import FileDataModel
from crc.models.study import StudyModel
class EmailService(object):
"""Provides common tools for working with an Email"""
@staticmethod
def add_email(subject, sender, recipients, content, content_html, cc=None, study_id=None):
def add_email(subject, sender, recipients, content, content_html,
cc=None, bcc=None, study_id=None, reply_to=None, attachment_files=None):
"""We will receive all data related to an email and store it"""
# Find corresponding study - if any
@ -35,11 +33,17 @@ class EmailService(object):
try:
msg = Message(subject,
sender=sender,
recipients=recipients)
recipients=recipients,
body=content,
html=content_html,
cc=cc,
bcc=bcc,
reply_to=reply_to)
msg.body = content
msg.html = content_html
msg.cc = cc
if attachment_files is not None:
for file in attachment_files:
file_data = session.query(FileDataModel).filter(FileDataModel.file_model_id==file['id']).first()
msg.attach(file['name'], file['type'], file_data.data)
mail.send(msg)
except Exception as e: