mirror of
https://github.com/FutureOfMedTech-FITM-hack/backend.git
synced 2024-11-24 23:33:44 +03:00
updated user registration, user info
This commit is contained in:
parent
8ac1c37e5d
commit
5961d7dbe0
|
@ -9,14 +9,14 @@ from . import schemas, services
|
||||||
from .schemas import User
|
from .schemas import User
|
||||||
|
|
||||||
|
|
||||||
async def get_user(session: AsyncSession, username: str) -> User | None:
|
async def get_user_by_email(session: AsyncSession, email: str) -> User | None:
|
||||||
r = await session.execute(select(UserScheme).where(UserScheme.username == username))
|
r = await session.execute(select(UserScheme).where(UserScheme.email == email))
|
||||||
user = r.scalars().first()
|
user = r.scalars().first()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
async def get_user_by_email(session: AsyncSession, email: str) -> User | None:
|
async def get_user(session: AsyncSession, pk: int) -> User | None:
|
||||||
r = await session.execute(select(UserScheme).where(UserScheme.email == email))
|
r = await session.execute(select(UserScheme).where(UserScheme.id == pk))
|
||||||
user = r.scalars().first()
|
user = r.scalars().first()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
@ -37,17 +37,15 @@ async def get_users(
|
||||||
|
|
||||||
|
|
||||||
async def create_user(session: AsyncSession, user: schemas.UserCreate) -> UserScheme:
|
async def create_user(session: AsyncSession, user: schemas.UserCreate) -> UserScheme:
|
||||||
if await get_user(session, user.username):
|
|
||||||
raise HTTPException(status_code=400, detail="Username already taken")
|
|
||||||
|
|
||||||
if await get_user_by_email(session, user.email):
|
if await get_user_by_email(session, user.email):
|
||||||
raise HTTPException(status_code=400, detail="Email already taken")
|
raise HTTPException(status_code=422, detail="Email already taken")
|
||||||
|
|
||||||
hashed_password = services.get_password_hash(user.password)
|
hashed_password = services.get_password_hash(user.password)
|
||||||
db_user = UserScheme(
|
db_user = UserScheme(
|
||||||
email=user.email,
|
email=user.email,
|
||||||
username=user.username,
|
|
||||||
fullname=user.fullname,
|
fullname=user.fullname,
|
||||||
|
gender=user.gender,
|
||||||
|
born=user.born.date(),
|
||||||
hashed_password=hashed_password,
|
hashed_password=hashed_password,
|
||||||
disabled=False,
|
disabled=False,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from pydantic import BaseModel, EmailStr
|
from pydantic import BaseModel, EmailStr
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,11 +9,11 @@ class Token(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class TokenData(BaseModel):
|
class TokenData(BaseModel):
|
||||||
username: str
|
email: EmailStr
|
||||||
|
|
||||||
|
|
||||||
class UserBase(BaseModel):
|
class UserBase(BaseModel):
|
||||||
username: str
|
email: EmailStr
|
||||||
|
|
||||||
|
|
||||||
class UserLogin(UserBase):
|
class UserLogin(UserBase):
|
||||||
|
@ -20,13 +22,13 @@ class UserLogin(UserBase):
|
||||||
|
|
||||||
class UserCreate(UserBase):
|
class UserCreate(UserBase):
|
||||||
password: str
|
password: str
|
||||||
email: EmailStr
|
|
||||||
fullname: str
|
fullname: str
|
||||||
|
gender: str
|
||||||
|
born: datetime
|
||||||
|
|
||||||
|
|
||||||
class UserPublicInfo(UserBase):
|
class UserPublicInfo(UserBase):
|
||||||
id: int
|
id: int
|
||||||
email: EmailStr
|
|
||||||
fullname: str | None
|
fullname: str | None
|
||||||
disabled: bool
|
disabled: bool
|
||||||
|
|
||||||
|
@ -36,8 +38,7 @@ class UserPublicInfo(UserBase):
|
||||||
|
|
||||||
class User(UserBase):
|
class User(UserBase):
|
||||||
id: int
|
id: int
|
||||||
email: EmailStr
|
fullname: str
|
||||||
fullname: str | None
|
|
||||||
hashed_password: str
|
hashed_password: str
|
||||||
disabled: bool
|
disabled: bool
|
||||||
is_manager: bool
|
is_manager: bool
|
||||||
|
|
|
@ -32,8 +32,8 @@ def get_password_hash(password: str) -> str:
|
||||||
return pwd_context.hash(password)
|
return pwd_context.hash(password)
|
||||||
|
|
||||||
|
|
||||||
async def get_user(session: AsyncSession, username: str) -> User:
|
async def get_user(session: AsyncSession, email: str) -> User:
|
||||||
db_user = await crud.get_user(session, username=username)
|
db_user = await crud.get_user_by_email(session, email=email)
|
||||||
if db_user is None:
|
if db_user is None:
|
||||||
raise HTTPException(status_code=404, detail="User not found")
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
return db_user
|
return db_user
|
||||||
|
@ -78,13 +78,13 @@ async def get_current_user(
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
payload = jwt.decode(token, SECRET_KEY, algorithms=[JWT_ALGORITHM])
|
payload = jwt.decode(token, SECRET_KEY, algorithms=[JWT_ALGORITHM])
|
||||||
username: str = payload.get("sub")
|
email: str = payload.get("sub")
|
||||||
if username is None:
|
if email is None:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
token_data = TokenData(username=username)
|
token_data = TokenData(email=email)
|
||||||
except JWTError:
|
except JWTError:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
user = await get_user(session, token_data.username)
|
user = await get_user(session, token_data.email)
|
||||||
if user is None:
|
if user is None:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
return user
|
return user
|
||||||
|
@ -96,3 +96,16 @@ async def get_current_active_user(
|
||||||
if current_user.disabled:
|
if current_user.disabled:
|
||||||
raise HTTPException(status_code=400, detail="Inactive user")
|
raise HTTPException(status_code=400, detail="Inactive user")
|
||||||
return current_user
|
return current_user
|
||||||
|
|
||||||
|
|
||||||
|
async def get_current_active_manager(
|
||||||
|
current_user: User = Depends(get_current_user),
|
||||||
|
) -> User:
|
||||||
|
if current_user.disabled:
|
||||||
|
raise HTTPException(status_code=400, detail="Inactive user")
|
||||||
|
if not current_user.is_manager:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
detail="You are not allowed to access this info",
|
||||||
|
)
|
||||||
|
return current_user
|
||||||
|
|
|
@ -23,7 +23,7 @@ async def login_for_access_token(
|
||||||
data: UserLogin,
|
data: UserLogin,
|
||||||
session: AsyncSession = Depends(get_db_session),
|
session: AsyncSession = Depends(get_db_session),
|
||||||
) -> Dict[str, str]:
|
) -> Dict[str, str]:
|
||||||
user = await authenticate_user(session, data.username, data.password)
|
user = await authenticate_user(session, data.email, data.password)
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
@ -32,7 +32,7 @@ async def login_for_access_token(
|
||||||
)
|
)
|
||||||
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||||
access_token = create_access_token(
|
access_token = create_access_token(
|
||||||
data={"sub": user.username},
|
data={"sub": user.email},
|
||||||
expires_delta=access_token_expires,
|
expires_delta=access_token_expires,
|
||||||
)
|
)
|
||||||
return {"access_token": access_token, "token_type": "bearer"}
|
return {"access_token": access_token, "token_type": "bearer"}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
from pydantic import EmailStr
|
from pydantic import EmailStr
|
||||||
from sqlalchemy import Boolean, Column, Integer, String
|
from sqlalchemy import Boolean, Column, Date, Integer, String
|
||||||
|
|
||||||
from med_backend.db.base import Base
|
from med_backend.db.base import Base
|
||||||
|
|
||||||
|
@ -10,12 +12,11 @@ class UserScheme(Base):
|
||||||
__tablename__ = "users"
|
__tablename__ = "users"
|
||||||
|
|
||||||
id: int = Column(Integer, primary_key=True, index=True)
|
id: int = Column(Integer, primary_key=True, index=True)
|
||||||
username: str = Column(String, unique=True, index=True, nullable=False)
|
|
||||||
email: EmailStr = Column(String, unique=True, index=True, nullable=False)
|
email: EmailStr = Column(String, unique=True, index=True, nullable=False)
|
||||||
fullname: str = Column(String, default="")
|
fullname: str = Column(String, default="")
|
||||||
hashed_password: str = Column(String)
|
hashed_password: str = Column(String)
|
||||||
gender: str = Column(String, default="Не выбран")
|
gender: str = Column(String, default="Не выбран")
|
||||||
age: int = Column(Integer, default=0)
|
born: date = Column(Date, nullable=False)
|
||||||
latest_form_result: str = Column(String, default="ok")
|
latest_form_result: str = Column(String, default="ok")
|
||||||
|
|
||||||
is_manager: bool = Column(Boolean, default=False)
|
is_manager: bool = Column(Boolean, default=False)
|
||||||
|
|
|
@ -1,12 +1,34 @@
|
||||||
from pydantic import EmailStr
|
from datetime import date, datetime
|
||||||
|
|
||||||
from med_backend.auth.schemas import UserBase
|
from dateutil.relativedelta import relativedelta
|
||||||
|
from pydantic import BaseModel, EmailStr, root_validator
|
||||||
|
|
||||||
|
|
||||||
class ExtendedUser(UserBase):
|
class ExtendedUser(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
fullname: str
|
fullname: str
|
||||||
age: int
|
gender: str
|
||||||
|
born: date
|
||||||
|
|
||||||
|
@root_validator(pre=False)
|
||||||
|
def _set_fields(cls, values):
|
||||||
|
"""This is a validator that sets the field values based on the
|
||||||
|
the user's account type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
values (dict): Stores the attributes of the User object.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The attributes of the user object with the user's fields.
|
||||||
|
"""
|
||||||
|
values["key"] = values["id"]
|
||||||
|
values["fio"] = values["fullname"]
|
||||||
|
values["age"] = relativedelta(datetime.now(), values["born"]).years
|
||||||
|
|
||||||
|
values.pop("id")
|
||||||
|
values.pop("fullname")
|
||||||
|
values.pop("born")
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
class ListUser(ExtendedUser):
|
class ListUser(ExtendedUser):
|
||||||
|
@ -17,7 +39,6 @@ class ListUser(ExtendedUser):
|
||||||
|
|
||||||
|
|
||||||
class FullUser(ListUser):
|
class FullUser(ListUser):
|
||||||
gender: str
|
|
||||||
email: EmailStr
|
email: EmailStr
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from starlette import status
|
|
||||||
|
|
||||||
from med_backend.auth.crud import get_users
|
from med_backend.auth import crud
|
||||||
from med_backend.auth.schemas import User
|
from med_backend.auth.schemas import User
|
||||||
from med_backend.auth.services import get_current_active_user
|
from med_backend.auth.services import get_current_active_manager
|
||||||
from med_backend.db.dependencies import get_db_session
|
from med_backend.db.dependencies import get_db_session
|
||||||
from med_backend.users.schemas import ListUser
|
from med_backend.users.schemas import FullUser, ListUser
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
@ -15,13 +14,20 @@ router = APIRouter()
|
||||||
async def get_all_users(
|
async def get_all_users(
|
||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
limit: int = 100,
|
limit: int = 100,
|
||||||
current_user: User = Depends(get_current_active_user),
|
current_user: User = Depends(get_current_active_manager),
|
||||||
session: AsyncSession = Depends(get_db_session),
|
session: AsyncSession = Depends(get_db_session),
|
||||||
):
|
):
|
||||||
if not current_user.is_manager:
|
users = await crud.get_users(session, skip, limit)
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
||||||
detail="You are not allowed to access this info",
|
|
||||||
)
|
|
||||||
users = await get_users(session, skip, limit)
|
|
||||||
return users
|
return users
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{key}", response_model=FullUser)
|
||||||
|
async def get_user(
|
||||||
|
key: int,
|
||||||
|
current_user: User = Depends(get_current_active_manager),
|
||||||
|
session: AsyncSession = Depends(get_db_session),
|
||||||
|
):
|
||||||
|
user = await crud.get_user(session, key)
|
||||||
|
if not user:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
return user
|
||||||
|
|
17
poetry.lock
generated
17
poetry.lock
generated
|
@ -983,6 +983,17 @@ python-versions = "*"
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pytest = ">=2.6.0"
|
pytest = ">=2.6.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-dateutil"
|
||||||
|
version = "2.8.2"
|
||||||
|
description = "Extensions to the standard Python datetime module"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
six = ">=1.5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-decouple"
|
name = "python-decouple"
|
||||||
version = "3.6"
|
version = "3.6"
|
||||||
|
@ -1399,7 +1410,7 @@ tokenize-rt = ">=2.1"
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.9"
|
python-versions = "^3.9"
|
||||||
content-hash = "ead3885108db4ad12e4fadd52509671806884feda6607c3364807ebb210f69a2"
|
content-hash = "322a94830a4e40dca70295059b87f26843820996227f5294bb417b00ff86a0f2"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
anyio = [
|
anyio = [
|
||||||
|
@ -2201,6 +2212,10 @@ pytest-cov = [
|
||||||
pytest-env = [
|
pytest-env = [
|
||||||
{file = "pytest-env-0.6.2.tar.gz", hash = "sha256:7e94956aef7f2764f3c147d216ce066bf6c42948bb9e293169b1b1c880a580c2"},
|
{file = "pytest-env-0.6.2.tar.gz", hash = "sha256:7e94956aef7f2764f3c147d216ce066bf6c42948bb9e293169b1b1c880a580c2"},
|
||||||
]
|
]
|
||||||
|
python-dateutil = [
|
||||||
|
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
|
||||||
|
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
|
||||||
|
]
|
||||||
python-decouple = [
|
python-decouple = [
|
||||||
{file = "python-decouple-3.6.tar.gz", hash = "sha256:2838cdf77a5cf127d7e8b339ce14c25bceb3af3e674e039d4901ba16359968c7"},
|
{file = "python-decouple-3.6.tar.gz", hash = "sha256:2838cdf77a5cf127d7e8b339ce14c25bceb3af3e674e039d4901ba16359968c7"},
|
||||||
{file = "python_decouple-3.6-py3-none-any.whl", hash = "sha256:6cf502dc963a5c642ea5ead069847df3d916a6420cad5599185de6bab11d8c2e"},
|
{file = "python_decouple-3.6-py3-none-any.whl", hash = "sha256:6cf502dc963a5c642ea5ead069847df3d916a6420cad5599185de6bab11d8c2e"},
|
||||||
|
|
|
@ -26,6 +26,7 @@ python-decouple = "^3.6"
|
||||||
python-jose = {extras = ["cryptography"], version = "^3.3.0"}
|
python-jose = {extras = ["cryptography"], version = "^3.3.0"}
|
||||||
passlib = {extras = ["bcrypt"], version = "^1.7.4"}
|
passlib = {extras = ["bcrypt"], version = "^1.7.4"}
|
||||||
python-multipart = "^0.0.5"
|
python-multipart = "^0.0.5"
|
||||||
|
python-dateutil = "^2.8.2"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pytest = "^7.1.3"
|
pytest = "^7.1.3"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user