diff --git a/app/database/events.py b/app/database/events.py index e473adb..d97c281 100644 --- a/app/database/events.py +++ b/app/database/events.py @@ -1,12 +1,22 @@ from __future__ import annotations -from datetime import datetime +from datetime import UTC, datetime from enum import Enum import json +from typing import TYPE_CHECKING -from app.database.lazer_user import User +from sqlmodel import ( + BigInteger, + Column, + DateTime, + Field, + ForeignKey, + Relationship, + SQLModel, +) -from sqlmodel import Field, Relationship, SQLModel +if TYPE_CHECKING: + from app.database.lazer_user import User class EventType(str, Enum): @@ -28,15 +38,20 @@ class EventType(str, Enum): class EventBase(SQLModel): id: int = Field(default=None, primary_key=True) - createdAt: datetime + created_at: datetime = Field( + sa_column=Column(DateTime(timezone=True), default=datetime.now(UTC)) + ) type: EventType event_payload: str class Event(EventBase, table=True): __tablename__ = "user_events" # pyright: ignore[reportAssignmentType] - user_id: int | None = Field(default=None, foreign_key="lazer_users.id") - user: User = Relationship(back_populates="events") + user_id: int | None = Field( + default=None, + sa_column=Column(BigInteger, ForeignKey("lazer_users.id"), index=True), + ) + user: "User" = Relationship(back_populates="events") class EventResp(EventBase): diff --git a/app/database/lazer_user.py b/app/database/lazer_user.py index 9a9a811..0a28027 100644 --- a/app/database/lazer_user.py +++ b/app/database/lazer_user.py @@ -1,7 +1,6 @@ from datetime import UTC, datetime, timedelta from typing import TYPE_CHECKING, NotRequired, TypedDict -from app.database.events import Event from app.models.model import UTCBaseModel from app.models.score import GameMode from app.models.user import Country, Page @@ -10,6 +9,7 @@ from .achievement import UserAchievement, UserAchievementResp from .beatmap_playcounts import BeatmapPlaycounts from .counts import CountResp, MonthlyPlaycounts, ReplayWatchedCount from .daily_challenge import DailyChallengeStats, DailyChallengeStatsResp +from .events import Event from .rank_history import RankHistory, RankHistoryResp, RankTop from .statistics import UserStatistics, UserStatisticsResp from .team import Team, TeamMember diff --git a/migrations/versions/198227d190b8_user_add_events.py b/migrations/versions/198227d190b8_user_add_events.py new file mode 100644 index 0000000..790e1cd --- /dev/null +++ b/migrations/versions/198227d190b8_user_add_events.py @@ -0,0 +1,66 @@ +"""user: add events + +Revision ID: 198227d190b8 +Revises: b6a304d96a2d +Create Date: 2025-08-12 15:12:49.860825 + +""" + +from __future__ import annotations + +from collections.abc import Sequence + +from alembic import op +import sqlalchemy as sa +import sqlmodel + +# revision identifiers, used by Alembic. +revision: str = "198227d190b8" +down_revision: str | Sequence[str] | None = "b6a304d96a2d" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +def upgrade() -> None: + """Upgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "user_events", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("created_at", sa.DateTime(timezone=True), nullable=True), + sa.Column( + "type", + sa.Enum( + "ACHIEVEMENT", + "BEATMAP_PLAYCOUNT", + "BEATMAPSET_APPROVE", + "BEATMAPSET_DELETE", + "BEATMAPSET_REVIVE", + "BEATMAPSET_UPDATE", + "BEATMAPSET_UPLOAD", + "RANK", + "RANK_LOST", + "USERNAME_CHANGE", + name="eventtype", + ), + nullable=False, + ), + sa.Column("event_payload", sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column("user_id", sa.BigInteger(), nullable=True), + sa.ForeignKeyConstraint( + ["user_id"], + ["lazer_users.id"], + ), + sa.PrimaryKeyConstraint("id"), + ) + op.create_index( + op.f("ix_user_events_user_id"), "user_events", ["user_id"], unique=False + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table("user_events") + # ### end Alembic commands ###