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>
This commit is contained in:
Mocsár Kálmán
2020-04-17 09:20:00 +02:00
committed by GitHub
parent 2b9ed9333a
commit fb874fea35
5 changed files with 54 additions and 17 deletions

View File

@@ -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:

View File

@@ -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]:

View File

@@ -11,29 +11,29 @@ class UserBase(BaseModel):
full_name: Optional[str] = None 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 id: int = None
class Config: class Config:
orm_mode = True 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 # 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

View File

@@ -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)

View File

@@ -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)