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

FastAPI migration #803

Merged
merged 77 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
cd1a72b
Initialize new fastapi project
erikguntner Sep 6, 2024
28cf2f3
Add settings config and db
erikguntner Sep 6, 2024
6393cf7
Add models, db seed operation, and api router
erikguntner Sep 6, 2024
c37e7d1
Add models, db see operation, and api router
erikguntner Sep 6, 2024
9107b10
Add auth router, dependencies, and schemas
erikguntner Sep 6, 2024
4b32985
Create crud operations and auth routes
erikguntner Sep 6, 2024
0ad2bc8
Update README
erikguntner Sep 6, 2024
3e9c298
Merge pull request #787 from hackforla/fastpi-setup
erikguntner Sep 6, 2024
0ff1d0c
Update README.md
erikguntner Sep 6, 2024
3aea3e2
Update README.md
erikguntner Sep 6, 2024
d8319bf
Update README.md
erikguntner Sep 6, 2024
cfaed98
Update README.md
erikguntner Sep 6, 2024
d84c2cd
Update README.md
erikguntner Sep 6, 2024
061b0fc
Update README.md
erikguntner Sep 6, 2024
946ee10
Update README.md
erikguntner Sep 6, 2024
32ddd8d
Update README.md
erikguntner Sep 6, 2024
feaef56
Update README.md
erikguntner Sep 6, 2024
73f5ee5
fastapi-migration: poetry for dependency mgmt only
paulespinosa Sep 6, 2024
ba0fa32
fastapi-migration: Moved tests and test config
paulespinosa Sep 6, 2024
7cd84a4
Merge remote-tracking branch 'origin/fastapi-migration' into fastapi-…
paulespinosa Sep 6, 2024
2c83714
Fix package name
erikguntner Sep 6, 2024
10c9048
Add session routes and schemas
erikguntner Sep 6, 2024
a0a6afd
Removed unused import
erikguntner Sep 6, 2024
0682d0f
Formattin
erikguntner Sep 6, 2024
aeede11
Add /user route
erikguntner Sep 6, 2024
b57c098
Create user router
erikguntner Sep 6, 2024
860553a
Refactor env config and remove python-dotenv package
erikguntner Sep 6, 2024
5253cb6
fastapi-migration: Organize by workflow sections
paulespinosa Sep 7, 2024
e8e96a7
Added forgot password route handler in api/routes/auth.py, created fo…
johnwroge Sep 8, 2024
3345914
Imported boto3
johnwroge Sep 8, 2024
53efe4b
I added the confirm forgot password route handler to verify forgot pa…
johnwroge Sep 8, 2024
08053ce
fastapi-migration: Organization and tests
paulespinosa Sep 10, 2024
89e0d81
Merge remote-tracking branch 'origin/fastapi-migration' into fastapi-…
paulespinosa Sep 10, 2024
cb118be
fastapi-migration: Fix bad merge
paulespinosa Sep 10, 2024
c7fa414
fastapi-migration: Add e2e test for workflow testing
paulespinosa Sep 10, 2024
9b5f8c6
Merge with primary branch
erikguntner Sep 10, 2024
2addea9
fastapi-migration: Add basic docs to Housing Orgs code
paulespinosa Sep 11, 2024
8577d02
fastapi-migration: Remove unused tests
paulespinosa Sep 11, 2024
53e9346
Move existing auth and files into access
erikguntner Sep 11, 2024
d04aae7
fastapi-migration: Housing Org controller transactions
paulespinosa Sep 11, 2024
e333cdc
fastapi-migration: Fix Housing Org controller
paulespinosa Sep 12, 2024
fbd38c6
Move folders to modules and update imports
erikguntner Sep 12, 2024
c939998
Update import
erikguntner Sep 12, 2024
27617cd
fastapi-migration: Rename stays to relationship_management
paulespinosa Sep 12, 2024
3055067
fastapi-migration: Follow best practice for primary key name
paulespinosa Sep 12, 2024
7370f0b
Update proxy path
erikguntner Sep 12, 2024
6b5a0dd
Create user api on front end
erikguntner Sep 12, 2024
531970d
Update role type
erikguntner Sep 12, 2024
f842cf3
fastapi-migration: Document API naming convention in README.
paulespinosa Sep 13, 2024
8dcac18
Merge branch 'fastapi-migration' of https://github.com/hackforla/Home…
erikguntner Sep 13, 2024
3a75d0a
Merge and move relationship management folder
erikguntner Sep 13, 2024
75de0d7
Merge pull request #793 from hackforla/fastapi-auth-flow
paulespinosa Sep 13, 2024
bc3484c
fastapi-migration: Test authentication
paulespinosa Sep 15, 2024
46eb2cf
fastapi-migration: Delete test_mocking
paulespinosa Sep 15, 2024
28f2f66
Update import
erikguntner Sep 18, 2024
a3e3741
Update confim sign up route to work with FastAPI
erikguntner Sep 18, 2024
77837b0
Update sign up form on frontend
erikguntner Sep 18, 2024
12cfac2
Change isLoading variable and Remove Google auth button
erikguntner Sep 18, 2024
4f041ac
Throw error if no type is provided
erikguntner Sep 18, 2024
4b1f8d7
Add signout route and remove session cookies
erikguntner Sep 18, 2024
8885528
Comment out divider from auth forms
erikguntner Sep 19, 2024
daed4f5
Update imports
erikguntner Sep 19, 2024
7fc5753
Change session route hash to use username, remove username from /sign…
erikguntner Sep 19, 2024
b57d9b4
Add route descriptions, protect signout route using bearer token
erikguntner Sep 19, 2024
7a5e434
rename forgot password routes
erikguntner Sep 19, 2024
a79198c
Change forgot password paths on frontend
erikguntner Sep 19, 2024
8d87d82
Update forgot password routes responses
erikguntner Sep 19, 2024
f9449cf
Protect user route
erikguntner Sep 19, 2024
c30492d
Add get user by id operation
erikguntner Sep 19, 2024
c60369c
change user controller to users and update paths
erikguntner Sep 19, 2024
9c3fc45
Update secret hash cal to use username
erikguntner Sep 19, 2024
3ea183d
update current user query and hooks on frontend
erikguntner Sep 19, 2024
2e02107
Fix delete user route
erikguntner Sep 19, 2024
1faab11
Get client id from settings instead of query params
erikguntner Sep 20, 2024
caebdd6
Merge pull request #799 from hackforla/fastapi-auth-continued
erikguntner Sep 20, 2024
d411e5a
update backend .env.example
erikguntner Sep 24, 2024
6055826
Change folder names
erikguntner Sep 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
COGNITO_CLIENT_ID=
COGNITO_CLIENT_SECRET=
COGNITO_REGION=
COGNITO_REDIRECT_URI=http://localhost:34828/signin
COGNITO_USER_POOL_ID=
COGNITO_ACCESS_ID=
COGNITO_ACCESS_KEY=
ROOT_URL=http://localhost:34828
DATABASE_URL=sqlite:///./homeuniteus.db
75 changes: 75 additions & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# Local database
homeuniteus.db

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
venv/
.venv/
.python-version
.pytest_cache

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

#Ipython Notebook
.ipynb_checkpoints

# Local Setup
.DS_Store
.vscode
personal.py
.env
63 changes: 63 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Home Unite Us FastAPI Server

## Overview

This is the _Home Unite Us_ web API server.

This server uses:

- [FastAPI](https://fastapi.tiangolo.com/) - Web framework for API development
- [SQLAlchemy](https://www.sqlalchemy.org/) - ORM for database operations
- [Pydantic](https://docs.pydantic.dev/latest/) - Data validation and serialization
- [Poetry](https://python-poetry.org/docs/) - Dependency management

## Requirements

You will need Python 3.8+ to install Poetry.

Run `python -V` to check the Python version.

**Note**: On some systems, you might need to use the `python3` and `pip3` commands.

[Poetry](https://python-poetry.org/docs/#installation) is used to manage the project dependencies. Follow the [installation instructions](https://python-poetry.org/docs/#installation) to run the CLI globally.

## Usage - Development

### Getting Started

#### Configuration

The API configuration must be specified before running the application. Configuration variables are specified as entries within a `.env` file located within the `api-v2` directory. To get started, create a `.env` file within `/api-v2` and copy the values from `.env.example` into the new `.env` file. You may have to contact someone from the development team to get the necessary values.

#### Setup and Run

Once the `.env` file has been configured and Poetry is installed, run the following commands in the `api-v2` directory to install the required development dependencies and run the application.

```shell
poetry install # Installs all dependencies

poetry shell # Activates the virtual environment

poetry run fastapi dev app/main.py # Runs this server in developer mode
```

Your server is now running at:
```
http://127.0.0.1:8000
```

And your API docs at:
```
http://127.0.0.1:8000/docs
```

To exit the virtual environment, within the shell run:
```shell
exit
```

## Conventions

### API Endpoints

A path segment with spaces must be replace the spaces with a hyphen `-`. For example, `https://dev.homeunite.us/api/housing-orgs`.
File renamed without changes.
91 changes: 91 additions & 0 deletions backend/alembic/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from logging.config import fileConfig

from sqlalchemy import engine_from_config
from sqlalchemy import pool

from alembic import context

import sys
import os
print(os.getcwd())
sys.path.append(os.getcwd())

from app import models as db

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:
fileConfig(config.config_file_name)

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = db.Base.metadata

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.


def run_migrations_offline() -> None:
"""Run migrations in 'offline' mode.

This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.

Calls to context.execute() here emit the given string to the
script output.

"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)

with context.begin_transaction():
context.run_migrations()


def run_migrations_online() -> None:
"""Run migrations in 'online' mode.

In this scenario we need to create an Engine
and associate a connection with the context.

"""
print("ONLINE")
# Check for an existing connection before creating a new engine.
# pytest-alembic will hook into alembic by creating a connection
# with the test engine configuration.
connectable = context.config.attributes.get("connection", None)
if connectable is None:
connectable = engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)

with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)

with context.begin_transaction():
context.run_migrations()


if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
File renamed without changes.
72 changes: 72 additions & 0 deletions backend/alembic/versions/e4c8bb426528_add_user_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""Add user types

Revision ID: e4c8bb426528
Revises: ec8b1c17739a
Create Date: 2024-03-10 21:47:13.942845

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy import text
from app.user_roles import UserRole

# revision identifiers, used by Alembic.
revision = 'e4c8bb426528'
down_revision = 'ec8b1c17739a'
branch_labels = None
depends_on = None

def upgrade() -> None:
'''
1. Add one table:
1. role - Store available application user roles
2. Prepopulate the role table with four role types: Admin, Host, Guest, Coordinator
3. Update the user table to add the first, middle, last name, and role_id columns.
* All existing users will be given the first, last name "UNKNOWN"
* Assign all existing users to the Guest role.
4. Drop the host table.
* There is no way to map host users back to the user table. We would need a user id foreign
key, or at least an email address.
'''
role_table = op.create_table('role',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.bulk_insert(role_table,
[{'name': UserRole.ADMIN.value},
{'name': UserRole.HOST.value},
{'name': UserRole.GUEST.value},
{'name': UserRole.COORDINATOR.value}])
op.create_index(op.f('ix_role_id'), 'role', ['id'])

conn = op.get_bind()
guest_role_id = conn.execute(text("SELECT id FROM role WHERE name = 'Guest'")).fetchone()[0]

with op.batch_alter_table('user', schema=None) as batch_op:
# Each existing user will get the first and last names "Unknown" by default
# and they will be assigned to the "Guest" user role.
batch_op.add_column(sa.Column('firstName', sa.String(length=255), nullable=False, server_default='Unknown'))
batch_op.add_column(sa.Column('middleName', sa.String(length=255), nullable=True))
batch_op.add_column(sa.Column('lastName', sa.String(length=255), nullable=True))
batch_op.add_column(sa.Column('role_id', sa.Integer, nullable=False, server_default=str(guest_role_id)))
batch_op.create_foreign_key('fk_user_role_id', 'role', ['role_id'], ['id'])

op.drop_table('host')

def downgrade() -> None:
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.drop_constraint('fk_user_role_id', type_='foreignkey')
batch_op.drop_column('lastName')
batch_op.drop_column('middleName')
batch_op.drop_column('firstName')

op.drop_index(op.f('ix_role_id'), table_name='role')
op.drop_table('role')
op.create_table('host',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_host_id'), 'host', ['id'])
File renamed without changes.
21 changes: 21 additions & 0 deletions backend/app/core/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from functools import lru_cache
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env")

COGNITO_CLIENT_ID: str
COGNITO_CLIENT_SECRET: str
COGNITO_REGION: str
COGNITO_REDIRECT_URI: str
COGNITO_USER_POOL_ID: str
COGNITO_ACCESS_ID: str
COGNITO_ACCESS_KEY: str
ROOT_URL: str
DATABASE_URL: str


@lru_cache
def get_settings():
return Settings()
32 changes: 32 additions & 0 deletions backend/app/core/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Shared database components."""
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, DeclarativeBase


_db_engine = None
_DbSessionFactory = None


class Base(DeclarativeBase):
pass


def init_db(engine):
Base.metadata.create_all(bind=engine, checkfirst=True)


def db_engine(settings):
global _db_engine
if _db_engine is None:
_db_engine = create_engine(settings.DATABASE_URL,
connect_args={"check_same_thread": False})
return _db_engine


def db_session_factory(engine):
global _DbSessionFactory
if _DbSessionFactory is None:
_DbSessionFactory = sessionmaker(autocommit=False,
autoflush=False,
bind=engine)
return _DbSessionFactory
20 changes: 20 additions & 0 deletions backend/app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from fastapi import FastAPI
from contextlib import asynccontextmanager

from app.modules.router import api_router
import app.core.db as db
import app.core.config as config


@asynccontextmanager
async def lifespan(app: FastAPI):
settings = config.get_settings()
engine = db.db_engine(settings)
import app.seed
db.init_db(engine)
yield


app = FastAPI(lifespan=lifespan)

app.include_router(api_router, prefix="/api")
File renamed without changes.
Loading
Loading