Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""add statistics range to usersettings

Revision ID: f3a5b7c9d1e2
Revises: c3d4e5f6a7b8
Create Date: 2026-09-08 15:30:00.000000

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = 'f3a5b7c9d1e2'
down_revision: Union[str, Sequence[str], None] = 'c3d4e5f6a7b8'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
op.add_column('usersettings', sa.Column('statistics_range', sa.String(length=20), nullable=False, server_default='alltime'))
op.add_column('usersettings', sa.Column('statistics_custom_from', sa.Date(), nullable=True))
op.add_column('usersettings', sa.Column('statistics_custom_to', sa.Date(), nullable=True))


def downgrade() -> None:
op.drop_column('usersettings', 'statistics_custom_to')
op.drop_column('usersettings', 'statistics_custom_from')
op.drop_column('usersettings', 'statistics_range')
5 changes: 4 additions & 1 deletion backend/app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from enum import Enum
from typing import Optional
from datetime import datetime, timezone
from datetime import date, datetime, timezone

import sqlalchemy as sa
from pydantic import model_validator
Expand Down Expand Up @@ -192,6 +192,9 @@ class UserSettings(SQLModel, table=True):
goal_books_per_year_enabled: bool = Field(default=False)
goal_books_per_year: int = Field(default=25, ge=1)
gamification_enabled: bool = Field(default=True)
statistics_range: str = Field(default="alltime", max_length=20)
statistics_custom_from: Optional[date] = Field(default=None)
statistics_custom_to: Optional[date] = Field(default=None)


class ApiKey(SQLModel, table=True):
Expand Down
18 changes: 18 additions & 0 deletions backend/app/routers/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
UserSettingsRead,
UserSettingsUpdate,
)
from app.routers.statistics import MAX_CUSTOM_RANGE_DAYS
from app.time_utils import utcnow
from app.services.user_deletion import (
assert_not_last_admin,
Expand Down Expand Up @@ -113,6 +114,9 @@ def get_settings(
goal_books_per_year_enabled=settings.goal_books_per_year_enabled,
goal_books_per_year=settings.goal_books_per_year,
gamification_enabled=settings.gamification_enabled,
statistics_range=settings.statistics_range,
statistics_custom_from=settings.statistics_custom_from,
statistics_custom_to=settings.statistics_custom_to,
)


Expand All @@ -130,6 +134,17 @@ def update_settings(
if not settings:
settings = UserSettings(user_id=current_user.id, language="en")
update_data = body.model_dump(exclude_unset=True)
if "statistics_range" in update_data and update_data["statistics_range"] is None:
raise HTTPException(status_code=422, detail="statistics_range cannot be null")
custom_from = update_data.get("statistics_custom_from", settings.statistics_custom_from)
custom_to = update_data.get("statistics_custom_to", settings.statistics_custom_to)
statistics_range = update_data.get("statistics_range", settings.statistics_range)
if statistics_range == "custom" and (custom_from is None or custom_to is None):
raise HTTPException(status_code=422, detail="Custom range requires both dates")
if custom_from is not None and custom_to is not None and custom_from > custom_to:
raise HTTPException(status_code=422, detail="statistics_custom_from cannot be after statistics_custom_to")
if custom_from is not None and custom_to is not None and (custom_to - custom_from).days > MAX_CUSTOM_RANGE_DAYS:
raise HTTPException(status_code=422, detail="Statistics custom range cannot exceed 25 years")
settings.sqlmodel_update(update_data)
if settings.theme != 'custom':
settings.custom_theme = None
Expand All @@ -151,6 +166,9 @@ def update_settings(
goal_books_per_year_enabled=settings.goal_books_per_year_enabled,
goal_books_per_year=settings.goal_books_per_year,
gamification_enabled=settings.gamification_enabled,
statistics_range=settings.statistics_range,
statistics_custom_from=settings.statistics_custom_from,
statistics_custom_to=settings.statistics_custom_to,
)


Expand Down
Loading