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

Feature/user management #24

Draft
wants to merge 12 commits into
base: staging
Choose a base branch
from
Binary file added .DS_Store
Binary file not shown.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
GOOGLE_CLIENT_ID=553026630658-ed4e19reiffffm0kihn5lh6ln3d4g.apps.googleusercontent.com
Copy link
Member

Choose a reason for hiding this comment

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

I hope this is actually a fake accoutn.

GOOGLE_CLIENT_SECRET=LUjC5CPRqX3mFcfdddxAqCoE9Tk
SECRET=S3CR3T
GOPHIE_ACCESS_KEY=S3CR3TK3Y
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
Copy link
Member

Choose a reason for hiding this comment

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

Add this file to .gitignore

Copy link
Member

Choose a reason for hiding this comment

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

Also add the .DS_Store and clean them up

"python.linting.banditEnabled": false,
"python.linting.enabled": true,
"python.linting.flake8Enabled": true
}
Binary file added alembic/.DS_Store
Binary file not shown.
Binary file added alembic/versions/.DS_Store
Binary file not shown.
38 changes: 38 additions & 0 deletions alembic/versions/3c0cb039fd0a_add_oauth2_to_user_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""add oauth2 to user model

Revision ID: 3c0cb039fd0a
Revises: b44fef6dc06b
Create Date: 2021-11-18 20:59:19.398458

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '3c0cb039fd0a'
down_revision = 'b44fef6dc06b'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index('ix_user_email', table_name='user')
op.drop_table('user')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('user',
sa.Column('id', sa.CHAR(length=36), nullable=False),
sa.Column('email', sa.VARCHAR(length=320), nullable=False),
sa.Column('hashed_password', sa.VARCHAR(length=72), nullable=False),
sa.Column('is_active', sa.BOOLEAN(), nullable=False),
sa.Column('is_superuser', sa.BOOLEAN(), nullable=False),
sa.Column('is_verified', sa.BOOLEAN(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_user_email', 'user', ['email'], unique=False)
# ### end Alembic commands ###
38 changes: 38 additions & 0 deletions alembic/versions/b44fef6dc06b_autho2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""autho2

Revision ID: b44fef6dc06b
Revises: ed436e5e9cd6
Create Date: 2021-11-18 20:48:38.550131

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'b44fef6dc06b'
down_revision = 'ed436e5e9cd6'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index('ix_user_email', table_name='user')
op.drop_table('user')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('user',
sa.Column('id', sa.CHAR(length=36), nullable=False),
sa.Column('email', sa.VARCHAR(length=320), nullable=False),
sa.Column('hashed_password', sa.VARCHAR(length=72), nullable=False),
sa.Column('is_active', sa.BOOLEAN(), nullable=False),
sa.Column('is_superuser', sa.BOOLEAN(), nullable=False),
sa.Column('is_verified', sa.BOOLEAN(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_user_email', 'user', ['email'], unique=False)
# ### end Alembic commands ###
28 changes: 28 additions & 0 deletions alembic/versions/ed436e5e9cd6_autho2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""autho2
Copy link
Member

@deven96 deven96 Nov 22, 2021

Choose a reason for hiding this comment

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

All the new migration files look incredibly sus
From my understanding, user table should be created in an upgrade and those foreign keys added to necessary tables
Then downgrade will consist of deleting the foreign keys and the table
I can't see the new user id foreign key field getting added to the download and referral tables

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've not been able to successfully migrate this, we could possibly check this out together later... having issues with FK and i haven't worked on it since the last time we spoke.

Copy link
Member

Choose a reason for hiding this comment

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

Alright no problem


Revision ID: ed436e5e9cd6
Revises: 05e696f0741c
Create Date: 2021-11-18 20:28:43.053448

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'ed436e5e9cd6'
down_revision = '05e696f0741c'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
48 changes: 41 additions & 7 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
from typing import List
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from app.settings import settings # Settings module must be imported before all modules so that it will be available
from app import models
from app.models import SessionLocal, engine
from app.routers import router

# Settings module must be imported before all modules so that it will be available
from app.settings import settings
from app.models import SessionLocal
from .routers import users, movie, music
from .dependencies import jwt_authentication, google_oauth_client
# from pydantic import BaseConfig

app = FastAPI()
app = FastAPI(title=settings.app_name)
# BaseConfig.arbitrary_types_allowed = True

app.add_middleware(
CORSMiddleware,
Expand All @@ -19,7 +21,34 @@
allow_origin_regex=settings.origins_regex
)

app.include_router(router)
app.include_router(
users.fastapi_users.get_register_router(),
prefix="/auth",
tags=["auth"],
)
app.include_router(
users.fastapi_users.get_users_router(),
prefix="/auth",
tags=["users"],
)
app.include_router(
users.fastapi_users.get_auth_router(jwt_authentication),
prefix="/auth",
tags=["auth"],
)
app.include_router(
users.fastapi_users.get_reset_password_router(),
prefix="/auth",
tags=["auth"],
)
app.include_router(
users.fastapi_users.get_oauth_router(google_oauth_client, settings.secret),
prefix="/auth/google",
deven96 marked this conversation as resolved.
Show resolved Hide resolved
tags=["auth"],
)
app.include_router(movie.router)
app.include_router(music.router)


# keeps clashing with alembic for table creation
# Uncomment to use poor man's table creation
Expand All @@ -33,3 +62,8 @@ def get_db():
yield db
finally:
db.close()


@app.get("/")
async def root():
return {"message": f"{settings.app_name}, 'Rating'!"}
41 changes: 41 additions & 0 deletions app/dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from httpx_oauth.clients.google import GoogleOAuth2
from fastapi import Depends, Request
from fastapi_users import BaseUserManager
from typing import Optional
from fastapi_users.authentication import JWTAuthentication
from app.models import get_user_db
import logging

from app.models.models import UserCreate, UserDB
from app.settings import settings


class UserManager(BaseUserManager[UserCreate, UserDB]):
user_db_model = UserDB
reset_password_token_secret = settings.secret
verification_token_secret = settings.secret

async def on_after_register(self, user: UserDB, request: Optional[Request] = None):
logging.info(f"User {user.id} has registered.")

async def on_after_forgot_password(
self, user: UserDB, token: str, request: Optional[Request] = None
):
logging.info(
f"User {user.id} has forgot their password. Reset token: {token}")

async def on_after_request_verify(
self, user: UserDB, token: str, request: Optional[Request] = None
):
logging.info(
f"Verification requested for user {user.id}. Verification token: {token}")


async def get_user_manager(user_db=Depends(get_user_db)):
yield UserManager(user_db)

jwt_authentication = JWTAuthentication(
secret=settings.secret, lifetime_seconds=3600, tokenUrl="auth/login")

google_oauth_client = GoogleOAuth2(
settings.google_client_id, settings.google_client_secret)
37 changes: 33 additions & 4 deletions app/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
from datetime import datetime

import databases
from sqlalchemy.orm import Session
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base

from fastapi_users.db import (
SQLAlchemyBaseOAuthAccountTable,
SQLAlchemyBaseUserTable,
SQLAlchemyUserDatabase,
)
from app import settings

from app.models.models import UserDB

Base = declarative_base()

if settings.debug:
engine = create_engine(settings.database_url, connect_args={"check_same_thread": False})
engine = create_engine(settings.database_url, connect_args={
"check_same_thread": False})
else:
engine = create_engine(settings.database_url)

database = databases.Database(settings.database_url)


class UserTable(Base, SQLAlchemyBaseUserTable):
pass


class OAuthAccount(SQLAlchemyBaseOAuthAccountTable, Base):
pass


class HashableSession(Session):
def __init__(self, *args, **kwargs):
Expand Down Expand Up @@ -42,7 +59,8 @@ def __eq__(self, other):
return self.__hash__() == other.__hash__()


SessionLocal = sessionmaker(autocommit=False, class_=HashableSession, autoflush=False, bind=engine)
SessionLocal = sessionmaker(
autocommit=False, class_=HashableSession, autoflush=False, bind=engine)


def get_db():
Expand All @@ -52,3 +70,14 @@ def get_db():
yield db
finally:
db.close()


Base.metadata.create_all(engine)

users = UserTable.__table__

oauth_accounts = OAuthAccount.__table__


async def get_user_db():
yield SQLAlchemyUserDatabase(UserDB, database, users, oauth_accounts)
Loading