diff --git a/alembic/versions/404bb5bb3a0e_add_notification_recipients.py b/alembic/versions/404bb5bb3a0e_add_notification_recipients.py new file mode 100644 index 00000000..b8127705 --- /dev/null +++ b/alembic/versions/404bb5bb3a0e_add_notification_recipients.py @@ -0,0 +1,34 @@ +"""add_notification_recipients + +Revision ID: 404bb5bb3a0e +Revises: 432c5287256d +Create Date: 2019-05-10 15:25:22.627996 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '404bb5bb3a0e' +down_revision = '432c5287256d' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('notification_recipients', + sa.Column('time_created', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.Column('time_updated', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False), + sa.Column('id', postgresql.UUID(as_uuid=True), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('email', sa.String(), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('notification_recipients') + # ### end Alembic commands ### diff --git a/atst/models/__init__.py b/atst/models/__init__.py index 8a3cdbfa..e3fc7e1c 100644 --- a/atst/models/__init__.py +++ b/atst/models/__init__.py @@ -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 diff --git a/atst/models/notification_recipient.py b/atst/models/notification_recipient.py new file mode 100644 index 00000000..72b55cbe --- /dev/null +++ b/atst/models/notification_recipient.py @@ -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) diff --git a/atst/utils/notification_sender.py b/atst/utils/notification_sender.py new file mode 100644 index 00000000..0260993f --- /dev/null +++ b/atst/utils/notification_sender.py @@ -0,0 +1,20 @@ +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_mail(recipients, self.EMAIL_SUBJECT, body) + + def _get_recipients(self, type_): + return [ + recipient.email + for recipient in db.session.query(NotificationRecipient).all() + ] diff --git a/tests/factories.py b/tests/factories.py index 8bdf9310..d9de9c97 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -318,3 +318,10 @@ class DD254Factory(Base): required_distribution = factory.LazyFunction( lambda: [random_choice(data.REQUIRED_DISTRIBUTIONS)] ) + + +class NotificationRecipientFactory(Base): + class Meta: + model = NotificationRecipient + + email = factory.Faker("email") diff --git a/tests/utils/test_notification_sender.py b/tests/utils/test_notification_sender.py new file mode 100644 index 00000000..d0f7150a --- /dev/null +++ b/tests/utils/test_notification_sender.py @@ -0,0 +1,27 @@ +import pytest +from unittest.mock import Mock + +from tests.factories import NotificationRecipientFactory +from atst.utils.notification_sender import NotificationSender + + +@pytest.fixture +def mock_queue(queue): + return Mock(spec=queue) + + +@pytest.fixture +def notification_sender(mock_queue): + return NotificationSender(mock_queue) + + +def test_can_send_notification(mock_queue, notification_sender): + recipient_email = "test@example.com" + email_body = "This is a test" + + NotificationRecipientFactory.create(email=recipient_email) + notification_sender.send(email_body) + + mock_queue.send_mail.assert_called_once_with( + ["test@example.com"], notification_sender.EMAIL_SUBJECT, email_body + )