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

Handle returning users by checking their guid #26

Merged
merged 5 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions submit-api/migrations/versions/aeb2ae9d64b9_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Add auth_guid column to account_users

Revision ID: aeb2ae9d64b9
Revises: 8e112bda0a34
Create Date: 2024-08-12 10:18:32.687612

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = 'aeb2ae9d64b9'
down_revision = '8e112bda0a34'
branch_labels = None
depends_on = None


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

op.drop_table('staff_users')
with op.batch_alter_table('account_users', schema=None) as batch_op:
batch_op.add_column(sa.Column('auth_guid', sa.String(), nullable=False, unique=True))
batch_op.create_index('ix_account_users_auth_guid', ['auth_guid'], unique=True)

# ### end Alembic commands ###


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

op.create_table('staff_users',
sa.Column('created_date', postgresql.TIMESTAMP(), autoincrement=False, nullable=False),
sa.Column('updated_date', postgresql.TIMESTAMP(), autoincrement=False, nullable=True),
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('first_name', sa.VARCHAR(length=50), autoincrement=False, nullable=True),
sa.Column('middle_name', sa.VARCHAR(length=50), autoincrement=False, nullable=True),
sa.Column('last_name', sa.VARCHAR(length=50), autoincrement=False, nullable=True),
sa.Column('username', sa.VARCHAR(length=100), autoincrement=False, nullable=True),
sa.Column('email_address', sa.VARCHAR(length=100), autoincrement=False, nullable=True),
sa.Column('contact_number', sa.VARCHAR(length=50), autoincrement=False, nullable=True),
sa.Column('created_by', sa.VARCHAR(length=50), autoincrement=False, nullable=True),
sa.Column('updated_by', sa.VARCHAR(length=50), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('id', name='staff_users_pkey')
)
with op.batch_alter_table('staff_users', schema=None) as batch_op:
batch_op.create_index('ix_staff_users_username', ['username'], unique=True)

# ### end Alembic commands ###
1 change: 0 additions & 1 deletion submit-api/src/submit_api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"""This exports all of the models and schemas used by the application."""

from .db import db, ma, migrate
from .user import User
from .account_role import AccountRole
from .account_user import AccountUser
from .role import Role
Expand Down
2 changes: 2 additions & 0 deletions submit-api/src/submit_api/models/account_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ 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)

@classmethod
def create_account_user(cls, data, session=None) -> AccountUser:
Expand All @@ -35,6 +36,7 @@ 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)
)
if session:
session.add(account_user)
Expand Down
1 change: 1 addition & 0 deletions submit-api/src/submit_api/models/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ def session_scope():
session.commit()
except Exception as e: # noqa: B901, E722
print(str(e))
print(f"Rolling back the session; error: {e}")
session.rollback()
raise
29 changes: 29 additions & 0 deletions submit-api/src/submit_api/models/queries/account_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright © 2024 Province of British Columbia
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Model to handle all complex operations related to User."""
from submit_api.models import AccountUser, db


# pylint: disable=too-few-public-methods
class UserQueries:
"""Query module for complex user queries"""

@classmethod
def get_by_guid(cls, guid: str):
"""Find user by guid"""
print(guid)
result = (db.session.query(AccountUser)
.filter(AccountUser.auth_guid == guid)
.first())
return result
59 changes: 0 additions & 59 deletions submit-api/src/submit_api/models/user.py

This file was deleted.

4 changes: 2 additions & 2 deletions submit-api/src/submit_api/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
from .apihelper import Api

from .ops import API as OPS_API
from .user import API as USER_API
from .account import API as ACCOUNT_API
from .user import API as USER_API

__all__ = ('API_BLUEPRINT', 'OPS_BLUEPRINT')

Expand All @@ -54,5 +54,5 @@

# HANDLER = ExceptionHandler(API)

API.add_namespace(USER_API)
API.add_namespace(ACCOUNT_API)
API.add_namespace(USER_API)
2 changes: 1 addition & 1 deletion submit-api/src/submit_api/resources/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
from submit_api.services.account_service import AccountService
from submit_api.utils.util import cors_preflight
from submit_api.schemas.account import AccountSchema, AccountCreateSchema
from submit_api.exceptions import ResourceNotFoundError
from .apihelper import Api as ApiHelper
from ..exceptions import ResourceNotFoundError

API = Namespace("accounts", description="Endpoints for Account Management")
"""Custom exception messages
Expand Down
89 changes: 18 additions & 71 deletions submit-api/src/submit_api/resources/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,93 +11,40 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""API endpoints for managing an user resource."""
"""API endpoints for managing an account resource."""

from http import HTTPStatus

from flask_restx import Namespace, Resource
from submit_api.services.user_service import UserService
from flask_restx import Namespace, Resource, cors
from submit_api.utils.util import cors_preflight
from submit_api.schemas.user import UserSchema, UserRequestSchema
from submit_api.exceptions import ResourceNotFoundError
from .apihelper import Api as ApiHelper
from ..schemas.user import UserSchema
from ..services.user_service import UserService

API = Namespace("users", description="Endpoints for User Management")
API = Namespace("users", description="Endpoints for Account Management")
"""Custom exception messages
"""

user_request_model = ApiHelper.convert_ma_schema_to_restx_model(
API, UserRequestSchema(), "User"
user_model = ApiHelper.convert_ma_schema_to_restx_model(
API, UserSchema(), "User"
)
user_list_model = ApiHelper.convert_ma_schema_to_restx_model(
API, UserSchema(), "UserListItem"
)


@cors_preflight("GET, OPTIONS, POST")
@API.route("", methods=["POST", "GET", "OPTIONS"])
class Users(Resource):
"""Resource for managing users."""

@staticmethod
@API.response(code=200, description="Success", model=[user_list_model])
@ApiHelper.swagger_decorators(API, endpoint_description="Fetch all users")
def get():
"""Fetch all users."""
users = UserService.get_all_users()
user_list_schema = UserSchema(many=True)
return user_list_schema.dump(users), HTTPStatus.OK

@staticmethod
@ApiHelper.swagger_decorators(API, endpoint_description="Create a user")
@API.expect(user_request_model)
@API.response(code=201, model=user_request_model, description="UserCreated")
@API.response(400, "Bad Request")
def post():
"""Create a user."""
user_data = UserRequestSchema().load(API.payload)
created_user = UserService.create_user(user_data)
return UserSchema().dump(created_user), HTTPStatus.CREATED


@cors_preflight("GET, OPTIONS, PATCH, DELETE")
@API.route("/<user_id>", methods=["PATCH", "GET", "OPTIONS", "DELETE"])
@API.doc(params={"user_id": "The user identifier"})
@cors_preflight("GET, OPTIONS")
@API.route("/guid/<string:guid>", methods=["GET", "OPTIONS"])
@API.doc(params={"guid": "The user global unique identifier"})
class User(Resource):
"""Resource for managing a single user"""
"""Resource for managing a single account"""

@staticmethod
@ApiHelper.swagger_decorators(API, endpoint_description="Fetch a user by id")
@API.response(code=200, model=user_list_model, description="Success")
@ApiHelper.swagger_decorators(API, endpoint_description="Fetch a user by guid")
@API.response(code=200, model=user_model, description="Success")
@API.response(404, "Not Found")
def get(user_id):
"""Fetch a user by id."""
user = UserService.get_user_by_id(user_id)
@cors.crossdomain(origin="*")
def get(guid):
"""Fetch an account by id."""
user = UserService.get_by_auth_guid(guid)
if not user:
raise ResourceNotFoundError(f"User with {user_id} not found")
return ResourceNotFoundError(f"User with guid {guid} not found")
return UserSchema().dump(user), HTTPStatus.OK

@staticmethod
@ApiHelper.swagger_decorators(API, endpoint_description="Update a user by id")
@API.expect(user_request_model)
@API.response(code=200, model=user_list_model, description="Success")
@API.response(400, "Bad Request")
@API.response(404, "Not Found")
def patch(user_id):
"""Update a user by id."""
user_data = UserRequestSchema().load(API.payload)
updated_user = UserService.update_user(user_id, user_data)
if not updated_user:
raise ResourceNotFoundError(f"User with {user_id} not found")
return UserSchema().dump(updated_user), HTTPStatus.OK

@staticmethod
@ApiHelper.swagger_decorators(API, endpoint_description="Delete a user by id")
@API.response(code=200, model=user_list_model, description="Deleted")
@API.response(404, "Not Found")
def delete(user_id):
"""Delete a user by id."""
deleted_user = UserService.delete_user(user_id)
if not deleted_user:
raise ResourceNotFoundError(f"User with {user_id} not found")
return UserSchema().dump(deleted_user), HTTPStatus.OK
1 change: 1 addition & 0 deletions submit-api/src/submit_api/schemas/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ class Meta: # pylint: disable=too-few-public-methods
work_contact_number = fields.Str(data_key="work_contact_number")
position = fields.Str(data_key="position")
proponent_id = fields.Str(data_key="proponent_id")
auth_guid = fields.Str(data_key="auth_guid")
19 changes: 19 additions & 0 deletions submit-api/src/submit_api/schemas/project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Engagement model class.

Manages the engagement
"""

from marshmallow import EXCLUDE, Schema, fields


class ProjectSchema(Schema):
"""Account schema."""

class Meta: # pylint: disable=too-few-public-methods
"""Exclude unknown fields in the deserialized output."""

unknown = EXCLUDE

id = fields.Int(data_key="id")
project_id = fields.Str(data_key="project_id")
account_id = fields.Str(data_key="account_id")
23 changes: 3 additions & 20 deletions submit-api/src/submit_api/schemas/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,7 @@ class Meta: # pylint: disable=too-few-public-methods

id = fields.Int(data_key="id")
first_name = fields.Str(data_key="first_name")
middle_name = fields.Str(data_key="description")
last_name = fields.Str(data_key="last_name")
email_address = fields.Str(data_key="email_address")
contact_number = fields.Str(data_key="contact_number")
username = fields.Str(data_key="username")


class UserRequestSchema(Schema):
"""User Request Schema"""

class Meta: # pylint: disable=too-few-public-methods
"""Exclude unknown fields in the deserialized output."""

unknown = EXCLUDE

first_name = fields.Str(data_key="first_name")
middle_name = fields.Str(data_key="description")
last_name = fields.Str(data_key="last_name")
email_address = fields.Str(data_key="email_address")
contact_number = fields.Str(data_key="contact_number")
username = fields.Str(data_key="username")
work_email_address = fields.Str(data_key="email_address")
work_contact_number = fields.Str(data_key="contact_number")
account_id = fields.Int(data_key="account_id")
11 changes: 6 additions & 5 deletions submit-api/src/submit_api/services/account_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ def create_account(cls, data):
account = AccountModel.create_account(account_data, session)
account_user_data = {
"account_id": account.id,
"first_name": data["first_name"],
"last_name": data["last_name"],
"position": data["position"],
"work_email_address": data["work_email_address"],
"work_contact_number": data["work_contact_number"],
"first_name": data.get("first_name"),
"last_name": data.get("last_name"),
"position": data.get("position"),
"work_email_address": data.get("work_email_address"),
"work_contact_number": data.get("work_contact_number"),
'auth_guid': data.get('auth_guid')
}
account_user = AccountUserModel.create_account_user(account_user_data, session)

Expand Down
Loading
Loading