Files
shinalokandClaude Sonnet 5 cee589bb3e Initial commit: habit tracker PWA with Google OAuth, push notifications
FastAPI + SQLAlchemy/Alembic + MariaDB backend with Jinja2/htmx/Alpine
server-rendered frontend. Multi-user via Google OAuth, daily habit
tracking, monthly/weekly history views, Web Push reminders via
APScheduler, and PWA support (manifest, service worker, offline caching).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 18:06:17 +09:00

44 lines
1.4 KiB
Python

from fastapi import Depends, HTTPException, Request, status
from itsdangerous import BadSignature, SignatureExpired, URLSafeTimedSerializer
from sqlalchemy.orm import Session
from app.config import settings
from app.database import get_db
from app.models.user import User
_serializer = URLSafeTimedSerializer(settings.secret_key, salt="habit-session")
SESSION_MAX_AGE_SECONDS = 60 * 60 * 24 * 30 # 30일
def create_session_token(user_id: int) -> str:
return _serializer.dumps({"user_id": user_id})
def get_session_user_id(request: Request) -> int | None:
token = request.cookies.get(settings.session_cookie_name)
if not token:
return None
try:
data = _serializer.loads(token, max_age=SESSION_MAX_AGE_SECONDS)
except (BadSignature, SignatureExpired):
return None
return data.get("user_id")
def require_login(request: Request, db: Session = Depends(get_db)) -> User:
user_id = get_session_user_id(request)
user = db.get(User, user_id) if user_id is not None else None
if user is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="로그인이 필요합니다")
return user
def get_current_user_optional(request: Request, db: Session) -> User | None:
user_id = get_session_user_id(request)
return db.get(User, user_id) if user_id is not None else None
def is_logged_in(request: Request) -> bool:
return get_session_user_id(request) is not None