mirror of
https://github.com/malmeloo/FindMy.py.git
synced 2026-04-18 13:54:01 +02:00
61 lines
1.7 KiB
Python
61 lines
1.7 KiB
Python
"""Code related to internal account state handling."""
|
|
from enum import Enum
|
|
from functools import wraps
|
|
from typing import TYPE_CHECKING, Callable, Concatenate, ParamSpec, TypeVar
|
|
|
|
from findmy.util.errors import InvalidStateError
|
|
|
|
if TYPE_CHECKING:
|
|
# noinspection PyUnresolvedReferences
|
|
from .account import BaseAppleAccount
|
|
|
|
P = ParamSpec("P")
|
|
R = TypeVar("R")
|
|
A = TypeVar("A", bound="BaseAppleAccount")
|
|
F = Callable[Concatenate[A, P], R]
|
|
|
|
|
|
class LoginState(Enum):
|
|
"""Enum of possible login states. Used for `AppleAccount`'s internal state machine."""
|
|
|
|
LOGGED_OUT = 0
|
|
REQUIRE_2FA = 1
|
|
AUTHENTICATED = 2
|
|
LOGGED_IN = 3
|
|
|
|
def __lt__(self, other: "LoginState") -> bool:
|
|
"""
|
|
Compare against another `LoginState`.
|
|
|
|
A `LoginState` is said to be "less than" another `LoginState` iff it is in
|
|
an "earlier" stage of the login process, going from LOGGED_OUT to LOGGED_IN.
|
|
"""
|
|
if isinstance(other, LoginState):
|
|
return self.value < other.value
|
|
|
|
return NotImplemented
|
|
|
|
def __repr__(self) -> str:
|
|
"""Human-readable string representation of the state."""
|
|
return self.__str__()
|
|
|
|
|
|
def require_login_state(*states: LoginState) -> Callable[[F], F]:
|
|
"""Enforce a login state as precondition for a method."""
|
|
|
|
def decorator(func: F) -> F:
|
|
@wraps(func)
|
|
def wrapper(acc: A, *args: P.args, **kwargs: P.kwargs) -> R:
|
|
if acc.login_state not in states:
|
|
msg = (
|
|
f"Invalid login state! Currently: {acc.login_state}"
|
|
f" but should be one of: {states}"
|
|
)
|
|
raise InvalidStateError(msg)
|
|
|
|
return func(acc, *args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
return decorator
|