Coverage for src / lexigram / admin / auth / store / protocols.py: 100%

12 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-13 22:14 +0800

1"""Admin user store protocol. 

2 

3Defines the formal contract for admin panel user store implementations. 

4Any class that satisfies these method signatures is a valid implementation. 

5""" 

6 

7from __future__ import annotations 

8 

9from typing import Any, Protocol, runtime_checkable 

10 

11 

12@runtime_checkable 

13class AdminUserStoreProtocol(Protocol): 

14 """Protocol for admin panel user store operations. 

15 

16 This is the single authoritative contract for anything that stores and 

17 manages admin-panel user accounts (distinct from the application's own 

18 user store managed by lexigram-auth). 

19 

20 Implementations: 

21 - :class:`~lexigram.admin.auth.store.direct_sql.DirectSQLAdminUserStore` 

22 — production SQL backend (``admin_users`` table) 

23 - :class:`~lexigram.admin.auth.store.memory.MemoryAdminUserStore` 

24 — in-memory store for testing 

25 """ 

26 

27 async def get_admin_count(self) -> int: 

28 """Return the total number of admin-panel accounts. 

29 

30 Used by :class:`~lexigram.admin.middleware.setup.SetupMiddleware` to 

31 decide whether to redirect to the first-run setup wizard. 

32 

33 Returns: 

34 Non-negative integer count of admin users. 

35 """ 

36 ... 

37 

38 async def create_user( 

39 self, 

40 name: str, 

41 email: str, 

42 hashed_password: str, 

43 roles: list[str] | None = None, 

44 permissions: list[str] | None = None, 

45 **kwargs: Any, 

46 ) -> Any: 

47 """Create (or upsert) an admin-panel user account. 

48 

49 Args: 

50 name: Display name. 

51 email: Unique email address — used as the login identifier. 

52 hashed_password: Pre-hashed credential. 

53 roles: Optional list of role strings (e.g. ``["superadmin"]``). 

54 permissions: Optional list of explicit permission strings. 

55 **kwargs: Implementation-specific extras (ignored if unsupported). 

56 

57 Returns: 

58 A lightweight object exposing at least ``user_id``, ``name``, and 

59 ``email`` attributes. 

60 """ 

61 ... 

62 

63 async def get_user_by_email(self, email: str) -> Any | None: 

64 """Look up an admin user by email address. 

65 

66 Args: 

67 email: Email to search for. 

68 

69 Returns: 

70 User object or ``None`` when no match exists. 

71 """ 

72 ... 

73 

74 async def get_user_by_id(self, user_id: str) -> Any | None: 

75 """Look up an admin user by primary key. 

76 

77 Args: 

78 user_id: Unique identifier (UUID string). 

79 

80 Returns: 

81 User object or ``None`` when no match exists. 

82 """ 

83 ... 

84 

85 async def update_user(self, user: Any) -> None: 

86 """Persist changes to an existing admin user. 

87 

88 Args: 

89 user: User object carrying updated field values. Must expose at 

90 least ``user_id``, ``name``, ``email``, ``roles``, 

91 ``permissions``, ``hashed_password``, and ``is_active``. 

92 """ 

93 ... 

94 

95 async def delete_user(self, user_id: str) -> None: 

96 """Permanently remove an admin user account. 

97 

98 Args: 

99 user_id: Unique identifier of the user to delete. 

100 """ 

101 ... 

102 

103 async def authenticate(self, email: str, password: str) -> Any | None: 

104 """Authenticate an admin user by email and password. 

105 

106 Args: 

107 email: Email address to look up. 

108 password: Plain-text password to verify. 

109 

110 Returns: 

111 User object when credentials are valid and account is active, 

112 ``None`` otherwise. 

113 """ 

114 ... 

115 

116 

117__all__ = ["AdminUserStoreProtocol"]