начал писать регистрацию

This commit is contained in:
Archibald 2025-04-19 13:01:45 +05:00
parent c0f0293ce7
commit 3d26a7f212
14 changed files with 253 additions and 2 deletions

View 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

View 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()

View 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()

View 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

View 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

View File

@ -0,0 +1,9 @@
from pydantic import BaseModel
class BaseUserEntity(BaseModel):
login: str
password: str
class Config:
abstract = True

View File

@ -0,0 +1,7 @@
from typing import Optional
from app.domain.entities.base_profile import BaseProfileEntity
class ProfileEntity(BaseProfileEntity):
id: Optional[int] = None

View 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

View 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

View File

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

View File

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

View File

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

View 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,
)

View File

@ -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"}