2018-07-06 23:52:19 +02:00
|
|
|
import logging
|
2020-12-04 03:23:04 +01:00
|
|
|
|
2020-12-05 20:52:02 +01:00
|
|
|
from app.tasks.emails import send_user_email
|
2018-07-06 23:52:19 +02:00
|
|
|
|
2020-12-04 03:23:04 +01:00
|
|
|
|
2018-07-06 23:52:19 +02:00
|
|
|
def _has_newline(line):
|
|
|
|
"""Used by has_bad_header to check for \\r or \\n"""
|
|
|
|
if line and ("\r" in line or "\n" in line):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _is_bad_subject(subject):
|
|
|
|
"""Copied from: flask_mail.py class Message def has_bad_headers"""
|
|
|
|
if _has_newline(subject):
|
|
|
|
for linenum, line in enumerate(subject.split("\r\n")):
|
|
|
|
if not line:
|
|
|
|
return True
|
|
|
|
if linenum > 0 and line[0] not in "\t ":
|
|
|
|
return True
|
|
|
|
if _has_newline(line):
|
|
|
|
return True
|
|
|
|
if len(line.strip()) == 0:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
class FlaskMailSubjectFormatter(logging.Formatter):
|
|
|
|
def format(self, record):
|
|
|
|
record.message = record.getMessage()
|
|
|
|
if self.usesTime():
|
|
|
|
record.asctime = self.formatTime(record, self.datefmt)
|
|
|
|
s = self.formatMessage(record)
|
|
|
|
return s
|
|
|
|
|
|
|
|
class FlaskMailTextFormatter(logging.Formatter):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class FlaskMailHTMLFormatter(logging.Formatter):
|
|
|
|
def formatException(self, exc_info):
|
|
|
|
formatted_exception = logging.Handler.formatException(self, exc_info)
|
2020-12-07 19:06:34 +01:00
|
|
|
return "<pre>%s</pre>" % formatted_exception
|
2018-07-06 23:52:19 +02:00
|
|
|
def formatStack(self, stack_info):
|
2020-12-03 23:59:13 +01:00
|
|
|
return "<pre>%s</pre>" % stack_info
|
2018-07-06 23:52:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
# see: https://github.com/python/cpython/blob/3.6/Lib/logging/__init__.py (class Handler)
|
|
|
|
|
|
|
|
class FlaskMailHandler(logging.Handler):
|
2020-12-07 19:06:34 +01:00
|
|
|
def __init__(self, send_to, subject_template, level=logging.NOTSET):
|
2018-07-06 23:52:19 +02:00
|
|
|
logging.Handler.__init__(self, level)
|
2020-12-07 19:06:34 +01:00
|
|
|
self.send_to = send_to
|
2018-07-06 23:52:19 +02:00
|
|
|
self.subject_template = subject_template
|
|
|
|
|
2020-12-07 19:06:34 +01:00
|
|
|
def setFormatter(self, text_fmt):
|
2018-07-06 23:52:19 +02:00
|
|
|
"""
|
|
|
|
Set the formatters for this handler. Provide at least one formatter.
|
|
|
|
When no text_fmt is provided, no text-part is created for the email body.
|
|
|
|
"""
|
2020-12-07 19:06:34 +01:00
|
|
|
assert text_fmt != None, "At least one formatter should be provided"
|
2018-07-06 23:52:19 +02:00
|
|
|
if type(text_fmt)==str:
|
|
|
|
text_fmt = FlaskMailTextFormatter(text_fmt)
|
|
|
|
self.formatter = text_fmt
|
|
|
|
|
|
|
|
def getSubject(self, record):
|
|
|
|
fmt = FlaskMailSubjectFormatter(self.subject_template)
|
|
|
|
subject = fmt.format(record)
|
2020-12-07 19:06:34 +01:00
|
|
|
# Since templates can cause header problems, and we rather have a incomplete email then an error, we fix this
|
2018-07-06 23:52:19 +02:00
|
|
|
if _is_bad_subject(subject):
|
2020-12-07 19:06:34 +01:00
|
|
|
subject="FlaskMailHandler log-entry from ContentDB [original subject is replaced, because it would result in a bad header]"
|
2018-07-06 23:52:19 +02:00
|
|
|
return subject
|
|
|
|
|
|
|
|
def emit(self, record):
|
|
|
|
text = self.format(record) if self.formatter else None
|
2020-12-07 19:06:34 +01:00
|
|
|
html = "<pre>{}</pre>".format(text)
|
2020-12-05 21:36:09 +01:00
|
|
|
for email in self.send_to:
|
|
|
|
send_user_email.delay(email, self.getSubject(record), text, html)
|
2018-07-06 23:52:19 +02:00
|
|
|
|
|
|
|
|
2020-12-07 19:06:34 +01:00
|
|
|
def build_handler(app):
|
2020-12-03 23:59:13 +01:00
|
|
|
subject_template = "ContentDB %(message)s (%(module)s > %(funcName)s)"
|
2020-12-07 19:06:34 +01:00
|
|
|
text_template = ("Message type: %(levelname)s\n"
|
|
|
|
"Location: %(pathname)s:%(lineno)d\n"
|
|
|
|
"Module: %(module)s\n"
|
|
|
|
"Function: %(funcName)s\n"
|
|
|
|
"Time: %(asctime)s\n"
|
|
|
|
"Message: %(message)s\n\n")
|
|
|
|
|
|
|
|
mail_handler = FlaskMailHandler(app.config["MAIL_UTILS_ERROR_SEND_TO"], subject_template)
|
2018-07-06 23:52:19 +02:00
|
|
|
mail_handler.setLevel(logging.ERROR)
|
2020-12-07 19:06:34 +01:00
|
|
|
mail_handler.setFormatter(text_template)
|
|
|
|
return mail_handler
|