начал писать регистрацию
This commit is contained in:
parent
c0f0293ce7
commit
3d26a7f212
14
API/app/application/profiles_repository.py
Normal file
14
API/app/application/profiles_repository.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from app.domain.models import Profile
|
||||||
|
|
||||||
|
|
||||||
|
class ProfilesRepository:
|
||||||
|
def __init__(self, db: AsyncSession):
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
async def create(self, profile: Profile) -> Profile:
|
||||||
|
self.db.add(profile)
|
||||||
|
await self.db.commit()
|
||||||
|
await self.db.refresh(profile)
|
||||||
|
return profile
|
||||||
16
API/app/application/roles_repository.py
Normal file
16
API/app/application/roles_repository.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from select import select
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from app.domain.models import Role
|
||||||
|
|
||||||
|
|
||||||
|
class RolesRepository:
|
||||||
|
def __init__(self, db: AsyncSession):
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
async def get_by_id(self, role_id: int) -> Optional[Role]:
|
||||||
|
stmt = select(Role).filter_by(id=role_id)
|
||||||
|
result = await self.db.execute(stmt)
|
||||||
|
return result.scalars().first()
|
||||||
16
API/app/application/teams_repository.py
Normal file
16
API/app/application/teams_repository.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from select import select
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from app.domain.models import Team
|
||||||
|
|
||||||
|
|
||||||
|
class TeamsRepository:
|
||||||
|
def __init__(self, db: AsyncSession):
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
async def get_by_id(self, team_id: int) -> Optional[Team]:
|
||||||
|
stmt = select(Team).filter_by(id=team_id)
|
||||||
|
result = await self.db.execute(stmt)
|
||||||
|
return result.scalars().first()
|
||||||
31
API/app/application/users_repository.py
Normal file
31
API/app/application/users_repository.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
from sqlalchemy import select
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
|
from typing_extensions import Optional
|
||||||
|
|
||||||
|
from app.domain.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class UsersRepository:
|
||||||
|
def __init__(self, db: AsyncSession):
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
async def get_by_id(self, user_id: int) -> Optional[User]:
|
||||||
|
stmt = select(User).filter_by(id=user_id)
|
||||||
|
result = await self.db.execute(stmt)
|
||||||
|
return result.scalars().first()
|
||||||
|
|
||||||
|
async def get_by_login(self, login: str) -> Optional[User]:
|
||||||
|
stmt = (
|
||||||
|
select(User)
|
||||||
|
.filter_by(login=login)
|
||||||
|
.options(joinedload(User.role))
|
||||||
|
)
|
||||||
|
result = await self.db.execute(stmt)
|
||||||
|
return result.scalars().first()
|
||||||
|
|
||||||
|
async def create(self, user: User) -> User:
|
||||||
|
self.db.add(user)
|
||||||
|
await self.db.commit()
|
||||||
|
await self.db.refresh(user)
|
||||||
|
return user
|
||||||
19
API/app/domain/entities/base_profile.py
Normal file
19
API/app/domain/entities/base_profile.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class BaseProfileEntity(BaseModel):
|
||||||
|
first_name: str
|
||||||
|
last_name: str
|
||||||
|
patronymic: Optional[str] = None
|
||||||
|
birthday: datetime.date
|
||||||
|
email: Optional[str] = None
|
||||||
|
phone: Optional[str] = None
|
||||||
|
|
||||||
|
role_id: int
|
||||||
|
team_id: int
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
abstract = True
|
||||||
9
API/app/domain/entities/base_user.py
Normal file
9
API/app/domain/entities/base_user.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class BaseUserEntity(BaseModel):
|
||||||
|
login: str
|
||||||
|
password: str
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
abstract = True
|
||||||
7
API/app/domain/entities/profile.py
Normal file
7
API/app/domain/entities/profile.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from app.domain.entities.base_profile import BaseProfileEntity
|
||||||
|
|
||||||
|
|
||||||
|
class ProfileEntity(BaseProfileEntity):
|
||||||
|
id: Optional[int] = None
|
||||||
6
API/app/domain/entities/register.py
Normal file
6
API/app/domain/entities/register.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from app.domain.entities.base_profile import BaseProfileEntity
|
||||||
|
from app.domain.entities.base_user import BaseUserEntity
|
||||||
|
|
||||||
|
|
||||||
|
class RegisterEntity(BaseUserEntity, BaseProfileEntity):
|
||||||
|
pass
|
||||||
12
API/app/domain/entities/user.py
Normal file
12
API/app/domain/entities/user.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from app.domain.entities.base_user import BaseUserEntity
|
||||||
|
from app.domain.entities.profile import ProfileEntity
|
||||||
|
|
||||||
|
|
||||||
|
class UserEntity(BaseUserEntity):
|
||||||
|
id: Optional[int] = None
|
||||||
|
|
||||||
|
profile_id: int
|
||||||
|
|
||||||
|
profile: Optional[ProfileEntity] = None
|
||||||
@ -11,4 +11,4 @@ class ProfilePhoto(AdvancedBaseModel):
|
|||||||
|
|
||||||
profile_id = Column(Integer, ForeignKey('profiles.id'), nullable=False)
|
profile_id = Column(Integer, ForeignKey('profiles.id'), nullable=False)
|
||||||
|
|
||||||
profile = relationship('Profile', back_populates='photos')
|
profile = relationship('Profile', back_populates='profile_photos')
|
||||||
@ -21,5 +21,5 @@ class Profile(AdvancedBaseModel):
|
|||||||
team = relationship('Team', back_populates='profiles')
|
team = relationship('Team', back_populates='profiles')
|
||||||
|
|
||||||
user = relationship('User', back_populates='profile')
|
user = relationship('User', back_populates='profile')
|
||||||
profile_photo = relationship('ProfilePhoto', back_populates='profile')
|
profile_photos = relationship('ProfilePhoto', back_populates='profile')
|
||||||
projects = relationship('ProjectMember', back_populates='profile')
|
projects = relationship('ProjectMember', back_populates='profile')
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from sqlalchemy import Column, VARCHAR, ForeignKey, Integer
|
from sqlalchemy import Column, VARCHAR, ForeignKey, Integer
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
from werkzeug.security import check_password_hash, generate_password_hash
|
||||||
|
|
||||||
from app.domain.models.base import AdvancedBaseModel
|
from app.domain.models.base import AdvancedBaseModel
|
||||||
|
|
||||||
@ -13,3 +14,9 @@ class User(AdvancedBaseModel):
|
|||||||
profile_id = Column(Integer, ForeignKey('profiles.id'), nullable=False)
|
profile_id = Column(Integer, ForeignKey('profiles.id'), nullable=False)
|
||||||
|
|
||||||
profile = relationship('Profile', back_populates='user')
|
profile = relationship('Profile', back_populates='user')
|
||||||
|
|
||||||
|
def check_password(self, password):
|
||||||
|
return check_password_hash(self.password, password)
|
||||||
|
|
||||||
|
def set_password(self, password):
|
||||||
|
self.password = generate_password_hash(password)
|
||||||
|
|||||||
93
API/app/infrastructure/users_service.py
Normal file
93
API/app/infrastructure/users_service.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from fastapi import HTTPException, status
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from app.application.profiles_repository import ProfilesRepository
|
||||||
|
from app.application.roles_repository import RolesRepository
|
||||||
|
from app.application.teams_repository import TeamsRepository
|
||||||
|
from app.application.users_repository import UsersRepository
|
||||||
|
from app.domain.entities.register import RegisterEntity
|
||||||
|
from app.domain.entities.user import UserEntity
|
||||||
|
from app.domain.models import User, Profile
|
||||||
|
|
||||||
|
|
||||||
|
class UsersService:
|
||||||
|
def __init__(self, db: AsyncSession):
|
||||||
|
self.users_repository = UsersRepository(db)
|
||||||
|
self.teams_repository = TeamsRepository(db)
|
||||||
|
self.roles_repository = RolesRepository(db)
|
||||||
|
self.profiles_repository = ProfilesRepository(db)
|
||||||
|
|
||||||
|
async def register_user(self, register_entity: RegisterEntity) -> Optional[UserEntity]:
|
||||||
|
team = await self.teams_repository.get_by_id(register_entity.team_id)
|
||||||
|
if team is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail="The team with this ID was not found",
|
||||||
|
)
|
||||||
|
|
||||||
|
role = await self.roles_repository.get_by_id(register_entity.role_id)
|
||||||
|
if role is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail="The role with this ID was not found",
|
||||||
|
)
|
||||||
|
|
||||||
|
user_model, profile_model = self.register_entity_to_models(register_entity)
|
||||||
|
|
||||||
|
profile_model = await self.profiles_repository.create(profile_model)
|
||||||
|
user_model.profile_id = profile_model.id
|
||||||
|
user_model = await self.users_repository.create(user_model)
|
||||||
|
|
||||||
|
return UserEntity
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_strong_password(password):
|
||||||
|
if len(password) < 8:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not any(char.isupper() for char in password):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not any(char.islower() for char in password):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not any(char.isdigit() for char in password):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not any(char in "!@#$%^&*()_+" for char in password):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not any(char.isalpha() for char in password):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def register_entity_to_models(register_entity: RegisterEntity) -> tuple[User, Profile]:
|
||||||
|
user = User(
|
||||||
|
login=register_entity.login,
|
||||||
|
)
|
||||||
|
|
||||||
|
user.set_password(register_entity.password)
|
||||||
|
|
||||||
|
pofile = Profile(
|
||||||
|
first_name=register_entity.first_name,
|
||||||
|
last_name=register_entity.last_name,
|
||||||
|
patronymic=register_entity.patronymic,
|
||||||
|
birthday=register_entity.birthday,
|
||||||
|
email=register_entity.email,
|
||||||
|
phone=register_entity.phone,
|
||||||
|
role_id=register_entity.role_id,
|
||||||
|
team_id=register_entity.team_id
|
||||||
|
)
|
||||||
|
|
||||||
|
return user, pofile
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def user_model_to_entity(user_model: User) -> UserEntity:
|
||||||
|
return UserEntity(
|
||||||
|
id=user_model.id,
|
||||||
|
login=user_model.login,
|
||||||
|
)
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
|
def start_app():
|
||||||
|
api_app = FastAPI()
|
||||||
|
|
||||||
|
api_app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=["http//localhost:5173"],
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
return api_app
|
||||||
|
|
||||||
|
app = start_app()
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def root():
|
||||||
|
return {"message": "Hello API"}
|
||||||
Loading…
x
Reference in New Issue
Block a user