Coverage for src / mysingle / auth / models.py: 0%
33 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-02 00:58 +0900
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-02 00:58 +0900
1from datetime import datetime
3from pydantic import EmailStr, Field
4from pymongo import IndexModel
6from mysingle.core.base import BaseDoc, BaseTimeDoc
9class User(BaseTimeDoc):
10 """Base User Document model."""
12 email: EmailStr
13 hashed_password: str
14 full_name: str | None = None
15 is_active: bool = True
16 is_superuser: bool = False
17 is_verified: bool = False
18 avatar_url: str | None = None
19 oauth_accounts: list["OAuthAccount"] = Field(default_factory=list)
21 # 활동 기록 필드
22 last_login_at: datetime | None = None
23 last_activity_at: datetime | None = None
24 login_count: int = 0
25 last_login_ip: str | None = None
26 last_activity_ip: str | None = None
28 class Settings:
29 """Beanie settings."""
31 name = "users"
32 # Unique constraint: email + is_superuser 조합이 unique해야 함
33 # 이렇게 하면 같은 이메일로 일반 유저(is_superuser=False) 1명과
34 # 슈퍼유저(is_superuser=True) 1명만 존재 가능
35 # 여러 워커가 동시에 실행되어도 MongoDB가 중복 생성을 방지함
36 indexes = [
37 IndexModel([("email", 1)]), # 검색 성능을 위한 일반 인덱스
38 IndexModel(
39 [("email", 1), ("is_superuser", 1)],
40 unique=True,
41 name="unique_email_superuser",
42 ), # email + is_superuser unique 조합
43 ]
46class OAuthAccount(BaseDoc):
47 """Base OAuth account Document model."""
49 oauth_name: str
50 name: str | None = None
51 avatar_url: str | None = None
52 access_token: str
53 account_id: str
54 account_email: str
55 expires_at: int | None = None
56 refresh_token: str | None = None
58 class Settings:
59 """Beanie settings."""
61 name = "oauth_accounts"
62 indexes = ["account_email"]