diff --git a/getcloser/.gitignore b/getcloser/.gitignore new file mode 100644 index 0000000..524bf12 --- /dev/null +++ b/getcloser/.gitignore @@ -0,0 +1,75 @@ +node_modules +.vite + + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +*.manifest +*.spec + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# IDE +.vscode/ +.cursor/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +*.log + +# Temporary files +*.tmp +*.temp diff --git a/getcloser/backend/app/api/v1/__init__.py b/getcloser/backend/app/api/v1/__init__.py index 0d9db47..0cad476 100644 --- a/getcloser/backend/app/api/v1/__init__.py +++ b/getcloser/backend/app/api/v1/__init__.py @@ -1,5 +1,7 @@ from api.v1.users import users +from api.v1.teams import teams from fastapi import APIRouter api_router = APIRouter() api_router.include_router(users.router, prefix="/users", tags=["users"]) +api_router.include_router(teams.router, prefix="/teams", tags=["teams"]) diff --git a/getcloser/backend/app/api/v1/teams/teams.py b/getcloser/backend/app/api/v1/teams/teams.py new file mode 100644 index 0000000..aa7e6e8 --- /dev/null +++ b/getcloser/backend/app/api/v1/teams/teams.py @@ -0,0 +1,11 @@ +from fastapi import APIRouter, Depends +from sqlalchemy.orm import Session +from core.database import get_db +from schemas.team_schema import TeamCreateRequest, TeamResponse +from services.team_service import create_team + +router = APIRouter() + +@router.post("/create", response_model=TeamResponse) +def create_team_route(req: TeamCreateRequest, db: Session = Depends(get_db)): + return create_team(db, req) diff --git a/getcloser/backend/app/models/teams.py b/getcloser/backend/app/models/teams.py new file mode 100644 index 0000000..83073f4 --- /dev/null +++ b/getcloser/backend/app/models/teams.py @@ -0,0 +1,14 @@ +from core.database import Base +from sqlalchemy import Column, Integer, UniqueConstraint + + +class Team(Base): + __tablename__ = "teams" + + id = Column(Integer, primary_key=True, index=True) + team_id = Column(Integer, index=True) + user_id = Column(Integer, unique=True, index=True) + + __table_args__ = ( + UniqueConstraint('team_id', 'user_id', name='_team_user_uc'), + ) diff --git a/getcloser/backend/app/schemas/team_schema.py b/getcloser/backend/app/schemas/team_schema.py new file mode 100644 index 0000000..a8aff3a --- /dev/null +++ b/getcloser/backend/app/schemas/team_schema.py @@ -0,0 +1,12 @@ +from pydantic import BaseModel, Field +from typing import List + + +class TeamCreateRequest(BaseModel): + my_id: int + member_ids: List[int] = Field(..., min_items=4, max_items=4, description="팀원 4명의 ID") + + +class TeamResponse(BaseModel): + team_id: int + members_ids: List[int] diff --git a/getcloser/backend/app/services/team_service.py b/getcloser/backend/app/services/team_service.py new file mode 100644 index 0000000..8315702 --- /dev/null +++ b/getcloser/backend/app/services/team_service.py @@ -0,0 +1,27 @@ +from sqlalchemy.orm import Session +from models.teams import Team +from schemas.team_schema import TeamCreateRequest, TeamResponse +from fastapi import HTTPException + +def create_team(db: Session, req: TeamCreateRequest) -> TeamResponse: + all_ids = [req.my_id] + req.member_ids + + existing = db.query(Team).filter(Team.user_id.in_(all_ids)).all() + if existing: + raise HTTPException(status_code=400, detail="Some users are already in a team.") + + last_team = ( + db.query(Team) + .order_by(Team.team_id.desc()) + .with_for_update() + .first() + ) + + new_team_id = (last_team.team_id + 1) if last_team else 1 + + for uid in all_ids: + db.add(Team(team_id=new_team_id, user_id=uid)) + + db.commit() + + return TeamResponse(team_id=new_team_id, members_ids=all_ids)