Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
- uses: isort/isort-action@master
with:
requirementsFiles: "requirements.txt requirements.dev.txt"
- uses: psf/black@stable
- uses: psf/black@23.11.0
- name: Comment if linting failed
if: failure()
uses: thollander/actions-comment-pull-request@v2
Expand Down
4 changes: 4 additions & 0 deletions calendar_backend/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
EventsGroups,
EventsLecturers,
EventsRooms,
EventUser,
EventUserStatus,
Group,
Lecturer,
Room,
Expand All @@ -27,4 +29,6 @@
"EventsRooms",
"ApproveStatuses",
"EventsGroups",
"EventUser",
"EventUserStatus",
]
18 changes: 18 additions & 0 deletions calendar_backend/models/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
from .base import ApproveStatuses, BaseDbModel


class EventUserStatus(str, Enum):
NO_STATUS: str = "no_status"
GOING: str = "going"
NOT_GOING: str = "not_going"
ATTENDED: str = "attended"


class Credentials(BaseDbModel):
"""User credentials"""

Expand Down Expand Up @@ -211,3 +218,14 @@ class CommentEvent(BaseDbModel):
foreign_keys="CommentEvent.event_id",
primaryjoin="and_(Event.id==CommentEvent.event_id, not_(Event.is_deleted))",
)


class EventUser(BaseDbModel):
id: Mapped[int] = mapped_column(Integer, primary_key=True)
event_id: Mapped[int] = mapped_column(Integer, ForeignKey("event.id"), nullable=False)
user_id: Mapped[int] = mapped_column(Integer, nullable=False)
status: Mapped[EventUserStatus] = mapped_column(DbEnum(EventUserStatus, native_enum=False), nullable=False)
updated_at: Mapped[datetime] = mapped_column(
DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow
)
is_deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
2 changes: 2 additions & 0 deletions calendar_backend/routes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from .event.comment import router as event_comment_router
from .event.comment_review import router as event_comment_review_router
from .event.event import router as event_router
from .event.user_event import router as user_event_router
from .group.group import router as group_router
from .lecturer.comment import router as lecturer_comment_router
from .lecturer.comment_review import router as lecturer_comment_review_router
Expand Down Expand Up @@ -128,3 +129,4 @@ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -
app.include_router(event_router)
app.include_router(event_comment_router)
app.include_router(event_comment_review_router)
app.include_router(user_event_router)
2 changes: 1 addition & 1 deletion calendar_backend/routes/event/event.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
from datetime import date, datetime, timedelta
from datetime import date, timedelta
from typing import Literal

from auth_lib.fastapi import UnionAuth
Expand Down
65 changes: 65 additions & 0 deletions calendar_backend/routes/event/user_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from auth_lib.fastapi import UnionAuth
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi_sqlalchemy import db

from calendar_backend.exceptions import ObjectNotFound
from calendar_backend.models import Event, EventUser
from calendar_backend.routes.models.visit import VisitRequest, VisitResponse


router = APIRouter(prefix="/event", tags=["Event: Visit"])


@router.post("/{event_id}/visit", response_model=VisitResponse)
async def set_event_visit_status(
event_id: int, visit: VisitRequest, auth: dict = Depends(UnionAuth(scopes=[]))
Comment thread
petrCher marked this conversation as resolved.
Outdated
Comment thread
petrCher marked this conversation as resolved.
Outdated
) -> VisitResponse:
"""
Отметить посещение мероприятия для текущего пользователя.
Comment thread
petrCher marked this conversation as resolved.
Outdated
"""
user_id = auth.get('id')
if user_id is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User ID not found in authentication data",
)

try:
_ = Event.get(event_id, with_deleted=False, session=db.session)
Comment thread
petrCher marked this conversation as resolved.
Outdated
except ObjectNotFound:
raise HTTPException(
Comment thread
petrCher marked this conversation as resolved.
Outdated
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Event with id {event_id} not found",
)

existing = (
db.session.query(EventUser)
Comment thread
petrCher marked this conversation as resolved.
Outdated
.filter(
EventUser.event_id == event_id,
EventUser.user_id == user_id,
EventUser.is_deleted == False,
)
.first()
)

if existing:
existing.status = visit.status
db.session.flush()
Comment thread
petrCher marked this conversation as resolved.
Outdated
result = existing
else:
result = EventUser.create(
session=db.session,
event_id=event_id,
user_id=user_id,
status=visit.status,
)

db.session.commit()
Comment thread
petrCher marked this conversation as resolved.
Outdated

return VisitResponse(
Comment thread
petrCher marked this conversation as resolved.
Outdated
id=result.id,
event_id=result.event_id,
user_id=result.user_id,
status=result.status,
updated_at=result.updated_at.isoformat(),
)
3 changes: 3 additions & 0 deletions calendar_backend/routes/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
Photo,
)
from .room import GetListRoom, RoomEvents, RoomPatch, RoomPost
from .visit import VisitRequest, VisitResponse


__all__ = (
Expand Down Expand Up @@ -46,4 +47,6 @@
"RoomEvents",
"RoomPatch",
"RoomPost",
"VisitRequest",
Comment thread
petrCher marked this conversation as resolved.
Outdated
"VisitResponse",
)
17 changes: 17 additions & 0 deletions calendar_backend/routes/models/visit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from pydantic import BaseModel

from calendar_backend.models import EventUserStatus


class VisitRequest(BaseModel):
Comment thread
petrCher marked this conversation as resolved.
Outdated
status: EventUserStatus


class VisitResponse(BaseModel):
Comment thread
petrCher marked this conversation as resolved.
Outdated
id: int
event_id: int
user_id: int
status: EventUserStatus
updated_at: str # ISO-формат
Comment thread
petrCher marked this conversation as resolved.
Outdated

model_config = {"from_attributes": True}
Comment thread
petrCher marked this conversation as resolved.
Outdated
50 changes: 50 additions & 0 deletions migrations/versions/b060027b11b3_eventuser_building.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""EventUser building

Revision ID: b060027b11b3
Revises: 55a049fde8f4
Create Date: 2026-04-20 17:56:39.185374

"""

import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
revision = 'b060027b11b3'
down_revision = '55a049fde8f4'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
'event_user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('event_id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column(
'status',
sa.Enum('NO_STATUS', 'GOING', 'NOT_GOING', 'ATTENDED', name='eventuserstatus', native_enum=False),
nullable=False,
),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.Column('is_deleted', sa.Boolean(), nullable=False),
sa.ForeignKeyConstraint(
['event_id'],
['event.id'],
),
sa.PrimaryKeyConstraint('id'),
)
op.drop_constraint(op.f('lesson_group_id_fkey'), 'event', type_='foreignkey')
op.drop_column('event', 'group_id')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('event', sa.Column('group_id', sa.INTEGER(), autoincrement=False, nullable=True))
op.create_foreign_key(op.f('lesson_group_id_fkey'), 'event', 'group', ['group_id'], ['id'])
op.drop_table('event_user')
# ### end Alembic commands ###
2 changes: 1 addition & 1 deletion requirements.dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ pytest
pytest-cov
requests
pytest-mock
black
black==23.11.0
isort
autoflake
Loading