Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
88b1b12
add pg-admin volume, fix flower
ghostforpy Nov 27, 2021
a32d06e
edit config.py
ghostforpy Nov 27, 2021
933d1ce
add async to tests_pre_start
ghostforpy Nov 27, 2021
de2768a
add async to initial_data
ghostforpy Nov 27, 2021
17f9555
add async to init_db
ghostforpy Nov 27, 2021
9846029
add async and profile query mode to session
ghostforpy Nov 27, 2021
f054756
add async to deps
ghostforpy Nov 27, 2021
7f1891f
add async to login endpoints
ghostforpy Nov 27, 2021
bde1a1f
add assync to users endpoints
ghostforpy Nov 27, 2021
290c797
add delete user endpoint
ghostforpy Nov 27, 2021
7bf95ad
add async to items emdpoints
ghostforpy Nov 27, 2021
ea2b870
add async to base crud
ghostforpy Nov 27, 2021
5cc1bce
add async to user crud
ghostforpy Nov 27, 2021
2b61a29
add async to item crud
ghostforpy Nov 27, 2021
40564f9
add async to confest.py tests
ghostforpy Nov 27, 2021
a5dc87f
add async to user test utils
ghostforpy Nov 27, 2021
25cf8b0
add asynnc to test utils
ghostforpy Nov 27, 2021
fb0bee7
add async to user crud tests
ghostforpy Nov 27, 2021
3a5d239
add async to item crud tests
ghostforpy Nov 27, 2021
1a43127
add async to pyproject for poetry
ghostforpy Nov 27, 2021
6afbff0
add async to test celery endpoint
ghostforpy Nov 27, 2021
7914ec0
add async to test login endpoints
ghostforpy Nov 27, 2021
3934cad
add async to test user endpoints
ghostforpy Nov 27, 2021
dea24a5
add async to item test endpoints
ghostforpy Nov 27, 2021
167a41d
add migrations scripts
ghostforpy Nov 27, 2021
2ffa998
add .env settings
ghostforpy Nov 27, 2021
3d504f2
iss typing AsyncGenerator
ghostforpy Nov 27, 2021
6515107
edit alembic for tests
ghostforpy Dec 7, 2021
d6f4e8d
fix alembic env.py
ghostforpy Dec 14, 2021
1668d1c
fix "how to use"
ghostforpy Dec 14, 2021
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Go to the directory where you want to create your project and run:

```bash
pip install cookiecutter
cookiecutter https://github.com/tiangolo/full-stack-fastapi-postgresql
cookiecutter https://github.com/ghostforpy/full-stack-fastapi-postgresql
```

### Generate passwords
Expand Down
6 changes: 6 additions & 0 deletions {{cookiecutter.project_slug}}/.env
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ POSTGRES_DB=app
PGADMIN_LISTEN_PORT=5050
PGADMIN_DEFAULT_EMAIL={{cookiecutter.pgadmin_default_user}}
PGADMIN_DEFAULT_PASSWORD={{cookiecutter.pgadmin_default_user_password}}

#TESTS
TEST_MODE=False

#QUERY PROFILE
PROFILE_QUERY_MODE=False
6 changes: 5 additions & 1 deletion {{cookiecutter.project_slug}}/backend/app/alembic/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ def get_url():
user = os.getenv("POSTGRES_USER", "postgres")
password = os.getenv("POSTGRES_PASSWORD", "")
server = os.getenv("POSTGRES_SERVER", "db")
db = os.getenv("POSTGRES_DB", "app")
TEST_MODE = os.getenv("TEST_MODE", 'False')
if TEST_MODE == 'True':
db = "postgres"
else:
db = os.getenv("POSTGRES_DB", "app")
return f"postgresql://{user}:{password}@{server}/{db}"


Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from typing import Any, List

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
#from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession

from app import crud, models, schemas
from app.api import deps
Expand All @@ -10,8 +11,8 @@


@router.get("/", response_model=List[schemas.Item])
def read_items(
db: Session = Depends(deps.get_db),
async def read_items(
db: AsyncSession = Depends(deps.async_get_db),
skip: int = 0,
limit: int = 100,
current_user: models.User = Depends(deps.get_current_active_user),
Expand All @@ -20,59 +21,59 @@ def read_items(
Retrieve items.
"""
if crud.user.is_superuser(current_user):
items = crud.item.get_multi(db, skip=skip, limit=limit)
items = await crud.item.get_multi(db, skip=skip, limit=limit)
else:
items = crud.item.get_multi_by_owner(
items = await crud.item.get_multi_by_owner(
db=db, owner_id=current_user.id, skip=skip, limit=limit
)
return items


@router.post("/", response_model=schemas.Item)
def create_item(
async def create_item(
*,
db: Session = Depends(deps.get_db),
db: AsyncSession = Depends(deps.async_get_db),
item_in: schemas.ItemCreate,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Create new item.
"""
item = crud.item.create_with_owner(db=db, obj_in=item_in, owner_id=current_user.id)
item = await crud.item.create_with_owner(db=db, obj_in=item_in, owner_id=current_user.id)
return item


@router.put("/{id}", response_model=schemas.Item)
def update_item(
async def update_item(
*,
db: Session = Depends(deps.get_db),
db: AsyncSession = Depends(deps.async_get_db),
id: int,
item_in: schemas.ItemUpdate,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Update an item.
"""
item = crud.item.get(db=db, id=id)
item = await crud.item.get(db=db, id=id)
if not item:
raise HTTPException(status_code=404, detail="Item not found")
if not crud.user.is_superuser(current_user) and (item.owner_id != current_user.id):
raise HTTPException(status_code=400, detail="Not enough permissions")
item = crud.item.update(db=db, db_obj=item, obj_in=item_in)
item = await crud.item.update(db=db, db_obj=item, obj_in=item_in)
return item


@router.get("/{id}", response_model=schemas.Item)
def read_item(
async def read_item(
*,
db: Session = Depends(deps.get_db),
db: AsyncSession = Depends(deps.async_get_db),
id: int,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get item by ID.
"""
item = crud.item.get(db=db, id=id)
item = await crud.item.get(db=db, id=id)
if not item:
raise HTTPException(status_code=404, detail="Item not found")
if not crud.user.is_superuser(current_user) and (item.owner_id != current_user.id):
Expand All @@ -81,19 +82,19 @@ def read_item(


@router.delete("/{id}", response_model=schemas.Item)
def delete_item(
async def delete_item(
*,
db: Session = Depends(deps.get_db),
db: AsyncSession = Depends(deps.async_get_db),
id: int,
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Delete an item.
"""
item = crud.item.get(db=db, id=id)
item = await crud.item.get(db=db, id=id)
if not item:
raise HTTPException(status_code=404, detail="Item not found")
if not crud.user.is_superuser(current_user) and (item.owner_id != current_user.id):
raise HTTPException(status_code=400, detail="Not enough permissions")
item = crud.item.remove(db=db, id=id)
item = await crud.item.remove(db=db, id=id)
return item
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from fastapi import APIRouter, Body, Depends, HTTPException
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession

from app import crud, models, schemas
from app.api import deps
Expand All @@ -20,13 +21,13 @@


@router.post("/login/access-token", response_model=schemas.Token)
def login_access_token(
db: Session = Depends(deps.get_db), form_data: OAuth2PasswordRequestForm = Depends()
async def login_access_token(
db: AsyncSession = Depends(deps.async_get_db), form_data: OAuth2PasswordRequestForm = Depends()
) -> Any:
"""
OAuth2 compatible token login, get an access token for future requests
OAuth2 compatible token login, get an access token for future requests.
"""
user = crud.user.authenticate(
user = await crud.user.authenticate(
db, email=form_data.username, password=form_data.password
)
if not user:
Expand All @@ -51,11 +52,11 @@ def test_token(current_user: models.User = Depends(deps.get_current_user)) -> An


@router.post("/password-recovery/{email}", response_model=schemas.Msg)
def recover_password(email: str, db: Session = Depends(deps.get_db)) -> Any:
async def recover_password(email: str, db: AsyncSession = Depends(deps.async_get_db)) -> Any:
"""
Password Recovery
"""
user = crud.user.get_by_email(db, email=email)
user = await crud.user.get_by_email(db, email=email)

if not user:
raise HTTPException(
Expand All @@ -70,18 +71,18 @@ def recover_password(email: str, db: Session = Depends(deps.get_db)) -> Any:


@router.post("/reset-password/", response_model=schemas.Msg)
def reset_password(
async def reset_password(
token: str = Body(...),
new_password: str = Body(...),
db: Session = Depends(deps.get_db),
db: AsyncSession = Depends(deps.async_get_db),
) -> Any:
"""
Reset password
"""
email = verify_password_reset_token(token)
if not email:
raise HTTPException(status_code=400, detail="Invalid token")
user = crud.user.get_by_email(db, email=email)
user = await crud.user.get_by_email(db, email=email)
if not user:
raise HTTPException(
status_code=404,
Expand All @@ -92,5 +93,5 @@ def reset_password(
hashed_password = get_password_hash(new_password)
user.hashed_password = hashed_password
db.add(user)
db.commit()
await db.commit()
return {"msg": "Password updated successfully"}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from fastapi import APIRouter, Body, Depends, HTTPException
from fastapi.encoders import jsonable_encoder
from pydantic.networks import EmailStr
from sqlalchemy.orm import Session
#from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession

from app import crud, models, schemas
from app.api import deps
Expand All @@ -14,36 +15,36 @@


@router.get("/", response_model=List[schemas.User])
def read_users(
db: Session = Depends(deps.get_db),
async def read_users(
db: AsyncSession = Depends(deps.async_get_db),
skip: int = 0,
limit: int = 100,
current_user: models.User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Retrieve users.
"""
users = crud.user.get_multi(db, skip=skip, limit=limit)
users = await crud.user.get_multi(db, skip=skip, limit=limit)
return users


@router.post("/", response_model=schemas.User)
def create_user(
async def create_user(
*,
db: Session = Depends(deps.get_db),
db: AsyncSession = Depends(deps.async_get_db),
user_in: schemas.UserCreate,
current_user: models.User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Create new user.
"""
user = crud.user.get_by_email(db, email=user_in.email)
user = await crud.user.get_by_email(db, email=user_in.email)
if user:
raise HTTPException(
status_code=400,
detail="The user with this username already exists in the system.",
)
user = crud.user.create(db, obj_in=user_in)
user = await crud.user.create(db, obj_in=user_in)
if settings.EMAILS_ENABLED and user_in.email:
send_new_account_email(
email_to=user_in.email, username=user_in.email, password=user_in.password
Expand All @@ -52,9 +53,9 @@ def create_user(


@router.put("/me", response_model=schemas.User)
def update_user_me(
async def update_user_me(
*,
db: Session = Depends(deps.get_db),
db: AsyncSession = Depends(deps.async_get_db),
password: str = Body(None),
full_name: str = Body(None),
email: EmailStr = Body(None),
Expand All @@ -71,13 +72,13 @@ def update_user_me(
user_in.full_name = full_name
if email is not None:
user_in.email = email
user = crud.user.update(db, db_obj=current_user, obj_in=user_in)
user = await crud.user.update(db, db_obj=current_user, obj_in=user_in)
return user


@router.get("/me", response_model=schemas.User)
def read_user_me(
db: Session = Depends(deps.get_db),
async def read_user_me(
db: AsyncSession = Depends(deps.async_get_db),
current_user: models.User = Depends(deps.get_current_active_user),
) -> Any:
"""
Expand All @@ -87,9 +88,9 @@ def read_user_me(


@router.post("/open", response_model=schemas.User)
def create_user_open(
async def create_user_open(
*,
db: Session = Depends(deps.get_db),
db: AsyncSession = Depends(deps.async_get_db),
password: str = Body(...),
email: EmailStr = Body(...),
full_name: str = Body(None),
Expand All @@ -102,52 +103,69 @@ def create_user_open(
status_code=403,
detail="Open user registration is forbidden on this server",
)
user = crud.user.get_by_email(db, email=email)
user = await crud.user.get_by_email(db, email=email)
if user:
raise HTTPException(
status_code=400,
detail="The user with this username already exists in the system",
)
user_in = schemas.UserCreate(password=password, email=email, full_name=full_name)
user = crud.user.create(db, obj_in=user_in)
user = await crud.user.create(db, obj_in=user_in)
return user


@router.get("/{user_id}", response_model=schemas.User)
def read_user_by_id(
async def read_user_by_id(
user_id: int,
current_user: models.User = Depends(deps.get_current_active_user),
db: Session = Depends(deps.get_db),
db: AsyncSession = Depends(deps.async_get_db),
) -> Any:
"""
Get a specific user by id.
"""
user = crud.user.get(db, id=user_id)
if user == current_user:
return user
if not crud.user.is_superuser(current_user):
user = await crud.user.get(db, id=user_id)
if not user:
raise HTTPException(
status_code=400, detail="The user doesn't have enough privileges"
)
return user


@router.put("/{user_id}", response_model=schemas.User)
def update_user(
async def update_user(
*,
db: Session = Depends(deps.get_db),
db: AsyncSession = Depends(deps.async_get_db),
user_id: int,
user_in: schemas.UserUpdate,
current_user: models.User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Update a user.
"""
user = crud.user.get(db, id=user_id)
user = await crud.user.get(db, id=user_id)
if not user:
raise HTTPException(
status_code=404,
detail="The user with this username does not exist in the system",
)
user = crud.user.update(db, db_obj=user, obj_in=user_in)
user = await crud.user.update(db, db_obj=user, obj_in=user_in)
return user

@router.delete("/{id}", response_model=schemas.User)
async def delete_user(
*,
db: AsyncSession = Depends(deps.async_get_db),
id: int,
current_user: models.User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Delete a user.
"""
user = await crud.user.get(db, id=id)
if not user:
raise HTTPException(
status_code=404,
detail="The user with this username does not exist in the system",
)
user = await crud.user.remove(db=db, id=id)
return user
Loading