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

1from datetime import datetime 

2 

3from pydantic import EmailStr, Field 

4from pymongo import IndexModel 

5 

6from mysingle.core.base import BaseDoc, BaseTimeDoc 

7 

8 

9class User(BaseTimeDoc): 

10 """Base User Document model.""" 

11 

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) 

20 

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 

27 

28 class Settings: 

29 """Beanie settings.""" 

30 

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 ] 

44 

45 

46class OAuthAccount(BaseDoc): 

47 """Base OAuth account Document model.""" 

48 

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 

57 

58 class Settings: 

59 """Beanie settings.""" 

60 

61 name = "oauth_accounts" 

62 indexes = ["account_email"]