From 450deae32aa302345b6307f703657299d19465e4 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Thu, 15 Feb 2018 14:16:16 +0000 Subject: [PATCH] add user_to_organisation and invited_organisation_users tables similar to user_to_service and invited_users, but without auth types or permissions --- app/models.py | 51 ++++++++++++++++-- .../versions/0166_add_org_user_stuff.py | 53 +++++++++++++++++++ tests/conftest.py | 7 --- 3 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 migrations/versions/0166_add_org_user_stuff.py diff --git a/app/models.py b/app/models.py index 9d3332d95..c3cff0684 100644 --- a/app/models.py +++ b/app/models.py @@ -137,6 +137,16 @@ user_to_service = db.Table( UniqueConstraint('user_id', 'service_id', name='uix_user_to_service') ) + +user_to_organisation = db.Table( + 'user_to_organisation', + db.Model.metadata, + db.Column('user_id', UUID(as_uuid=True), db.ForeignKey('users.id')), + db.Column('organisation_id', UUID(as_uuid=True), db.ForeignKey('organisation.id')), + UniqueConstraint('user_id', 'organisation_id', name='uix_user_to_organisation') +) + + BRANDING_GOVUK = 'govuk' BRANDING_ORG = 'org' BRANDING_BOTH = 'both' @@ -237,6 +247,11 @@ class Organisation(db.Model): secondary='organisation_to_service', uselist=True) + users = db.relationship( + 'User', + secondary='user_to_organisation', + backref=db.backref('organisations', lazy='dynamic')) + def serialize(self): serialized = { "id": str(self.id), @@ -1362,9 +1377,6 @@ class NotificationHistory(db.Model, HistoryModel): self.status = original.status -INVITED_USER_STATUS_TYPES = ['pending', 'accepted', 'cancelled'] - - class ScheduledNotification(db.Model): __tablename__ = 'scheduled_notifications' @@ -1375,6 +1387,18 @@ class ScheduledNotification(db.Model): pending = db.Column(db.Boolean, nullable=False, default=True) +INVITE_PENDING = 'pending' +INVITE_ACCEPTED = 'accepted' +INVITE_CANCELLED = 'cancelled' +INVITED_USER_STATUS_TYPES = [INVITE_PENDING, INVITE_ACCEPTED, INVITE_CANCELLED] + + +class InviteStatusType(db.Model): + __tablename__ = 'invite_status_type' + + name = db.Column(db.String, primary_key=True) + + class InvitedUser(db.Model): __tablename__ = 'invited_users' @@ -1391,7 +1415,7 @@ class InvitedUser(db.Model): nullable=False, default=datetime.datetime.utcnow) status = db.Column( - db.Enum(*INVITED_USER_STATUS_TYPES, name='invited_users_status_types'), nullable=False, default='pending') + db.Enum(*INVITED_USER_STATUS_TYPES, name='invited_users_status_types'), nullable=False, default=INVITE_PENDING) permissions = db.Column(db.String, nullable=False) auth_type = db.Column( db.String, @@ -1407,6 +1431,25 @@ class InvitedUser(db.Model): return self.permissions.split(',') +class InvitedOrganisationUser(db.Model): + __tablename__ = 'invited_organisation_users' + + id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + email_address = db.Column(db.String(255), nullable=False) + invited_by_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), nullable=False) + invited_by = db.relationship('User') + organisation_id = db.Column(UUID(as_uuid=True), db.ForeignKey('organisation.id'), nullable=False) + organisation = db.relationship('Organisation') + created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow) + + status = db.Column( + db.String, + db.ForeignKey('invite_status_type.name'), + nullable=False, + default=INVITE_PENDING + ) + + # Service Permissions MANAGE_USERS = 'manage_users' MANAGE_TEMPLATES = 'manage_templates' diff --git a/migrations/versions/0166_add_org_user_stuff.py b/migrations/versions/0166_add_org_user_stuff.py new file mode 100644 index 000000000..539338830 --- /dev/null +++ b/migrations/versions/0166_add_org_user_stuff.py @@ -0,0 +1,53 @@ +""" + +Revision ID: 0166_add_org_user_stuff +Revises: 0165_another_letter_org +Create Date: 2018-02-14 17:25:11.747996 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +revision = '0166_add_org_user_stuff' +down_revision = '0165_another_letter_org' + + +def upgrade(): + op.create_table('invite_status_type', + sa.Column('name', sa.String(), nullable=False), + sa.PrimaryKeyConstraint('name') + ) + + op.execute("insert into invite_status_type values ('pending'), ('accepted'), ('cancelled')") + + op.create_table('invited_organisation_users', + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('email_address', sa.String(length=255), nullable=False), + sa.Column('invited_by_id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('organisation_id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=False), + sa.Column('status', sa.String(), nullable=False), + + sa.ForeignKeyConstraint(['invited_by_id'], ['users.id'], ), + sa.ForeignKeyConstraint(['organisation_id'], ['organisation.id'], ), + sa.ForeignKeyConstraint(['status'], ['invite_status_type.name'], ), + sa.PrimaryKeyConstraint('id') + ) + + op.create_table('user_to_organisation', + sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=True), + sa.Column('organisation_id', postgresql.UUID(as_uuid=True), nullable=True), + + sa.ForeignKeyConstraint(['organisation_id'], ['organisation.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.UniqueConstraint('user_id', 'organisation_id', name='uix_user_to_organisation') + ) + + op.create_unique_constraint(None, 'organisation_to_service', columns=['service_id', 'organisation_id']) + + +def downgrade(): + op.drop_table('user_to_organisation') + op.drop_table('invited_organisation_users') + op.drop_table('invite_status_type') diff --git a/tests/conftest.py b/tests/conftest.py index 266346ba9..8f3972d2d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,7 +4,6 @@ import os from flask import Flask from alembic.command import upgrade from alembic.config import Config -import boto3 import pytest import sqlalchemy @@ -128,12 +127,6 @@ def os_environ(): os.environ = old_env -@pytest.fixture(scope='function') -def sqs_client_conn(): - boto3.setup_default_session(region_name='eu-west-1') - return boto3.resource('sqs') - - def pytest_generate_tests(metafunc): # Copied from https://gist.github.com/pfctdayelise/5719730 idparametrize = getattr(metafunc.function, 'idparametrize', None)