diff --git a/{{cookiecutter.project_slug}}/README.md b/{{cookiecutter.project_slug}}/README.md index abbb7cd..23b89b8 100644 --- a/{{cookiecutter.project_slug}}/README.md +++ b/{{cookiecutter.project_slug}}/README.md @@ -134,6 +134,20 @@ If you need to install any additional package for the tests, add it to the file If you use GitLab CI the tests will run automatically. +#### Local tests + +Start the stack with this command: + +```Bash +DOMAIN=backend sh ./scripts/test-local.sh +``` +The `./backend/app` directory is mounted as a "host volume" inside the docker container (set in the file `docker-compose.dev.volumes.yml`). +You can rerun the test on live code: + +```Bash +docker-compose exec backend-tests /tests-start.sh +``` + #### Test running stack If your stack is already up and you just want to run the tests, you can use: diff --git a/{{cookiecutter.project_slug}}/backend/app/app/crud/crud_user.py b/{{cookiecutter.project_slug}}/backend/app/app/crud/crud_user.py index e5d9d55..e8ade85 100644 --- a/{{cookiecutter.project_slug}}/backend/app/app/crud/crud_user.py +++ b/{{cookiecutter.project_slug}}/backend/app/app/crud/crud_user.py @@ -3,7 +3,7 @@ from typing import Optional from sqlalchemy.orm import Session from app.models.user import User -from app.schemas.user import UserCreate, UserUpdate +from app.schemas.user import UserCreate, UserUpdate, UserInDB from app.core.security import verify_password, get_password_hash from app.crud.base import CRUDBase @@ -24,6 +24,15 @@ class CRUDUser(CRUDBase[User, UserCreate, UserUpdate]): db_session.refresh(db_obj) return db_obj + def update(self, db_session: Session, *, db_obj: User, obj_in: UserUpdate) -> User: + if obj_in.password: + update_data = obj_in.dict(exclude_unset=True) + hashed_password = get_password_hash(obj_in.password) + del update_data["password"] + update_data["hashed_password"] = hashed_password + use_obj_in = UserInDB.parse_obj(update_data) + return super().update(db_session, db_obj=db_obj, obj_in=use_obj_in) + def authenticate( self, db_session: Session, *, email: str, password: str ) -> Optional[User]: diff --git a/{{cookiecutter.project_slug}}/backend/app/app/schemas/user.py b/{{cookiecutter.project_slug}}/backend/app/app/schemas/user.py index d80e906..32e3a98 100644 --- a/{{cookiecutter.project_slug}}/backend/app/app/schemas/user.py +++ b/{{cookiecutter.project_slug}}/backend/app/app/schemas/user.py @@ -11,29 +11,29 @@ class UserBase(BaseModel): full_name: Optional[str] = None -class UserBaseInDB(UserBase): +# Properties to receive via API on creation +class UserCreate(UserBase): + email: EmailStr + password: str + + +# Properties to receive via API on update +class UserUpdate(UserBase): + password: Optional[str] = None + + +class UserInDBBase(UserBase): id: int = None class Config: orm_mode = True -# Properties to receive via API on creation -class UserCreate(UserBaseInDB): - email: EmailStr - password: str - - -# Properties to receive via API on update -class UserUpdate(UserBaseInDB): - password: Optional[str] = None - - # Additional properties to return via API -class User(UserBaseInDB): +class User(UserInDBBase): pass # Additional properties stored in DB -class UserInDB(UserBaseInDB): +class UserInDB(UserInDBBase): hashed_password: str diff --git a/{{cookiecutter.project_slug}}/backend/app/app/tests/crud/test_user.py b/{{cookiecutter.project_slug}}/backend/app/app/tests/crud/test_user.py index 39cbf33..d1c1443 100644 --- a/{{cookiecutter.project_slug}}/backend/app/app/tests/crud/test_user.py +++ b/{{cookiecutter.project_slug}}/backend/app/app/tests/crud/test_user.py @@ -1,8 +1,9 @@ from fastapi.encoders import jsonable_encoder from app import crud +from app.core.security import get_password_hash, verify_password from app.db.session import db_session -from app.schemas.user import UserCreate +from app.schemas.user import UserCreate, UserUpdate from app.tests.utils.utils import random_lower_string, random_email @@ -78,3 +79,16 @@ def test_get_user(): user_2 = crud.user.get(db_session, id=user.id) assert user.email == user_2.email assert jsonable_encoder(user) == jsonable_encoder(user_2) + + +def test_update_user(): + password = random_lower_string() + email = random_email() + user_in = UserCreate(email=email, password=password, is_superuser=True) + user = crud.user.create(db_session, obj_in=user_in) + new_password = random_lower_string() + user_in = UserUpdate(password=new_password, is_superuser=True) + crud.user.update(db_session, db_obj=user, obj_in=user_in) + user_2 = crud.user.get(db_session, id=user.id) + assert user.email == user_2.email + assert verify_password(new_password, user_2.hashed_password) diff --git a/{{cookiecutter.project_slug}}/backend/app/app/tests/utils/user.py b/{{cookiecutter.project_slug}}/backend/app/app/tests/utils/user.py index 6dfa337..42f80ce 100644 --- a/{{cookiecutter.project_slug}}/backend/app/app/tests/utils/user.py +++ b/{{cookiecutter.project_slug}}/backend/app/app/tests/utils/user.py @@ -38,6 +38,6 @@ def authentication_token_from_email(email): user = crud.user.create(db_session=db_session, obj_in=user_in) else: user_in = UserUpdate(password=password) - user = crud.user.update(db_session, obj_in=user, db_obj=user_in) + user = crud.user.update(db_session, db_obj=user, obj_in=user_in) return user_authentication_headers(get_server_api(), email, password)