mirror of
https://github.com/GSA/notifications-api.git
synced 2026-06-22 06:01:04 -04:00
add broadcast_message to database
new broadcast_message table. contains a whole bunch of timestamps, a couple of user ids for who created and who approved, some personalisation and a template id/version. areas is a jsonb field - it is expected that this will be an array, for example `["england", "wales"]` intended valid state transitions are as follows, from an initial status of draft * draft -> pending-approval, rejected * pending-approval -> broadcasting, rejected, (draft maybe) * broadcasting -> completed, cancelled rejected, completed, cancelled and technical-failure are terminating states. also copy across the enum switching code from migration 0060 (adding letter type).
This commit is contained in:
@@ -2148,3 +2148,65 @@ class ServiceContactList(db.Model):
|
||||
"created_at": created_at_in_bst.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
return contact_list
|
||||
|
||||
|
||||
class BroadcastStatusType(db.Model):
|
||||
__tablename__ = 'broadcast_status_type'
|
||||
DRAFT = 'draft'
|
||||
PENDING_APPROVAL = 'pending-approval'
|
||||
REJECTED = 'rejected'
|
||||
BROADCASTING = 'broadcasting'
|
||||
COMPLETED = 'completed'
|
||||
CANCELLED = 'cancelled'
|
||||
TECHNICAL_FAILURE = 'technical-failure'
|
||||
|
||||
STATUSES = [DRAFT, PENDING_APPROVAL, REJECTED, BROADCASTING, COMPLETED, CANCELLED, TECHNICAL_FAILURE]
|
||||
|
||||
name = db.Column(db.String, primary_key=True)
|
||||
|
||||
|
||||
class BroadcastMessage(db.Model):
|
||||
__tablename__ = 'broadcast_message'
|
||||
__table_args__ = (
|
||||
db.ForeignKeyConstraint(
|
||||
['template_id', 'template_version'],
|
||||
['templates_history.id', 'templates_history.version'],
|
||||
),
|
||||
{}
|
||||
)
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True)
|
||||
|
||||
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'))
|
||||
service = db.relationship('Service', backref='broadcast_messages')
|
||||
|
||||
template_id = db.Column(UUID(as_uuid=True), nullable=False)
|
||||
template_version = db.Column(db.Integer, nullable=False)
|
||||
template = db.relationship('TemplateHistory', backref='broadcast_messages')
|
||||
|
||||
_personalisation = db.Column(db.String, nullable=True)
|
||||
|
||||
status = db.Column(
|
||||
db.String,
|
||||
db.ForeignKey('broadcast_status_type.name'),
|
||||
nullable=False,
|
||||
default=BroadcastStatusType.DRAFT
|
||||
)
|
||||
|
||||
# these times are related to the actual broadcast, rather than auditing purposes
|
||||
starts_at = db.Column(db.DateTime, nullable=True)
|
||||
finishes_at = db.Column(db.DateTime, nullable=True) # isn't updated if user cancels
|
||||
|
||||
# these times correspond to when
|
||||
created_at = db.Column(db.DateTime, nullable=False)
|
||||
approved_at = db.Column(db.DateTime, nullable=True)
|
||||
cancelled_at = db.Column(db.DateTime, nullable=True)
|
||||
updated_at = db.Column(db.DateTime, nullable=True, onupdate=datetime.datetime.utcnow)
|
||||
|
||||
created_by_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), nullable=False)
|
||||
approved_by_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), nullable=True)
|
||||
cancelled_by_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), nullable=True)
|
||||
|
||||
created_by = db.relationship('User', foreign_keys=[created_by_id])
|
||||
approved_by = db.relationship('User', foreign_keys=[approved_by_id])
|
||||
cancelled_by = db.relationship('User', foreign_keys=[cancelled_by_id])
|
||||
|
||||
98
migrations/versions/0323_broadcast_message.py
Normal file
98
migrations/versions/0323_broadcast_message.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""
|
||||
|
||||
Revision ID: 0323_broadcast_message
|
||||
Revises: 0322_broadcast_service_perm
|
||||
Create Date: 2020-07-02 11:59:38.734650
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.sql import column, func
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
from app.models import BroadcastMessage
|
||||
|
||||
revision = '0323_broadcast_message'
|
||||
down_revision = '0322_broadcast_service_perm'
|
||||
|
||||
|
||||
name = 'template_type'
|
||||
tmp_name = 'tmp_' + name
|
||||
|
||||
old_options = ('sms', 'email', 'letter')
|
||||
new_options = old_options + ('broadcast',)
|
||||
|
||||
new_type = sa.Enum(*new_options, name=name)
|
||||
old_type = sa.Enum(*old_options, name=name)
|
||||
|
||||
|
||||
STATUSES = [
|
||||
'draft',
|
||||
'pending-approval',
|
||||
'rejected',
|
||||
'broadcasting',
|
||||
'completed',
|
||||
'cancelled',
|
||||
'technical-failure',
|
||||
]
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.execute(f'ALTER TYPE {name} RENAME TO {tmp_name}')
|
||||
new_type.create(op.get_bind())
|
||||
|
||||
for table in ['templates', 'templates_history', 'service_contact_list']:
|
||||
op.execute(f'ALTER TABLE {table} ALTER COLUMN template_type TYPE {name} USING template_type::text::{name}')
|
||||
|
||||
op.execute(f'DROP TYPE {tmp_name}')
|
||||
|
||||
broadcast_status_type = op.create_table(
|
||||
'broadcast_status_type',
|
||||
sa.Column('name', sa.String(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('name')
|
||||
)
|
||||
op.bulk_insert(broadcast_status_type, [{'name': state} for state in STATUSES])
|
||||
|
||||
op.create_table(
|
||||
'broadcast_message',
|
||||
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('service_id', postgresql.UUID(as_uuid=True)),
|
||||
sa.Column('template_id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('template_version', sa.Integer(), nullable=False),
|
||||
sa.Column('_personalisation', sa.String()),
|
||||
sa.Column('areas', postgresql.JSONB(none_as_null=True, astext_type=sa.Text())),
|
||||
sa.Column('status', sa.String()),
|
||||
sa.Column('starts_at', sa.DateTime()),
|
||||
sa.Column('finishes_at', sa.DateTime()),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('approved_at', sa.DateTime()),
|
||||
sa.Column('cancelled_at', sa.DateTime()),
|
||||
sa.Column('updated_at', sa.DateTime()),
|
||||
sa.Column('created_by_id', postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('approved_by_id', postgresql.UUID(as_uuid=True)),
|
||||
sa.Column('cancelled_by_id', postgresql.UUID(as_uuid=True)),
|
||||
|
||||
sa.ForeignKeyConstraint(['approved_by_id'], ['users.id'], ),
|
||||
sa.ForeignKeyConstraint(['cancelled_by_id'], ['users.id'], ),
|
||||
sa.ForeignKeyConstraint(['created_by_id'], ['users.id'], ),
|
||||
sa.ForeignKeyConstraint(['service_id'], ['services.id'], ),
|
||||
sa.ForeignKeyConstraint(['template_id', 'template_version'], ['templates_history.id', 'templates_history.version'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
op.add_column('templates', sa.Column('broadcast_data', postgresql.JSONB(none_as_null=True, astext_type=sa.Text())))
|
||||
op.add_column('templates_history', sa.Column('broadcast_data', postgresql.JSONB(none_as_null=True, astext_type=sa.Text())))
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.execute(f'ALTER TYPE {name} RENAME TO {tmp_name}')
|
||||
old_type.create(op.get_bind())
|
||||
|
||||
for table in ['templates', 'templates_history', 'service_contact_list']:
|
||||
op.execute(f'ALTER TABLE {table} ALTER COLUMN template_type TYPE {name} USING template_type::text::{name}')
|
||||
op.execute(f'DROP TYPE {tmp_name}')
|
||||
|
||||
op.drop_column('templates_history', 'broadcast_data')
|
||||
op.drop_column('templates', 'broadcast_data')
|
||||
op.drop_table('broadcast_message')
|
||||
op.drop_table('broadcast_status_type')
|
||||
@@ -212,6 +212,7 @@ def test_should_raise_error_if_service_does_not_exist_on_create(client, sample_u
|
||||
|
||||
|
||||
@pytest.mark.parametrize('permissions, template_type, subject, expected_error', [
|
||||
([EMAIL_TYPE, SMS_TYPE, LETTER_TYPE], BROADCAST_TYPE, None, {'template_type': ['Creating broadcast message templates is not allowed']}), # noqa
|
||||
([EMAIL_TYPE], SMS_TYPE, None, {'template_type': ['Creating text message templates is not allowed']}),
|
||||
([SMS_TYPE], EMAIL_TYPE, 'subject', {'template_type': ['Creating email templates is not allowed']}),
|
||||
([SMS_TYPE], LETTER_TYPE, 'subject', {'template_type': ['Creating letter templates is not allowed']}),
|
||||
|
||||
Reference in New Issue
Block a user