Merge pull request #1672 from alphagov/org-users

Org user DB models
This commit is contained in:
Leo Hemsted
2018-02-16 10:57:27 +00:00
committed by GitHub
5 changed files with 108 additions and 12 deletions

View File

@@ -137,6 +137,16 @@ user_to_service = db.Table(
UniqueConstraint('user_id', 'service_id', name='uix_user_to_service') 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_GOVUK = 'govuk'
BRANDING_ORG = 'org' BRANDING_ORG = 'org'
BRANDING_BOTH = 'both' BRANDING_BOTH = 'both'
@@ -237,6 +247,11 @@ class Organisation(db.Model):
secondary='organisation_to_service', secondary='organisation_to_service',
uselist=True) uselist=True)
users = db.relationship(
'User',
secondary='user_to_organisation',
backref=db.backref('organisations', lazy='dynamic'))
def serialize(self): def serialize(self):
serialized = { serialized = {
"id": str(self.id), "id": str(self.id),
@@ -1362,9 +1377,6 @@ class NotificationHistory(db.Model, HistoryModel):
self.status = original.status self.status = original.status
INVITED_USER_STATUS_TYPES = ['pending', 'accepted', 'cancelled']
class ScheduledNotification(db.Model): class ScheduledNotification(db.Model):
__tablename__ = 'scheduled_notifications' __tablename__ = 'scheduled_notifications'
@@ -1375,6 +1387,18 @@ class ScheduledNotification(db.Model):
pending = db.Column(db.Boolean, nullable=False, default=True) 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): class InvitedUser(db.Model):
__tablename__ = 'invited_users' __tablename__ = 'invited_users'
@@ -1391,7 +1415,7 @@ class InvitedUser(db.Model):
nullable=False, nullable=False,
default=datetime.datetime.utcnow) default=datetime.datetime.utcnow)
status = db.Column( 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) permissions = db.Column(db.String, nullable=False)
auth_type = db.Column( auth_type = db.Column(
db.String, db.String,
@@ -1407,6 +1431,25 @@ class InvitedUser(db.Model):
return self.permissions.split(',') 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 # Service Permissions
MANAGE_USERS = 'manage_users' MANAGE_USERS = 'manage_users'
MANAGE_TEMPLATES = 'manage_templates' MANAGE_TEMPLATES = 'manage_templates'

View File

@@ -32,6 +32,13 @@ def upgrade():
unique=True) unique=True)
op.create_index(op.f('ix_service_sms_senders_service_id'), 'service_sms_senders', ['service_id'], unique=True) op.create_index(op.f('ix_service_sms_senders_service_id'), 'service_sms_senders', ['service_id'], unique=True)
# populate govuk seeded service
op.execute("""
INSERT INTO service_sms_senders
(id, sms_sender, service_id, is_default, inbound_number_id, created_at, updated_at)
VALUES ('286d6176-adbe-7ea7-ba26-b7606ee5e2a4', 'GOVUK', 'd6aa2c68-a2d9-4437-ab19-3ae8eb202553', true, null, now(), null)
""")
def downgrade(): def downgrade():
op.drop_index(op.f('ix_service_sms_senders_service_id'), table_name='service_sms_senders') op.drop_index(op.f('ix_service_sms_senders_service_id'), table_name='service_sms_senders')

View File

@@ -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')

View File

@@ -15,7 +15,7 @@ jsonschema==2.6.0
marshmallow-sqlalchemy==0.13.2 marshmallow-sqlalchemy==0.13.2
marshmallow==2.15.0 marshmallow==2.15.0
monotonic==1.4 monotonic==1.4
psycopg2==2.7.4 psycopg2-binary==2.7.4
PyJWT==1.5.3 PyJWT==1.5.3
SQLAlchemy-Utils==0.32.21 SQLAlchemy-Utils==0.32.21
SQLAlchemy==1.2.2 SQLAlchemy==1.2.2

View File

@@ -4,7 +4,6 @@ import os
from flask import Flask from flask import Flask
from alembic.command import upgrade from alembic.command import upgrade
from alembic.config import Config from alembic.config import Config
import boto3
import pytest import pytest
import sqlalchemy import sqlalchemy
@@ -128,12 +127,6 @@ def os_environ():
os.environ = old_env 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): def pytest_generate_tests(metafunc):
# Copied from https://gist.github.com/pfctdayelise/5719730 # Copied from https://gist.github.com/pfctdayelise/5719730
idparametrize = getattr(metafunc.function, 'idparametrize', None) idparametrize = getattr(metafunc.function, 'idparametrize', None)