Skip to content

Commit

Permalink
Merge pull request #133 from jadmsaadaot/SUBMIT-11
Browse files Browse the repository at this point in the history
Add a User entity and table and make AccountUser it's child
  • Loading branch information
jadmsaadaot authored Nov 1, 2024
2 parents a188842 + 2cc74fe commit 6d83aa9
Show file tree
Hide file tree
Showing 38 changed files with 528 additions and 307 deletions.
53 changes: 53 additions & 0 deletions submit-api/migrations/versions/075df7d4f03b_add_user_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
""" Add user type column
Revision ID: 075df7d4f03b
Revises: 8e3b41ce9e50
Create Date: 2024-10-30 16:15:35.557115
"""
import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
revision = '075df7d4f03b'
down_revision = '8e3b41ce9e50'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
usertype_enum = sa.Enum('PROPONENT', 'STAFF', name='usertype')
usertype_enum.create(op.get_bind(), checkfirst=True)

with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.add_column(sa.Column('type', usertype_enum, nullable=True))

# get list of user_ids from account_users
conn = op.get_bind()
result = conn.execute(sa.text("SELECT user_id FROM account_users")).fetchall()
user_ids = [row[0] for row in result]

# update user type to PROPONENT for all users in account_users, pgsql
op.execute(f"UPDATE users SET type = 'PROPONENT' WHERE id IN ({','.join(map(str, user_ids))})")

# update user type to STAFF for all users not in account_users, pgsql
op.execute(f"UPDATE users SET type = 'STAFF' WHERE id NOT IN ({','.join(map(str, user_ids))})")

with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.alter_column('type', nullable=False)

# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.drop_column('type')

# Drop the enum type
usertype_enum = sa.Enum('PROPONENT', 'STAFF', name='usertype')
usertype_enum.drop(op.get_bind(), checkfirst=True)

# ### end Alembic commands ###
46 changes: 46 additions & 0 deletions submit-api/migrations/versions/20a2b81fe5f7_add_users_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
""" add user table
Revision ID: 20a2b81fe5f7
Revises: e1e1b81ad5c8
Create Date: 2024-10-30 12:56:44.220088
"""
import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
revision = '20a2b81fe5f7'
down_revision = 'e1e1b81ad5c8'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('users',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('auth_guid', sa.String(), nullable=False),
sa.Column('created_date', sa.DateTime(), nullable=False),
sa.Column('updated_date', sa.DateTime(), nullable=True),
sa.Column('created_by', sa.String(length=50), nullable=True),
sa.Column('updated_by', sa.String(length=50), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('auth_guid')
)
with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.create_index('ix_users_auth_guid', ['auth_guid'], unique=True)

# populate auth_guid, created_Date, updated_date, created_by, updated_by from account_users
op.execute("INSERT INTO users (auth_guid, created_date, updated_date, created_by, updated_by) SELECT auth_guid, created_date, updated_date, created_by, updated_by FROM account_users")

# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.drop_index('ix_users_auth_guid')

op.drop_table('users')
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Drop auth_guid from account_users
Revision ID: 8e3b41ce9e50
Revises: cba5ebbb4a74
Create Date: 2024-10-30 16:06:23.630182
"""
import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
revision = '8e3b41ce9e50'
down_revision = 'cba5ebbb4a74'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('account_users', 'auth_guid')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('account_users', sa.Column('auth_guid', sa.String(), nullable=True))
op.execute("UPDATE account_users au SET auth_guid = u.auth_guid FROM users u WHERE u.id = au.user_id")
op.create_unique_constraint('unique_account_users_auth_guid', 'account_users', ['auth_guid'])
op.alter_column('account_users', 'auth_guid', existing_type=sa.String(), nullable=False)
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Add user_id to account_users
Revision ID: cba5ebbb4a74
Revises: 20a2b81fe5f7
Create Date: 2024-10-30 12:58:53.607737
"""
import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
revision = 'cba5ebbb4a74'
down_revision = '20a2b81fe5f7'
branch_labels = None
depends_on = None


def upgrade():
# add user_id to account_users and populate it then make it foreign key
op.add_column('account_users', sa.Column('user_id', sa.Integer(), nullable=True))
op.execute("UPDATE account_users au SET user_id = u.id FROM users u WHERE u.auth_guid = au.auth_guid")
op.alter_column('account_users', 'user_id', existing_type=sa.Integer(), nullable=False)
op.create_foreign_key('fk_account_users_user_id_users', 'account_users', 'users', ['user_id'], ['id'])


def downgrade():
# remove user_id from account_users
op.drop_constraint('fk_account_users_user_id_users', 'account_users', type_='foreignkey')
op.drop_column('account_users', 'user_id')
1 change: 1 addition & 0 deletions submit-api/src/submit_api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@
from .submission import Submission
from .submitted_document import SubmittedDocument
from .submitted_form import SubmittedForm
from .user import User
19 changes: 12 additions & 7 deletions submit-api/src/submit_api/models/account_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
"""
from __future__ import annotations

from sqlalchemy import Column, ForeignKey, Index
from sqlalchemy import Column, ForeignKey
from sqlalchemy.orm import column_property

from .base_model import BaseModel
from .db import db
from .user import User as UserModel


class AccountUser(BaseModel):
Expand All @@ -24,12 +25,10 @@ class AccountUser(BaseModel):
position = Column(db.String(100), nullable=False)
work_email_address = Column(db.String(100), nullable=False)
work_contact_number = Column(db.String(50), nullable=False)
auth_guid = Column(db.String(), nullable=False, unique=True)
account = db.relationship('Account', foreign_keys=[account_id], lazy='joined')
user_id = Column(db.Integer, ForeignKey('users.id'), nullable=False)

__table_args__ = (
Index('ix_account_users_auth_guid', 'auth_guid', unique=True),
)
account = db.relationship('Account', foreign_keys=[account_id], lazy='joined')
user = db.relationship('User', foreign_keys=[user_id], lazy='joined')

@classmethod
def create_account_user(cls, data, session=None) -> AccountUser:
Expand All @@ -41,11 +40,17 @@ def create_account_user(cls, data, session=None) -> AccountUser:
position=data.get('position', None),
work_email_address=data.get('work_email_address', None),
work_contact_number=data.get('work_contact_number', None),
auth_guid=data.get('auth_guid', None)
user_id=data.get('user_id', None)
)
if session:
session.add(account_user)
session.commit()
else:
account_user.save()
return account_user

@classmethod
def get_by_guid(cls, _guid):
"""Get account user by guid."""
account_user = cls.query.join(UserModel).filter(UserModel.auth_guid == _guid).first()
return account_user
8 changes: 2 additions & 6 deletions submit-api/src/submit_api/models/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,8 @@ class Package(BaseModel):
type_id = Column(db.Integer, ForeignKey('package_types.id'), nullable=False)
type = db.relationship('PackageType', foreign_keys=[type_id], lazy='joined')
submitted_on = Column(db.DateTime, nullable=True)
submitted_by = Column(db.String(255), nullable=True)
submitted_by_account_user = db.relationship(
'AccountUser',
primaryjoin="foreign(Package.submitted_by) == AccountUser.auth_guid",
lazy='joined'
)
submitted_by = Column(db.String, ForeignKey('users.auth_guid'), nullable=True)
submitted_by_user = db.relationship('User', foreign_keys=[submitted_by], lazy='joined')
meta = db.relationship('PackageMetadata', backref='package', lazy='select')
items = db.relationship('Item', backref='package', lazy='joined', order_by='Item.sort_order')
status = Column(db.ARRAY(Enum(PackageStatus)), nullable=False, default=[PackageStatus.NEW_SUBMISSION.value])
Expand Down
29 changes: 0 additions & 29 deletions submit-api/src/submit_api/models/queries/account_user.py

This file was deleted.

1 change: 1 addition & 0 deletions submit-api/src/submit_api/models/queries/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from submit_api.models.account_project_search_options import AccountProjectSearchOptions
from submit_api.models.package import Package


# pylint: disable=too-few-public-methods


Expand Down
7 changes: 2 additions & 5 deletions submit-api/src/submit_api/models/submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,8 @@ class Submission(BaseModel):
submitted_form = db.relationship('SubmittedForm', foreign_keys=[submitted_form_id], lazy='joined')
submitted_document = db.relationship('SubmittedDocument', foreign_keys=[submitted_document_id], lazy='joined')
version = Column(db.Integer, nullable=False, default=1)
account_user = db.relationship(
'AccountUser',
primaryjoin="foreign(Submission.created_by) == AccountUser.auth_guid",
lazy='joined'
)
created_by = Column(db.String, ForeignKey('users.auth_guid'), nullable=False)
submitted_by_user = db.relationship('User', foreign_keys=[created_by], lazy='joined')

Index('idx_submissions_type_item_id', type, item_id)

Expand Down
53 changes: 53 additions & 0 deletions submit-api/src/submit_api/models/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""User model class.
Manages the user
"""
from __future__ import annotations

import enum

from sqlalchemy import Column, Enum, Index

from .base_model import BaseModel
from .db import db


class UserType(enum.Enum):
"""Enum for user type."""

PROPONENT = 'PROPONENT'
STAFF = 'STAFF'


class User(BaseModel):
"""Definition of the User entity."""

__tablename__ = 'users'

id = Column(db.Integer, primary_key=True, autoincrement=True)
auth_guid = Column(db.String(), nullable=False, unique=True)
type = Column(Enum(UserType), nullable=False)
account_user = db.relationship('AccountUser', uselist=False, back_populates='user')

__table_args__ = (
Index('ix_users_auth_guid', 'auth_guid', unique=True),
)

@classmethod
def create_user(cls, data, session=None) -> User:
"""Create user."""
account_user = User(
auth_guid=data.get('auth_guid', None),
type=data.get('type', None)
)
if session:
session.add(account_user)
session.commit()
else:
account_user.save()
return account_user

@classmethod
def get_by_guid(cls, _guid):
"""Get user by guid."""
return cls.query.filter(cls.auth_guid == _guid).first()
9 changes: 4 additions & 5 deletions submit-api/src/submit_api/resources/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@

from flask_restx import Namespace, Resource, cors

from submit_api.auth import auth
from submit_api.exceptions import ResourceNotFoundError
from submit_api.resources.apihelper import Api as ApiHelper
from submit_api.schemas.user import UserSchema
from submit_api.services.user_service import UserService
from submit_api.utils.util import cors_preflight

from ..auth import auth
from ..schemas.user import UserSchema
from ..services.user_service import UserService
from .apihelper import Api as ApiHelper


API = Namespace("users", description="Endpoints for Account Management")
"""Custom exception messages
Expand Down
11 changes: 8 additions & 3 deletions submit-api/src/submit_api/schemas/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
Manages the item schema
"""

from marshmallow import EXCLUDE, Schema, fields
from marshmallow import EXCLUDE, Schema, fields, pre_dump

from submit_api.enums.item_status import ItemStatus
from submit_api.models.submission import SubmissionTypeStatus
from submit_api.schemas.account_user import AccountUserSchema
from submit_api.schemas.item_type import ItemTypeSchema
from submit_api.schemas.submission import SubmittedDocumentSchema, SubmittedFormSchema

Expand All @@ -29,9 +28,15 @@ class Meta: # pylint: disable=too-few-public-methods
submitted_document = fields.Nested(SubmittedDocumentSchema, data_key="submitted_document")
created_date = fields.DateTime(data_key="created_date")
created_by = fields.Str(data_key="created_by")
account_user = fields.Nested(AccountUserSchema, data_key="account_user")
submitted_by = fields.Str(data_key="submitted_by")
version = fields.Int(data_key="version")

@pre_dump
def get_submitted_by(self, obj, **kwargs):
"""Get submitted by."""
obj.submitted_by = obj.submitted_by_user.account_user.full_name if obj.submitted_by_user else None
return obj


class ItemSchema(Schema):
"""item schema."""
Expand Down
Loading

0 comments on commit 6d83aa9

Please sign in to comment.