CI / lint (push) Canceled after 0s
CI / typecheck (push) Canceled after 0s
CI / unit-tests (push) Canceled after 0s
CI / integration-tests (push) Canceled after 0s
CI / container-build (push) Canceled after 0s
CI / dependency-audit (push) Canceled after 0s
The first authenticated-user concept in Aurora Core -- everything else in this codebase is public, read-only catalog data. Foundation for ratings and a watchlist (not yet built): POST /auth/register, POST /auth/login, GET /auth/me. Security specifics worth knowing: - Passwords hashed with argon2 (via argon2-cffi), never stored plain or logged. - Login returns an identical 401 for a nonexistent email and a wrong password on a real one, including matching response timing (burn_time_like_a_password_check) -- otherwise either the status code or the timing alone lets a client enumerate registered emails. - AURORA_SECRET_KEY now actually signs JWTs (previously defined but unused anywhere) -- .env.example's existing token_urlsafe(48) guidance already produces a long enough key, just flagged its new stakes. - Email matched case-insensitively via explicit normalization in the service layer, not relied on from Pydantic's EmailStr (which does not lowercase the local part). 12 new integration tests (register/login/me over real HTTP via the `client` fixture) plus 10 unit tests for the hashing/JWT logic itself, following the same-day lesson that only unit tests actually execute locally without Postgres -- the auth core is tested for real here rather than only through integration tests that might not run before a deploy. Co-Authored-By: Claude Sonnet 5 <[email protected]>
83 lines
2.1 KiB
Python
83 lines
2.1 KiB
Python
"""SQLAlchemy models.
|
|
|
|
Import every model module here so `Base.metadata` is fully populated for
|
|
Alembic autogeneration and `Base.metadata.create_all()` (used only in
|
|
tests) regardless of which module happens to trigger the import first.
|
|
"""
|
|
|
|
from app.models.artwork import Artwork
|
|
from app.models.base import Base
|
|
from app.models.collection import Collection, CollectionMovie, CollectionRelation, CollectionSeries
|
|
from app.models.company import Company, MovieCompany, SeriesCompany
|
|
from app.models.credit import Credit
|
|
from app.models.external_id import ExternalID
|
|
from app.models.genre import Genre, MovieGenre, SeriesGenre
|
|
from app.models.keyword import Keyword, MovieKeyword, SeriesKeyword
|
|
from app.models.language_country import Certification, Country, Language
|
|
from app.models.movie import (
|
|
Movie,
|
|
MovieAlternateTitle,
|
|
MovieProductionCountry,
|
|
MovieRecommendation,
|
|
MovieSpokenLanguage,
|
|
ReleaseDate,
|
|
)
|
|
from app.models.person import Person
|
|
from app.models.provider import IngestionJob, Provider, ProviderRecord
|
|
from app.models.trending import TrendingEntry
|
|
from app.models.tv import (
|
|
Episode,
|
|
Season,
|
|
Series,
|
|
SeriesAlternateTitle,
|
|
SeriesProductionCountry,
|
|
SeriesSpokenLanguage,
|
|
)
|
|
from app.models.user import User
|
|
from app.models.video import Video
|
|
from app.models.watch_provider import WatchProvider, WatchProviderOffering
|
|
|
|
__all__ = [
|
|
"Base",
|
|
"Artwork",
|
|
"Collection",
|
|
"CollectionMovie",
|
|
"CollectionSeries",
|
|
"CollectionRelation",
|
|
"Company",
|
|
"MovieCompany",
|
|
"SeriesCompany",
|
|
"Credit",
|
|
"ExternalID",
|
|
"Genre",
|
|
"MovieGenre",
|
|
"SeriesGenre",
|
|
"Keyword",
|
|
"MovieKeyword",
|
|
"SeriesKeyword",
|
|
"Language",
|
|
"Country",
|
|
"Certification",
|
|
"Movie",
|
|
"MovieAlternateTitle",
|
|
"MovieSpokenLanguage",
|
|
"MovieProductionCountry",
|
|
"ReleaseDate",
|
|
"MovieRecommendation",
|
|
"Person",
|
|
"Provider",
|
|
"ProviderRecord",
|
|
"IngestionJob",
|
|
"Series",
|
|
"SeriesAlternateTitle",
|
|
"SeriesSpokenLanguage",
|
|
"SeriesProductionCountry",
|
|
"Season",
|
|
"Episode",
|
|
"Video",
|
|
"WatchProvider",
|
|
"WatchProviderOffering",
|
|
"TrendingEntry",
|
|
"User",
|
|
]
|