diff --git a/docs/account.md b/docs/account.md index defb498..f83e053 100644 --- a/docs/account.md +++ b/docs/account.md @@ -1214,6 +1214,54 @@ account.profile_picture.show() When a new profile picture is set, any previous image in the **assets** folder is removed. The image is also copied into the Status Backend Docker volume so it is picked up by the backend when updating the account identity. +### `status` + +Get or update the **presence status** of the currently logged‑in account. This is the same presence indicator shown next to the account in Status App, and it controls how the account appears to other users. + +Returns `str` when reading the property - one of the options below. After a successful [`login`](./account.md#loginpassword-key_uidnone-display_namenone-mnemonicnone-infura_tokennone-alchemy_tokennone-coingecko_api_keynone), the status is automatically set to `on`. + +The value is **case‑insensitive** and must be one of the following options: + +| Option | Description | +|-------|-------------| +| `on` | **Always online**. The account is shown as online to other users. This is the default after login. | +| `auto` | **Automatic**. Status App decides the presence automatically based on activity. | +| `dnd` | **Do Not Disturb**. The account is shown as do not disturb. **This is experimental**. | +| `off` | **Inactive**. The account is shown as offline / inactive to other users. | + +```python +from status_sdk import Account + +account = Account() +params = { + "name": "status-app-bot", + "password": "SNTPUMP" +} +account.login(**params) + +# Read the current status +print(account.status) +``` + +You can update the status by assigning a new value: + +```python +from status_sdk import Account + +account = Account() +params = { + "name": "status-app-bot", + "password": "SNTPUMP" +} +account.login(**params) + +# Update the presence status +account.status = "off" +print(account.status) +``` + +**Note**: Assigning any value other than `on`, `auto`, `dnd` or `off` raises a custom exception. The comparison is case‑insensitive, so `ON` and `on` are equivalent. + ### `signal` The property exists in `Account` because signals require an **active logged‑in session**. Attempting to use signals before calling `login()` will raise an exception. Signals are low‑level events emitted by the Status Backend. diff --git a/status_sdk/__init__.py b/status_sdk/__init__.py index 0e1f71e..7f69550 100644 --- a/status_sdk/__init__.py +++ b/status_sdk/__init__.py @@ -2,5 +2,3 @@ from .account import Account from .group_chat import GroupChat from .utils import launch_docker_container from . import exceptions - -__all__ = ["Account", "launch_docker_container", "exceptions"] diff --git a/status_sdk/account.py b/status_sdk/account.py index 7f8e074..d6beda4 100644 --- a/status_sdk/account.py +++ b/status_sdk/account.py @@ -34,7 +34,12 @@ class Account: "transfer": "a9059cbb" # keccak256("transfer(address,uint256)")[:4] } __ETH_ADDRESS = "0x0000000000000000000000000000000000000000" - + __status_types = { + "auto": 1, + "dnd": 2, + "on": 3, + "off": 4 + } def __init__(self, domain: str = "localhost", backend_port: int = 8080, media_port: int = 9000, is_secure: bool = False, backup_folder: Optional[str] = None, volume_folder: Optional[str] = None): """ Work with your own Status App account @@ -104,6 +109,7 @@ class Account: "signals": f"{self.__ws_base_url}signals" } } + self.__status = "on" self.__media_port = media_port self.__signal = Signal(self.__urls["socket"]["signals"]) # Initialize profile @@ -582,6 +588,23 @@ class Account: balance.insert(0, "timestamp", datetime.datetime.now()) return balance.copy() + @property + def status(self) -> str: + """ + Get the current active status of the account + """ + return self.__status + + @status.setter + def status(self, new_status: str): + selected = self.__status_types.get(new_status.lower()) + if not selected: + raise exceptions.InvalidUserStatusError(f"Selected status '{selected}' is invalid... Available options: {' / '.join(self.__status_types.keys())}") + + self.__status = new_status.lower() + self._call_rpc("messaging", "setUserStatus", [selected, ""]) + + @property def community_members(self) -> pd.DataFrame: """ @@ -1277,8 +1300,6 @@ class Account: return __swap_tokens(from_token, to_token, amount, chain_id) - - def get_transactions(self, refresh: bool = False) -> pd.DataFrame: """ Get wallet transactions from all Alchemy chains. @@ -1377,6 +1398,7 @@ class Account: self.__signal.get("waku.connection.status.change") self.__is_messenger_launched = True self.logger.info("Messaging launched") + self.status = "on" def __del__(self): """ diff --git a/status_sdk/exceptions.py b/status_sdk/exceptions.py index 9e6afe3..86c6d10 100644 --- a/status_sdk/exceptions.py +++ b/status_sdk/exceptions.py @@ -11,6 +11,9 @@ class WalletNotConfiguredError(Exception): def __init__(self, msg: Optional[str] = None): super().__init__(msg or "Cannot use this wallet method without setting `infura_token`, `alchemy_token` and `coingecko_api_key` when calling `login`.") +class InvalidUserStatusError(ValueError): + pass + class InvalidDisplayNameError(ValueError): pass diff --git a/status_sdk/group_chat.py b/status_sdk/group_chat.py index 88b9e08..7653fe6 100644 --- a/status_sdk/group_chat.py +++ b/status_sdk/group_chat.py @@ -290,8 +290,6 @@ class GroupChat: if not re.fullmatch(r"[A-Za-z0-9_. \t-]+", name): raise exceptions.InvalidGroupChatNameError("Group chat name can contain only letters, numbers, underscores (_), periods (.), whitespaces and hyphens (-).") - return True - def __action_log(self, public_keys: list[str], action: str): """ Log how many members were affected by an `add` / `remove` action.