From 2ee05f748c3750bbe32023bc9ee8c92e8d63b028 Mon Sep 17 00:00:00 2001
From: Moul <moul@moul.re>
Date: Mon, 7 Apr 2025 11:53:51 +0200
Subject: [PATCH] Implement AccountStorage class (#477)

Define tools.click_fail() (#501)
---
 silkaj/account_storage.py          | 54 ++++++++++++++++++++++++++++++
 silkaj/tools.py                    |  5 +++
 tests/unit/test_account_storage.py | 49 +++++++++++++++++++++++++++
 3 files changed, 108 insertions(+)
 create mode 100644 silkaj/account_storage.py
 create mode 100644 tests/unit/test_account_storage.py

diff --git a/silkaj/account_storage.py b/silkaj/account_storage.py
new file mode 100644
index 00000000..f955af7e
--- /dev/null
+++ b/silkaj/account_storage.py
@@ -0,0 +1,54 @@
+# Copyright  2016-2025 Maël Azimi <m.a@moul.re>
+#
+# Silkaj is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Silkaj is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
+
+from pathlib import Path
+
+from silkaj import tools
+from silkaj.blockchain import tools as bc_tools
+
+
+class AccountStorage:
+    xdg_data_home = ".local/share"
+    program_name = "silkaj"
+    revocation_file_name = "revocation.txt"
+    authentication_v1_file_name = "authentication_file_ed25519.dewif"
+    authentication_v2_file_name = "authentication_file_sr25519.json"
+
+    def __init__(self) -> None:
+        self.account_name = tools.has_account_defined()
+
+        self.path = Path.home().joinpath(
+            self.xdg_data_home,
+            self.program_name,
+            bc_tools.get_currency(),
+            self.account_name,
+        )
+        self.path.mkdir(parents=True, exist_ok=True)
+
+    def authentication_file_path(self, check_exist: bool = True) -> Path:
+        auth_file_path = self.path.joinpath(self.authentication_v1_file_name)
+        if check_exist and not auth_file_path.is_file():
+            tools.click_fail(
+                f"{auth_file_path} not found for account name: {self.account_name}",
+            )
+        return auth_file_path
+
+    def revocation_path(self, check_exist: bool = True) -> Path:
+        revocation_path = self.path.joinpath(self.revocation_file_name)
+        if check_exist and not revocation_path.is_file():
+            tools.click_fail(
+                f"{revocation_path} not found for account name: {self.account_name}",
+            )
+        return revocation_path
diff --git a/silkaj/tools.py b/silkaj/tools.py
index fc6e11f6..5b58383b 100644
--- a/silkaj/tools.py
+++ b/silkaj/tools.py
@@ -36,6 +36,11 @@ def message_exit(message: str) -> None:
     sys.exit(FAILURE_EXIT_STATUS)
 
 
+@click.pass_context
+def click_fail(context: click.Context, message: str) -> None:
+    context.fail(message)
+
+
 class MutuallyExclusiveOption(click.Option):
     def __init__(self, *args: Any, **kwargs: Any) -> None:
         self.mutually_exclusive = set(kwargs.pop("mutually_exclusive", []))
diff --git a/tests/unit/test_account_storage.py b/tests/unit/test_account_storage.py
new file mode 100644
index 00000000..57b7251a
--- /dev/null
+++ b/tests/unit/test_account_storage.py
@@ -0,0 +1,49 @@
+# Copyright  2016-2025 Maël Azimi <m.a@moul.re>
+#
+# Silkaj is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Silkaj is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
+
+from pathlib import Path
+from unittest.mock import Mock
+
+import pytest
+
+from silkaj.account_storage import AccountStorage
+from silkaj.blockchain import tools
+from tests import helpers
+
+
+@pytest.mark.parametrize(
+    ("account_name", "currency"),
+    [
+        ("test", "g1"),
+        ("toto", "g1-test"),
+    ],
+)
+def test_account_storage_account(account_name, currency, monkeypatch):
+    def patched_get_currency():
+        return currency
+
+    helpers.define_click_context(account_name=account_name)
+    patched_pathlib_mkdir = Mock()
+    monkeypatch.setattr(Path, "mkdir", patched_pathlib_mkdir)
+    monkeypatch.setattr(tools, "get_currency", patched_get_currency)
+
+    account_storage = AccountStorage()
+    assert account_storage.path == Path.home().joinpath(
+        account_storage.xdg_data_home,
+        account_storage.program_name,
+        currency,
+        account_name,
+    )
+    patched_pathlib_mkdir.assert_called_once()
-- 
GitLab