Skip to content
This repository has been archived by the owner on Nov 14, 2022. It is now read-only.

Commit

Permalink
Refactor backend and frontend (#7)
Browse files Browse the repository at this point in the history
* ⬆️ Upgrade backend dependencies in Dockerfiles

* 📝 Update generated docs to use latest integrated /start-reload.sh

* 🔧 Add scripts for project generator development

* ➕ Add backend development dependencies

* 🔥 Remove scripts provided by base image

* 🔊 Add logs to starting scripts

* 🏗️ Upgrade backend structure, names, dependencies

* 🎨 Upgrade linting script to include dead code detection

* ⬆️ Upgrade frontend dependencies

* 🏗️ Upgrade vuex integration and standardize layout

* 🐛 Fix backend logic to update users

* 🎨 Format frontend code
  • Loading branch information
tiangolo authored Mar 11, 2019
1 parent cfebb50 commit 718cb4a
Show file tree
Hide file tree
Showing 68 changed files with 743 additions and 686 deletions.
17 changes: 17 additions & 0 deletions dev-fsfcb-back.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#! /usr/bin/env bash

# Run this script from outside the project, to integrate a dev-fsfcb project with changes and review modifications

# Exit in case of error
set -e

if [ $(uname -s) = "Linux" ]; then
echo "Remove __pycache__ files"
sudo find ./dev-fsfcb/ -type d -name __pycache__ -exec rm -r {} \+
fi

rm -rf ./full-stack-fastapi-couchbase/\{\{cookiecutter.project_slug\}\}/*

rsync -a --exclude=node_modules ./dev-fsfcb/* ./full-stack-fastapi-couchbase/\{\{cookiecutter.project_slug\}\}/

rsync -a ./dev-fsfcb/{.env,.gitignore,.gitlab-ci.yml} ./full-stack-fastapi-couchbase/\{\{cookiecutter.project_slug\}\}/
2 changes: 2 additions & 0 deletions dev-fsfcb-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
default_context:
"project_name": "Dev FSFCB"
10 changes: 10 additions & 0 deletions dev-fsfcb.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#! /usr/bin/env bash

# Run this script from outside the project, to generate a dev-fsfcb project

# Exit in case of error
set -e

rm -rf ./dev-fsfcb

cookiecutter --config-file ./full-stack-fastapi-couchbase/dev-fsfcb-config.yml --no-input -f ./full-stack-fastapi-couchbase
8 changes: 4 additions & 4 deletions {{cookiecutter.project_slug}}/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ The changes to those files only affect the local development environment, not th

For example, the directory with the backend code is mounted as a Docker "host volume" (in the file `docker-compose.dev.volumes.yml`), mapping the code you change live to the directory inside the container. That allows you to test your changes right away, without having to build the Docker image again. It should only be done during development, for production, you should build the Docker image with a recent version of the backend code. But during development, it allows you to iterate very fast.

There is also a commented out `command` override (in the file `docker-compose.dev.command.yml`), if you want to enable it, uncomment it. It makes the backend container run a process that does "nothing", but keeps the process running. That allows you to get inside your living container and run commands inside, for example a Python interpreter to test installed dependencies, or start the development server that reloads when it detectes changes.
There is also a commented out `command` override (in the file `docker-compose.dev.command.yml`), if you want to enable it, uncomment it. It makes the backend container run a process that does "nothing", but keeps the process running. That allows you to get inside your living container and run commands inside, for example a Python interpreter to test installed dependencies, or start the development server that reloads when it detects changes.

To get inside the container with a `bash` session you can start the stack with:

Expand All @@ -103,16 +103,16 @@ root@7f2607af31c3:/app#

that means that you are in a `bash` session inside your container, as a `root` user, under the `/app` directory.

There is also a script `backend-live.sh` to run the debug live reloading server. You can run that script from inside the container with:
There is also a script `/start-reload.sh` to run the debug live reloading server. You can run that script from inside the container with:

```bash
bash ./backend-live.sh
bash /start-reload.sh
```

...it will look like:

```bash
root@7f2607af31c3:/app# bash ./backend-live.sh
root@7f2607af31c3:/app# bash /start-reload.sh
```

and then hit enter. That runs the debugging server that auto reloads when it detects code changes.
Expand Down
2 changes: 2 additions & 0 deletions {{cookiecutter.project_slug}}/backend/app/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ isort = "*"
autoflake = "*"
flake8 = "*"
pytest = "*"
vulture = "*"

[packages]
fastapi = "*"
Expand All @@ -26,6 +27,7 @@ pydantic = "*"
couchbase = "*"
emails = "*"
raven = "*"
jinja2 = "*"

[requires]
python_version = "3.6"
Expand Down
13 changes: 5 additions & 8 deletions {{cookiecutter.project_slug}}/backend/app/app/api/api_v1/api.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
from fastapi import APIRouter

from app.api.api_v1.endpoints.role import router as roles_router
from app.api.api_v1.endpoints.token import router as token_router
from app.api.api_v1.endpoints.user import router as user_router
from app.api.api_v1.endpoints.utils import router as utils_router
from app.api.api_v1.endpoints import role, token, user, utils

api_router = APIRouter()
api_router.include_router(roles_router)
api_router.include_router(token_router)
api_router.include_router(user_router)
api_router.include_router(utils_router)
api_router.include_router(role.router)
api_router.include_router(token.router)
api_router.include_router(user.router)
api_router.include_router(utils.router)
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
from fastapi import APIRouter, Depends
from starlette.exceptions import HTTPException

from app.core.jwt import get_current_user
from app.crud.user import check_if_user_is_active, check_if_user_is_superuser
from app.crud.utils import ensure_enums_to_strs
from app import crud
from app.api.utils.security import get_current_active_superuser
from app.models.role import RoleEnum, Roles
from app.models.user import UserInDB

router = APIRouter()


@router.get("/roles/", response_model=Roles)
def route_roles_get(current_user: UserInDB = Depends(get_current_user)):
def read_roles(current_user: UserInDB = Depends(get_current_active_superuser)):
"""
Retrieve roles
"""
if not check_if_user_is_active(current_user):
raise HTTPException(status_code=400, detail="Inactive user")
elif not (check_if_user_is_superuser(current_user)):
raise HTTPException(
status_code=400, detail="The current user does not have enogh privileges"
)
roles = ensure_enums_to_strs(RoleEnum)
roles = crud.utils.ensure_enums_to_strs(RoleEnum)
return {"roles": roles}
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
from datetime import timedelta

from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import OAuth2PasswordRequestForm
from starlette.exceptions import HTTPException

from app import crud
from app.api.utils.security import get_current_user
from app.core import config
from app.core.jwt import create_access_token, get_current_user
from app.crud.user import (
authenticate_user,
check_if_user_is_active,
check_if_user_is_superuser,
get_user,
update_user,
)
from app.core.jwt import create_access_token
from app.db.database import get_default_bucket
from app.models.msg import Msg
from app.models.token import Token
Expand All @@ -27,70 +21,72 @@


@router.post("/login/access-token", response_model=Token, tags=["login"])
def route_login_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
def login(form_data: OAuth2PasswordRequestForm = Depends()):
"""
OAuth2 compatible token login, get an access token for future requests
"""
bucket = get_default_bucket()
user = authenticate_user(bucket, form_data.username, form_data.password)
user = crud.user.authenticate(
bucket, username=form_data.username, password=form_data.password
)
if not user:
raise HTTPException(status_code=400, detail="Incorrect email or password")
elif not check_if_user_is_active(user):
elif not crud.user.is_active(user):
raise HTTPException(status_code=400, detail="Inactive user")
access_token_expires = timedelta(minutes=config.ACCESS_TOKEN_EXPIRE_MINUTES)
return {
"access_token": create_access_token(
data={"username": form_data.username}, expires_delta=access_token_expires
data={"username": user.username}, expires_delta=access_token_expires
),
"token_type": "bearer",
}


@router.post("/login/test-token", tags=["login"], response_model=User)
def route_test_token(current_user: UserInDB = Depends(get_current_user)):
def test_token(current_user: UserInDB = Depends(get_current_user)):
"""
Test access token
"""
return current_user


@router.post("/password-recovery/{username}", tags=["login"], response_model=Msg)
def route_recover_password(username: str):
def recover_password(username: str):
"""
Password Recovery
"""
bucket = get_default_bucket()
user = get_user(bucket, username)
user = crud.user.get(bucket, username=username)

if not user:
raise HTTPException(
status_code=404,
detail="The user with this username does not exist in the system.",
)
password_reset_token = generate_password_reset_token(username)
password_reset_token = generate_password_reset_token(username=username)
send_reset_password_email(
email_to=user.email, username=username, token=password_reset_token
)
return {"msg": "Password recovery email sent"}


@router.post("/reset-password/", tags=["login"], response_model=Msg)
def route_reset_password(token: str, new_password: str):
def reset_password(token: str, new_password: str):
"""
Reset password
"""
username = verify_password_reset_token(token)
if not username:
raise HTTPException(status_code=400, detail="Invalid token")
bucket = get_default_bucket()
user = get_user(bucket, username)
user = crud.user.get(bucket, username=username)
if not user:
raise HTTPException(
status_code=404,
detail="The user with this username does not exist in the system.",
)
elif not check_if_user_is_active(user):
elif not crud.user.is_active(user):
raise HTTPException(status_code=400, detail="Inactive user")
user_in = UserInUpdate(name=username, password=new_password)
user = update_user(bucket, user_in)
user = crud.user.update(bucket, username=username, user_in=user_in)
return {"msg": "Password updated successfully"}
Loading

0 comments on commit 718cb4a

Please sign in to comment.