init
This commit is contained in:
0
app/routers/__init__.py
Normal file
0
app/routers/__init__.py
Normal file
127
app/routers/hackathons.py
Normal file
127
app/routers/hackathons.py
Normal file
@@ -0,0 +1,127 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.connection import get_session
|
||||
from app.models.hackathon import Hackathon
|
||||
from app.models.hackathon_participant import HackathonParticipant
|
||||
from app.models.user import User
|
||||
from app.schemas.hackathon import (
|
||||
HackathonCreate,
|
||||
HackathonRead,
|
||||
HackathonReadWithOrganizer,
|
||||
ParticipantRegistration,
|
||||
ParticipantRead,
|
||||
ParticipantConfirm,
|
||||
)
|
||||
from app.auth.dependencies import get_current_user, get_current_organizer
|
||||
|
||||
router = APIRouter(prefix="/hackathons", tags=["Hackathons"])
|
||||
|
||||
|
||||
# ── CRUD ────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@router.post("/", response_model=HackathonRead, status_code=status.HTTP_201_CREATED)
|
||||
def create_hackathon(
|
||||
data: HackathonCreate,
|
||||
session: Session = Depends(get_session),
|
||||
organizer: User = Depends(get_current_organizer),
|
||||
) -> Hackathon:
|
||||
hackathon = Hackathon(**data.model_dump(), organizer_id=organizer.id)
|
||||
session.add(hackathon)
|
||||
session.commit()
|
||||
session.refresh(hackathon)
|
||||
return hackathon
|
||||
|
||||
|
||||
@router.get("/", response_model=list[HackathonRead])
|
||||
def list_hackathons(session: Session = Depends(get_session)) -> list[Hackathon]:
|
||||
return list(session.exec(select(Hackathon)).all())
|
||||
|
||||
|
||||
@router.get("/{hackathon_id}", response_model=HackathonReadWithOrganizer)
|
||||
def get_hackathon(hackathon_id: int, session: Session = Depends(get_session)) -> Hackathon:
|
||||
hackathon = session.get(Hackathon, hackathon_id)
|
||||
if not hackathon:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Хакатон не найден")
|
||||
return hackathon
|
||||
|
||||
|
||||
@router.delete("/{hackathon_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def delete_hackathon(
|
||||
hackathon_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
organizer: User = Depends(get_current_organizer),
|
||||
) -> None:
|
||||
hackathon = session.get(Hackathon, hackathon_id)
|
||||
if not hackathon:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Хакатон не найден")
|
||||
session.delete(hackathon)
|
||||
session.commit()
|
||||
|
||||
|
||||
# ── Регистрация участников ──────────────────────────────────────────────────
|
||||
|
||||
|
||||
@router.post("/{hackathon_id}/register", response_model=ParticipantRead, status_code=status.HTTP_201_CREATED)
|
||||
def register_for_hackathon(
|
||||
hackathon_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> HackathonParticipant:
|
||||
hackathon = session.get(Hackathon, hackathon_id)
|
||||
if not hackathon:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Хакатон не найден")
|
||||
|
||||
existing = session.exec(
|
||||
select(HackathonParticipant).where(
|
||||
HackathonParticipant.user_id == current_user.id,
|
||||
HackathonParticipant.hackathon_id == hackathon_id,
|
||||
)
|
||||
).first()
|
||||
if existing:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Вы уже зарегистрированы")
|
||||
|
||||
participant = HackathonParticipant(
|
||||
user_id=current_user.id,
|
||||
hackathon_id=hackathon_id,
|
||||
)
|
||||
session.add(participant)
|
||||
session.commit()
|
||||
session.refresh(participant)
|
||||
return participant
|
||||
|
||||
|
||||
@router.get("/{hackathon_id}/participants", response_model=list[ParticipantRead])
|
||||
def list_participants(
|
||||
hackathon_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
) -> list[HackathonParticipant]:
|
||||
return list(
|
||||
session.exec(
|
||||
select(HackathonParticipant).where(HackathonParticipant.hackathon_id == hackathon_id)
|
||||
).all()
|
||||
)
|
||||
|
||||
|
||||
@router.patch("/{hackathon_id}/confirm", response_model=ParticipantRead)
|
||||
def confirm_participant(
|
||||
hackathon_id: int,
|
||||
data: ParticipantConfirm,
|
||||
session: Session = Depends(get_session),
|
||||
organizer: User = Depends(get_current_organizer),
|
||||
) -> HackathonParticipant:
|
||||
"""Организатор подтверждает регистрацию участника."""
|
||||
participant = session.exec(
|
||||
select(HackathonParticipant).where(
|
||||
HackathonParticipant.user_id == data.user_id,
|
||||
HackathonParticipant.hackathon_id == hackathon_id,
|
||||
)
|
||||
).first()
|
||||
if not participant:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Регистрация не найдена")
|
||||
participant.is_confirmed = True
|
||||
session.add(participant)
|
||||
session.commit()
|
||||
session.refresh(participant)
|
||||
return participant
|
||||
59
app/routers/submissions.py
Normal file
59
app/routers/submissions.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.connection import get_session
|
||||
from app.models.submission import Submission
|
||||
from app.models.user import User
|
||||
from app.schemas.submission import SubmissionCreate, SubmissionRead, SubmissionReadWithDetails
|
||||
from app.auth.dependencies import get_current_user
|
||||
|
||||
router = APIRouter(prefix="/submissions", tags=["Submissions"])
|
||||
|
||||
|
||||
@router.post("/", response_model=SubmissionRead, status_code=status.HTTP_201_CREATED)
|
||||
def create_submission(
|
||||
data: SubmissionCreate,
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> Submission:
|
||||
submission = Submission(**data.model_dump())
|
||||
session.add(submission)
|
||||
session.commit()
|
||||
session.refresh(submission)
|
||||
return submission
|
||||
|
||||
|
||||
@router.get("/", response_model=list[SubmissionRead])
|
||||
def list_submissions(
|
||||
task_id: int | None = None,
|
||||
team_id: int | None = None,
|
||||
session: Session = Depends(get_session),
|
||||
) -> list[Submission]:
|
||||
query = select(Submission)
|
||||
if task_id is not None:
|
||||
query = query.where(Submission.task_id == task_id)
|
||||
if team_id is not None:
|
||||
query = query.where(Submission.team_id == team_id)
|
||||
return list(session.exec(query).all())
|
||||
|
||||
|
||||
@router.get("/{submission_id}", response_model=SubmissionReadWithDetails)
|
||||
def get_submission(submission_id: int, session: Session = Depends(get_session)) -> Submission:
|
||||
"""Возвращает работу с вложенными данными команды и задачи."""
|
||||
submission = session.get(Submission, submission_id)
|
||||
if not submission:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Работа не найдена")
|
||||
return submission
|
||||
|
||||
|
||||
@router.delete("/{submission_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def delete_submission(
|
||||
submission_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> None:
|
||||
submission = session.get(Submission, submission_id)
|
||||
if not submission:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Работа не найдена")
|
||||
session.delete(submission)
|
||||
session.commit()
|
||||
73
app/routers/tasks.py
Normal file
73
app/routers/tasks.py
Normal file
@@ -0,0 +1,73 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.connection import get_session
|
||||
from app.models.task import Task
|
||||
from app.models.user import User
|
||||
from app.schemas.task import TaskCreate, TaskRead, TaskUpdate
|
||||
from app.auth.dependencies import get_current_organizer
|
||||
|
||||
router = APIRouter(prefix="/tasks", tags=["Tasks"])
|
||||
|
||||
|
||||
@router.post("/", response_model=TaskRead, status_code=status.HTTP_201_CREATED)
|
||||
def create_task(
|
||||
data: TaskCreate,
|
||||
session: Session = Depends(get_session),
|
||||
organizer: User = Depends(get_current_organizer),
|
||||
) -> Task:
|
||||
task = Task(**data.model_dump())
|
||||
session.add(task)
|
||||
session.commit()
|
||||
session.refresh(task)
|
||||
return task
|
||||
|
||||
|
||||
@router.get("/", response_model=list[TaskRead])
|
||||
def list_tasks(
|
||||
hackathon_id: int | None = None,
|
||||
session: Session = Depends(get_session),
|
||||
) -> list[Task]:
|
||||
query = select(Task)
|
||||
if hackathon_id is not None:
|
||||
query = query.where(Task.hackathon_id == hackathon_id)
|
||||
return list(session.exec(query).all())
|
||||
|
||||
|
||||
@router.get("/{task_id}", response_model=TaskRead)
|
||||
def get_task(task_id: int, session: Session = Depends(get_session)) -> Task:
|
||||
task = session.get(Task, task_id)
|
||||
if not task:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Задача не найдена")
|
||||
return task
|
||||
|
||||
|
||||
@router.patch("/{task_id}", response_model=TaskRead)
|
||||
def update_task(
|
||||
task_id: int,
|
||||
data: TaskUpdate,
|
||||
session: Session = Depends(get_session),
|
||||
organizer: User = Depends(get_current_organizer),
|
||||
) -> Task:
|
||||
task = session.get(Task, task_id)
|
||||
if not task:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Задача не найдена")
|
||||
for field, value in data.model_dump(exclude_unset=True).items():
|
||||
setattr(task, field, value)
|
||||
session.add(task)
|
||||
session.commit()
|
||||
session.refresh(task)
|
||||
return task
|
||||
|
||||
|
||||
@router.delete("/{task_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def delete_task(
|
||||
task_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
organizer: User = Depends(get_current_organizer),
|
||||
) -> None:
|
||||
task = session.get(Task, task_id)
|
||||
if not task:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Задача не найдена")
|
||||
session.delete(task)
|
||||
session.commit()
|
||||
118
app/routers/teams.py
Normal file
118
app/routers/teams.py
Normal file
@@ -0,0 +1,118 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.connection import get_session
|
||||
from app.models.team import Team
|
||||
from app.models.team_member import TeamMember
|
||||
from app.models.user import User
|
||||
from app.schemas.team import (
|
||||
TeamCreate,
|
||||
TeamRead,
|
||||
TeamReadWithMembers,
|
||||
TeamMemberAdd,
|
||||
TeamMemberRead,
|
||||
)
|
||||
from app.auth.dependencies import get_current_user
|
||||
|
||||
router = APIRouter(prefix="/teams", tags=["Teams"])
|
||||
|
||||
|
||||
@router.post("/", response_model=TeamRead, status_code=status.HTTP_201_CREATED)
|
||||
def create_team(
|
||||
data: TeamCreate,
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> Team:
|
||||
team = Team(**data.model_dump())
|
||||
session.add(team)
|
||||
session.commit()
|
||||
session.refresh(team)
|
||||
|
||||
# Создатель автоматически становится участником команды
|
||||
member = TeamMember(user_id=current_user.id, team_id=team.id, role="captain")
|
||||
session.add(member)
|
||||
session.commit()
|
||||
session.refresh(team)
|
||||
return team
|
||||
|
||||
|
||||
@router.get("/", response_model=list[TeamRead])
|
||||
def list_teams(
|
||||
hackathon_id: int | None = None,
|
||||
session: Session = Depends(get_session),
|
||||
) -> list[Team]:
|
||||
query = select(Team)
|
||||
if hackathon_id is not None:
|
||||
query = query.where(Team.hackathon_id == hackathon_id)
|
||||
return list(session.exec(query).all())
|
||||
|
||||
|
||||
@router.get("/{team_id}", response_model=TeamReadWithMembers)
|
||||
def get_team(team_id: int, session: Session = Depends(get_session)) -> Team:
|
||||
"""Возвращает команду с вложенным списком участников (one-to-many)."""
|
||||
team = session.get(Team, team_id)
|
||||
if not team:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Команда не найдена")
|
||||
return team
|
||||
|
||||
|
||||
@router.delete("/{team_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def delete_team(
|
||||
team_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> None:
|
||||
team = session.get(Team, team_id)
|
||||
if not team:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Команда не найдена")
|
||||
session.delete(team)
|
||||
session.commit()
|
||||
|
||||
|
||||
# ── Участники команды ───────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@router.post("/{team_id}/members", response_model=TeamMemberRead, status_code=status.HTTP_201_CREATED)
|
||||
def add_member(
|
||||
team_id: int,
|
||||
data: TeamMemberAdd,
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> TeamMember:
|
||||
team = session.get(Team, team_id)
|
||||
if not team:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Команда не найдена")
|
||||
|
||||
existing = session.exec(
|
||||
select(TeamMember).where(
|
||||
TeamMember.user_id == data.user_id,
|
||||
TeamMember.team_id == team_id,
|
||||
)
|
||||
).first()
|
||||
if existing:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Пользователь уже в команде")
|
||||
|
||||
member = TeamMember(user_id=data.user_id, team_id=team_id, role=data.role)
|
||||
session.add(member)
|
||||
session.commit()
|
||||
session.refresh(member)
|
||||
return member
|
||||
|
||||
|
||||
@router.delete("/{team_id}/members/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def remove_member(
|
||||
team_id: int,
|
||||
user_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> None:
|
||||
member = session.exec(
|
||||
select(TeamMember).where(
|
||||
TeamMember.user_id == user_id,
|
||||
TeamMember.team_id == team_id,
|
||||
)
|
||||
).first()
|
||||
if not member:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Участник не найден")
|
||||
session.delete(member)
|
||||
session.commit()
|
||||
66
app/routers/users.py
Normal file
66
app/routers/users.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.connection import get_session
|
||||
from app.models.user import User
|
||||
from app.schemas.user import UserRead, UserUpdate, PasswordChange
|
||||
from app.auth.dependencies import get_current_user
|
||||
from app.auth.utils import verify_password, hash_password
|
||||
|
||||
router = APIRouter(prefix="/users", tags=["Users"])
|
||||
|
||||
|
||||
@router.get("/me", response_model=UserRead)
|
||||
def get_me(current_user: User = Depends(get_current_user)) -> User:
|
||||
return current_user
|
||||
|
||||
|
||||
@router.get("/", response_model=list[UserRead])
|
||||
def list_users(
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> list[User]:
|
||||
return list(session.exec(select(User)).all())
|
||||
|
||||
|
||||
@router.get("/{user_id}", response_model=UserRead)
|
||||
def get_user(
|
||||
user_id: int,
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> User:
|
||||
user = session.get(User, user_id)
|
||||
if not user:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Пользователь не найден")
|
||||
return user
|
||||
|
||||
|
||||
@router.patch("/me", response_model=UserRead)
|
||||
def update_me(
|
||||
data: UserUpdate,
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> User:
|
||||
for field, value in data.model_dump(exclude_unset=True).items():
|
||||
setattr(current_user, field, value)
|
||||
session.add(current_user)
|
||||
session.commit()
|
||||
session.refresh(current_user)
|
||||
return current_user
|
||||
|
||||
|
||||
@router.post("/me/change-password", status_code=status.HTTP_200_OK)
|
||||
def change_password(
|
||||
data: PasswordChange,
|
||||
session: Session = Depends(get_session),
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> dict:
|
||||
if not verify_password(data.old_password, current_user.hashed_password):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Неверный старый пароль",
|
||||
)
|
||||
current_user.hashed_password = hash_password(data.new_password)
|
||||
session.add(current_user)
|
||||
session.commit()
|
||||
return {"detail": "Пароль успешно изменён"}
|
||||
Reference in New Issue
Block a user