Add Items (crud, models, endpoints), utils, refactor (#14)

* Update CRUD utils to use types better.
* Simplify Pydantic model names, from `UserInCreate` to `UserCreate`, etc.
* Upgrade packages.
* Add new generic "Items" models, crud utils, endpoints, and tests. To facilitate re-using them to create new functionality. As they are simple and generic (not like Users), it's easier to copy-paste and adapt them to each use case.
* Update endpoints/*path operations* to simplify code and use new utilities, prefix and tags in `include_router`.
* Update testing utils.
* Update linting rules, relax vulture to reduce false positives.
* Update migrations to include new Items.
* Update project README.md with tips about how to start with backend.
This commit is contained in:
Sebastián Ramírez
2019-04-19 09:45:23 +04:00
committed by GitHub
parent 1fe4908b0a
commit ecd634e497
32 changed files with 426 additions and 1091 deletions

View File

@@ -1,8 +1,9 @@
from fastapi import APIRouter
from app.api.api_v1.endpoints import token, user, utils
from app.api.api_v1.endpoints import items, login, users, utils
api_router = APIRouter()
api_router.include_router(token.router)
api_router.include_router(user.router)
api_router.include_router(utils.router)
api_router.include_router(login.router, tags=["login"])
api_router.include_router(users.router, prefix="/users", tags=["users"])
api_router.include_router(utils.router, prefix="/utils", tags=["utils"])
api_router.include_router(items.router, prefix="/items", tags=["items"])

View File

@@ -0,0 +1,102 @@
from typing import List
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from app import crud
from app.api.utils.db import get_db
from app.api.utils.security import get_current_active_user
from app.db_models.user import User as DBUser
from app.models.item import Item, ItemCreate, ItemUpdate
router = APIRouter()
@router.get("/", response_model=List[Item])
def read_items(
db: Session = Depends(get_db),
skip: int = 0,
limit: int = 100,
current_user: DBUser = Depends(get_current_active_user),
):
"""
Retrieve items.
"""
if crud.user.is_superuser(current_user):
items = crud.item.get_multi(db, skip=skip, limit=limit)
else:
items = crud.item.get_multi_by_owner(
db_session=db, owner_id=current_user.id, skip=skip, limit=limit
)
return items
@router.post("/", response_model=Item)
def create_item(
*,
db: Session = Depends(get_db),
item_in: ItemCreate,
current_user: DBUser = Depends(get_current_active_user),
):
"""
Create new item.
"""
item = crud.item.create(db_session=db, item_in=item_in, owner_id=current_user.id)
return item
@router.put("/{id}", response_model=Item)
def update_item(
*,
db: Session = Depends(get_db),
id: int,
item_in: ItemUpdate,
current_user: DBUser = Depends(get_current_active_user),
):
"""
Update an item.
"""
item = crud.item.get(db_session=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_session=db, item=item, item_in=item_in)
return item
@router.get("/{id}", response_model=Item)
def read_user_me(
*,
db: Session = Depends(get_db),
id: int,
current_user: DBUser = Depends(get_current_active_user),
):
"""
Get item by ID.
"""
item = crud.item.get(db_session=db, id=id)
if not item:
raise HTTPException(status_code=400, 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")
return item
@router.delete("/{id}", response_model=Item)
def delete_item(
*,
db: Session = Depends(get_db),
id: int,
current_user: DBUser = Depends(get_current_active_user),
):
"""
Delete an item.
"""
item = crud.item.get(db_session=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_session=db, id=id)
return item

View File

@@ -10,13 +10,13 @@ from app.api.utils.db import get_db
from app.api.utils.security import get_current_active_superuser, get_current_active_user
from app.core import config
from app.db_models.user import User as DBUser
from app.models.user import User, UserInCreate, UserInDB, UserInUpdate
from app.models.user import User, UserCreate, UserInDB, UserUpdate
from app.utils import send_new_account_email
router = APIRouter()
@router.get("/users/", tags=["users"], response_model=List[User])
@router.get("/", response_model=List[User])
def read_users(
db: Session = Depends(get_db),
skip: int = 0,
@@ -24,21 +24,21 @@ def read_users(
current_user: DBUser = Depends(get_current_active_superuser),
):
"""
Retrieve users
Retrieve users.
"""
users = crud.user.get_multi(db, skip=skip, limit=limit)
return users
@router.post("/users/", tags=["users"], response_model=User)
@router.post("/", response_model=User)
def create_user(
*,
db: Session = Depends(get_db),
user_in: UserInCreate,
user_in: UserCreate,
current_user: DBUser = Depends(get_current_active_superuser),
):
"""
Create new user
Create new user.
"""
user = crud.user.get_by_email(db, email=user_in.email)
if user:
@@ -54,7 +54,7 @@ def create_user(
return user
@router.put("/users/me", tags=["users"], response_model=User)
@router.put("/me", response_model=User)
def update_user_me(
*,
db: Session = Depends(get_db),
@@ -64,10 +64,10 @@ def update_user_me(
current_user: DBUser = Depends(get_current_active_user),
):
"""
Update own user
Update own user.
"""
current_user_data = jsonable_encoder(current_user)
user_in = UserInUpdate(**current_user_data)
user_in = UserUpdate(**current_user_data)
if password is not None:
user_in.password = password
if full_name is not None:
@@ -78,18 +78,18 @@ def update_user_me(
return user
@router.get("/users/me", tags=["users"], response_model=User)
@router.get("/me", response_model=User)
def read_user_me(
db: Session = Depends(get_db),
current_user: DBUser = Depends(get_current_active_user),
):
"""
Get current user
Get current user.
"""
return current_user
@router.post("/users/open", tags=["users"], response_model=User)
@router.post("/open", response_model=User)
def create_user_open(
*,
db: Session = Depends(get_db),
@@ -98,7 +98,7 @@ def create_user_open(
full_name: str = Body(None),
):
"""
Create new user without the need to be logged in
Create new user without the need to be logged in.
"""
if not config.USERS_OPEN_REGISTRATION:
raise HTTPException(
@@ -111,19 +111,19 @@ def create_user_open(
status_code=400,
detail="The user with this username already exists in the system",
)
user_in = UserInCreate(password=password, email=email, full_name=full_name)
user_in = UserCreate(password=password, email=email, full_name=full_name)
user = crud.user.create(db, user_in=user_in)
return user
@router.get("/users/{user_id}", tags=["users"], response_model=User)
@router.get("/{user_id}", response_model=User)
def read_user_by_id(
user_id: int,
current_user: DBUser = Depends(get_current_active_user),
db: Session = Depends(get_db),
):
"""
Get a specific user by id
Get a specific user by id.
"""
user = crud.user.get(db, user_id=user_id)
if user == current_user:
@@ -135,19 +135,18 @@ def read_user_by_id(
return user
@router.put("/users/{user_id}", tags=["users"], response_model=User)
@router.put("/{user_id}", response_model=User)
def update_user(
*,
db: Session = Depends(get_db),
user_id: int,
user_in: UserInUpdate,
user_in: UserUpdate,
current_user: UserInDB = Depends(get_current_active_superuser),
):
"""
Update a user
Update a user.
"""
user = crud.user.get(db, user_id=user_id)
if not user:
raise HTTPException(
status_code=404,

View File

@@ -10,23 +10,23 @@ from app.utils import send_test_email
router = APIRouter()
@router.post("/test-celery/", tags=["utils"], response_model=Msg, status_code=201)
@router.post("/test-celery/", response_model=Msg, status_code=201)
def test_celery(
msg: Msg, current_user: UserInDB = Depends(get_current_active_superuser)
):
"""
Test Celery worker
Test Celery worker.
"""
celery_app.send_task("app.worker.test_celery", args=[msg.msg])
return {"msg": "Word received"}
@router.post("/test-email/", tags=["utils"], response_model=Msg, status_code=201)
@router.post("/test-email/", response_model=Msg, status_code=201)
def test_email(
email_to: EmailStr, current_user: UserInDB = Depends(get_current_active_superuser)
):
"""
Test emails
Test emails.
"""
send_test_email(email_to=email_to)
return {"msg": "Test email sent"}