Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LLSC-16] Add basic user model #2

Merged
merged 15 commits into from
Oct 28, 2024
Merged

[LLSC-16] Add basic user model #2

merged 15 commits into from
Oct 28, 2024

Conversation

mslwang
Copy link
Collaborator

@mslwang mslwang commented Oct 3, 2024

Notion ticket link

Initial User Model

Implementation description

Adding initial User and Role models, so that other services aren't blocked on this model. First time running migration script as well.

Steps to test

  1. Run docker-compose up

What should reviewers focus on?

  • User, Role model
  • migrations

Checklist

  • My PR name is descriptive and in imperative tense
  • My commit messages are descriptive and in imperative tense. My commits are atomic and trivial commits are squashed or fixup'd into non-trivial commits
  • I have run the appropriate linter(s)
  • I have requested a review from the PL, as well as other devs who have background knowledge on this PR or who will be building on top of this PR


class User(Base):
__tablename__ = "users"
id = Column(String, primary_key=True) # UUID
Copy link
Collaborator

@mmiqball mmiqball Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from sqlalchemy.dialects.postgresql import UUID
import uuid

id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)

How about this to auto-generate UUIDs when a new user is inserted into the db?

This was the migration I added for this:

"""Update users id to UUID with default

Revision ID: c9bc2b4d1036
Revises: 79de0b981dd8
Create Date: 2024-10-16 17:13:53.820521

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = 'c9bc2b4d1036'
down_revision: Union[str, None] = '79de0b981dd8'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('users', 'id',
               existing_type=sa.VARCHAR(),
               type_=sa.UUID(),
               postgresql_using="id::uuid",
               server_default=sa.text("gen_random_uuid()"),
               existing_nullable=False)
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.alter_column('users', 'id',
               existing_type=sa.UUID(),
               type_=sa.VARCHAR(),
               postgresql_using="id::text",
               server_default=None,
               existing_nullable=False)
    # ### end Alembic commands ###

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that's a stronger guarantee, let's do that instead.

from .Base import Base


class Role(Base):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add in roles right now?

I added a migration with this in my ticket since we need the roles in the db to assign them to users. I can keep it there, or if you think it belongs in this PR that would work too.

    op.bulk_insert(
        sa.table('roles',
            sa.Column('id', sa.Integer(), nullable=False),
            sa.Column('name', sa.String(length=80), nullable=False),
        ),
        [
            {'id': 1, 'name': 'participant'},
            {'id': 2, 'name': 'volunteer'},
            {'id': 3, 'name': 'admin'},
        ]
    )
    

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'll move it to this PR, given that @emma-x1 can just work off this branch.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, can you please add in an auth_id field as well? It's needed for referencing the Firebase UID associated with a user in our db. I was keeping it in my ticket since that's where I initialized Firebase auth, but it's probably good to add it in here if @emma-x1 is working off this branch.

FIeld:

auth_id = Column(String, nullable=True) # Firebase Auth ID

Migration:

def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('users', sa.Column('auth_id', sa.String(), nullable=True))
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column('users', 'auth_id')
    # ### end Alembic commands ###

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make nullable=False when Firebase auth is implemented?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, since every user should have a Firebase UID. We can just add it in as nullable=False right now too, should be fine.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think with the new edge cases you mentioned, we should keep this. From what I understand, a participant can have different types (caregiver, patient) so we can maybe assign multiple roles to that user to handle those cases. It also seems safer since stuff does seem to change around a bit whenever we talk to the npo

@@ -0,0 +1,50 @@
"""create user table and roles
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wanted to confirm all files under migration folder are autogenerated from defined model/schemas correct

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes for the most part. The only exception would be seeding for constants or roles in this case.

Copy link
Collaborator

@Mayank808 Mayank808 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As starter table definitions, i think this is fine for now. Good to merge once the comments above are added in. We should probably add in a github action/precommit hook to ensure the migration scripts are autogenerated every time.

@@ -3,7 +3,7 @@
[alembic]
# path to migration scripts
# Use forward slashes (/) also on windows to provide an os agnostic path
script_location = migrations
script_location = app/migrations
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason we needed to move migration scripts into the app?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved it a while back to figure out the migration issue, but it's good now. Moved it back to migrations folder


from .Base import Base


Copy link
Collaborator

@Mayank808 Mayank808 Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add just a few comments above table definitions, giving a brief description of what the table is used for. Ie role tables will be like entitlements table housing all possible user roles on the system. Documentation on variables/relations if we think that's important could also be added but might be overkill.


from .Base import Base
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

``

Suggested change
from .Base import Base

Copy link
Collaborator Author

@mslwang mslwang Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need that for Base.metadata.create_all(bind=engine) and in backend/app/migrations/env.py

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: removing Base.metadata.create_all(bind=engine) so that we rely only on migrations to create tables.

Converted all nullable columns to be non-nullable

Migrations added:
- adding auth id to user model
- updated user id to uuid
- Seeded roles directly through migration
@mslwang mslwang requested a review from mmiqball October 28, 2024 00:51

def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a command to remove the roles we added in downgrade?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep let's do that.

@mslwang mslwang merged commit ff1b4f7 into main Oct 28, 2024
1 check passed
@mslwang mslwang deleted the mslwang/LLSC-16-add-user branch October 28, 2024 07:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants