Browse Source

Update CRUD utils for users handling password hashing (#106)

* Add some information how to run backand test for local backand development

* Bug fixes in backend app

* 🎨 Update format

*  Use random_email for test_update_user

Co-authored-by: Mocsar Kalman <mocsar.kalman@gravityrd.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
pull/13907/head
Mocsár Kálmán 5 years ago
committed by GitHub
parent
commit
fb874fea35
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      {{cookiecutter.project_slug}}/README.md
  2. 11
      {{cookiecutter.project_slug}}/backend/app/app/crud/crud_user.py
  3. 22
      {{cookiecutter.project_slug}}/backend/app/app/schemas/user.py
  4. 16
      {{cookiecutter.project_slug}}/backend/app/app/tests/crud/test_user.py
  5. 2
      {{cookiecutter.project_slug}}/backend/app/app/tests/utils/user.py

14
{{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. 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 #### Test running stack
If your stack is already up and you just want to run the tests, you can use: If your stack is already up and you just want to run the tests, you can use:

11
{{cookiecutter.project_slug}}/backend/app/app/crud/crud_user.py

@ -3,7 +3,7 @@ from typing import Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.models.user import User 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.core.security import verify_password, get_password_hash
from app.crud.base import CRUDBase from app.crud.base import CRUDBase
@ -24,6 +24,15 @@ class CRUDUser(CRUDBase[User, UserCreate, UserUpdate]):
db_session.refresh(db_obj) db_session.refresh(db_obj)
return 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( def authenticate(
self, db_session: Session, *, email: str, password: str self, db_session: Session, *, email: str, password: str
) -> Optional[User]: ) -> Optional[User]:

22
{{cookiecutter.project_slug}}/backend/app/app/schemas/user.py

@ -11,29 +11,29 @@ class UserBase(BaseModel):
full_name: Optional[str] = None full_name: Optional[str] = None
class UserBaseInDB(UserBase):
id: int = None
class Config:
orm_mode = True
# Properties to receive via API on creation # Properties to receive via API on creation
class UserCreate(UserBaseInDB): class UserCreate(UserBase):
email: EmailStr email: EmailStr
password: str password: str
# Properties to receive via API on update # Properties to receive via API on update
class UserUpdate(UserBaseInDB): class UserUpdate(UserBase):
password: Optional[str] = None password: Optional[str] = None
class UserInDBBase(UserBase):
id: int = None
class Config:
orm_mode = True
# Additional properties to return via API # Additional properties to return via API
class User(UserBaseInDB): class User(UserInDBBase):
pass pass
# Additional properties stored in DB # Additional properties stored in DB
class UserInDB(UserBaseInDB): class UserInDB(UserInDBBase):
hashed_password: str hashed_password: str

16
{{cookiecutter.project_slug}}/backend/app/app/tests/crud/test_user.py

@ -1,8 +1,9 @@
from fastapi.encoders import jsonable_encoder from fastapi.encoders import jsonable_encoder
from app import crud from app import crud
from app.core.security import get_password_hash, verify_password
from app.db.session import db_session 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 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) user_2 = crud.user.get(db_session, id=user.id)
assert user.email == user_2.email assert user.email == user_2.email
assert jsonable_encoder(user) == jsonable_encoder(user_2) 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)

2
{{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) user = crud.user.create(db_session=db_session, obj_in=user_in)
else: else:
user_in = UserUpdate(password=password) 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) return user_authentication_headers(get_server_api(), email, password)

Loading…
Cancel
Save