Merge pull request #827 from dod-ccpo/stig-notifications
Create Notification System
This commit is contained in:
@@ -29,6 +29,7 @@ from atst.utils import mailer
|
||||
from atst.utils.form_cache import FormCache
|
||||
from atst.utils.json import CustomJSONEncoder
|
||||
from atst.queue import queue
|
||||
from atst.utils.notification_sender import NotificationSender
|
||||
|
||||
from logging.config import dictConfig
|
||||
from atst.utils.logging import JsonFormatter, RequestContextFilter
|
||||
@@ -63,6 +64,7 @@ def make_app(config):
|
||||
make_csp_provider(app)
|
||||
make_crl_validator(app)
|
||||
make_mailer(app)
|
||||
make_notification_sender(app)
|
||||
queue.init_app(app)
|
||||
|
||||
db.init_app(app)
|
||||
@@ -247,6 +249,10 @@ def make_mailer(app):
|
||||
app.mailer = mailer.Mailer(mailer_connection, sender)
|
||||
|
||||
|
||||
def make_notification_sender(app):
|
||||
app.notification_sender = NotificationSender(queue)
|
||||
|
||||
|
||||
def apply_json_logger():
|
||||
dictConfig(
|
||||
{
|
||||
|
||||
@@ -17,5 +17,6 @@ from .portfolio_invitation import PortfolioInvitation
|
||||
from .application_invitation import ApplicationInvitation
|
||||
from .task_order import TaskOrder
|
||||
from .dd_254 import DD254
|
||||
from .notification_recipient import NotificationRecipient
|
||||
|
||||
from .mixins.invites import Status as InvitationStatus
|
||||
|
||||
10
atst/models/notification_recipient.py
Normal file
10
atst/models/notification_recipient.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from sqlalchemy import String, Column
|
||||
|
||||
from atst.models import Base, types, mixins
|
||||
|
||||
|
||||
class NotificationRecipient(Base, mixins.TimestampsMixin):
|
||||
__tablename__ = "notification_recipients"
|
||||
|
||||
id = types.Id()
|
||||
email = Column(String, nullable=False)
|
||||
@@ -30,6 +30,9 @@ class ATSTQueue(RQ):
|
||||
def send_mail(self, recipients, subject, body):
|
||||
self._queue_job(ATSTQueue._send_mail, recipients, subject, body)
|
||||
|
||||
def send_notification_mail(self, recipients, subject, body):
|
||||
self._queue_job(ATSTQueue._send_notification_mail, recipients, subject, body)
|
||||
|
||||
# pylint: disable=pointless-string-statement
|
||||
"""Class methods to actually perform the work.
|
||||
|
||||
@@ -41,5 +44,14 @@ class ATSTQueue(RQ):
|
||||
def _send_mail(self, recipients, subject, body):
|
||||
app.mailer.send(recipients, subject, body)
|
||||
|
||||
@classmethod
|
||||
def _send_notification_mail(self, recipients, subject, body):
|
||||
app.logger.info(
|
||||
"Sending a notification to these recipients: {}\n\n{}".format(
|
||||
recipients, body
|
||||
)
|
||||
)
|
||||
app.mailer.send(recipients, subject, body)
|
||||
|
||||
|
||||
queue = ATSTQueue()
|
||||
|
||||
@@ -12,14 +12,22 @@ from atst.domain.authnid.crl import CRLInvalidException
|
||||
from atst.domain.portfolios import PortfolioError
|
||||
from atst.utils.flash import formatted_flash as flash
|
||||
|
||||
NO_NOTIFY_STATUS_CODES = set([404, 401])
|
||||
|
||||
|
||||
def log_error(e):
|
||||
error_message = e.message if hasattr(e, "message") else str(e)
|
||||
current_app.logger.exception(error_message)
|
||||
|
||||
|
||||
def notify(e, message, code):
|
||||
if code not in NO_NOTIFY_STATUS_CODES:
|
||||
current_app.notification_sender.send(message)
|
||||
|
||||
|
||||
def handle_error(e, message="Not Found", code=404):
|
||||
log_error(e)
|
||||
notify(e, message, code)
|
||||
return render_template("error.html", message=message), code
|
||||
|
||||
|
||||
@@ -56,13 +64,9 @@ def make_error_pages(app):
|
||||
@app.errorhandler(Exception)
|
||||
# pylint: disable=unused-variable
|
||||
def exception(e):
|
||||
log_error(e)
|
||||
if current_app.debug:
|
||||
raise e
|
||||
return (
|
||||
render_template("error.html", message="An Unexpected Error Occurred"),
|
||||
500,
|
||||
)
|
||||
return handle_error(e, message="An Unexpected Error Occurred", code=500)
|
||||
|
||||
@app.errorhandler(InvitationError)
|
||||
@app.errorhandler(InvitationWrongUserError)
|
||||
|
||||
20
atst/utils/notification_sender.py
Normal file
20
atst/utils/notification_sender.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from sqlalchemy import select
|
||||
|
||||
from atst.queue import ATSTQueue
|
||||
from atst.database import db
|
||||
from atst.models import NotificationRecipient
|
||||
|
||||
|
||||
class NotificationSender(object):
|
||||
EMAIL_SUBJECT = "ATST notification"
|
||||
|
||||
def __init__(self, queue: ATSTQueue):
|
||||
self.queue = queue
|
||||
|
||||
def send(self, body, type_=None):
|
||||
recipients = self._get_recipients(type_)
|
||||
self.queue.send_notification_mail(recipients, self.EMAIL_SUBJECT, body)
|
||||
|
||||
def _get_recipients(self, type_):
|
||||
query = select([NotificationRecipient.email])
|
||||
return db.session.execute(query).fetchone()
|
||||
Reference in New Issue
Block a user