Files
rose-ash/events/bp/calendar/services/calendar_view.py
giles f42042ccb7
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m5s
Monorepo: consolidate 7 repos into one
Combines shared, blog, market, cart, events, federation, and account
into a single repository. Eliminates submodule sync, sibling model
copying at build time, and per-app CI orchestration.

Changes:
- Remove per-app .git, .gitmodules, .gitea, submodule shared/ dirs
- Remove stale sibling model copies from each app
- Update all 6 Dockerfiles for monorepo build context (root = .)
- Add build directives to docker-compose.yml
- Add single .gitea/workflows/ci.yml with change detection
- Add .dockerignore for monorepo build context
- Create __init__.py for federation and account (cross-app imports)
2026-02-24 19:44:17 +00:00

110 lines
3.2 KiB
Python

from __future__ import annotations
from datetime import datetime, timezone
from typing import Optional
import calendar as pycalendar
from quart import request
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload, with_loader_criteria
from models.calendars import Calendar, CalendarSlot
def parse_int_arg(name: str, default: Optional[int] = None) -> Optional[int]:
"""Parse an integer query parameter from the request."""
val = request.args.get(name, "").strip()
if not val:
return default
try:
return int(val)
except ValueError:
return default
def add_months(year: int, month: int, delta: int) -> tuple[int, int]:
"""Add (or subtract) months to a given year/month, handling year overflow."""
new_month = month + delta
new_year = year + (new_month - 1) // 12
new_month = ((new_month - 1) % 12) + 1
return new_year, new_month
def build_calendar_weeks(year: int, month: int) -> list[list[dict]]:
"""
Build a calendar grid for the given year and month.
Returns a list of weeks, where each week is a list of 7 day dictionaries.
"""
today = datetime.now(timezone.utc).date()
cal = pycalendar.Calendar(firstweekday=0) # 0 = Monday
weeks: list[list[dict]] = []
for week in cal.monthdatescalendar(year, month):
week_days = []
for d in week:
week_days.append(
{
"date": d,
"in_month": (d.month == month),
"is_today": (d == today),
}
)
weeks.append(week_days)
return weeks
async def get_calendar_by_post_and_slug(
session: AsyncSession,
post_id: int,
calendar_slug: str,
) -> Optional[Calendar]:
"""
Fetch a calendar by post_id and slug, with slots eagerly loaded.
Returns None if not found.
"""
result = await session.execute(
select(Calendar)
.options(
selectinload(Calendar.slots),
with_loader_criteria(CalendarSlot, CalendarSlot.deleted_at.is_(None)),
)
.where(
Calendar.container_type == "page",
Calendar.container_id == post_id,
Calendar.slug == calendar_slug,
Calendar.deleted_at.is_(None),
)
)
return result.scalar_one_or_none()
async def get_calendar_by_slug(
session: AsyncSession,
calendar_slug: str,
) -> Optional[Calendar]:
"""
Fetch a calendar by slug only (for standalone events service).
With slots eagerly loaded. Returns None if not found.
"""
result = await session.execute(
select(Calendar)
.options(
selectinload(Calendar.slots),
with_loader_criteria(CalendarSlot, CalendarSlot.deleted_at.is_(None)),
)
.where(
Calendar.slug == calendar_slug,
Calendar.deleted_at.is_(None),
)
)
return result.scalar_one_or_none()
async def update_calendar_description(
calendar: Calendar,
description: Optional[str],
) -> None:
"""Update calendar description (in-place on the calendar object)."""
calendar.description = description or None