Refine remote config and path browsing
This commit is contained in:
+47
@@ -2689,6 +2689,8 @@ class HandlerRouteTests(unittest.TestCase):
|
||||
self.assertEqual(handler.json_status, HTTPStatus.OK)
|
||||
self.assertEqual(handler.json_payload["path"], allowed_root)
|
||||
self.assertEqual(handler.json_payload["home_path"], allowed_root)
|
||||
self.assertEqual(handler.json_payload["root_paths"][0], allowed_root)
|
||||
self.assertIn(allowed_root, handler.json_payload["root_paths"])
|
||||
|
||||
def test_remote_path_roots_include_explicit_allowlist(self):
|
||||
with tempfile.TemporaryDirectory() as base_root, tempfile.TemporaryDirectory() as extra_root:
|
||||
@@ -2705,6 +2707,31 @@ class HandlerRouteTests(unittest.TestCase):
|
||||
self.assertIn(Path(base_root).resolve(), roots)
|
||||
self.assertIn(Path(extra_root).resolve(), roots)
|
||||
|
||||
def test_remote_filesystem_browse_returns_all_allowed_root_paths(self):
|
||||
with tempfile.TemporaryDirectory() as base_root, tempfile.TemporaryDirectory() as extra_root:
|
||||
APP.save_runtime_config({"download_dir": base_root, "mode": "sub", "quality": "best"})
|
||||
encoded = base64.b64encode(b"demo:secret-pass").decode("ascii")
|
||||
handler = DummyHandler("/api/fs/browse?path=&mode=dir")
|
||||
handler.client_address = ("192.168.1.25", 8421)
|
||||
handler.headers["Authorization"] = f"Basic {encoded}"
|
||||
|
||||
with mock.patch.dict(
|
||||
os.environ,
|
||||
{
|
||||
"ANI_CLI_WEB_ALLOW_REMOTE": "1",
|
||||
"ANI_CLI_WEB_AUTH_USERNAME": "demo",
|
||||
"ANI_CLI_WEB_AUTH_PASSWORD": "secret-pass",
|
||||
"ANI_CLI_WEB_REMOTE_PATH_ROOTS": extra_root,
|
||||
},
|
||||
clear=False,
|
||||
):
|
||||
APP.Handler.do_GET(handler)
|
||||
|
||||
self.assertEqual(handler.json_status, HTTPStatus.OK)
|
||||
self.assertEqual(handler.json_payload["root_paths"][:2], [extra_root, base_root])
|
||||
self.assertIn(extra_root, handler.json_payload["root_paths"])
|
||||
self.assertIn(base_root, handler.json_payload["root_paths"])
|
||||
|
||||
def test_config_post_accepts_discord_webhook_fields(self):
|
||||
body = b'{"download_dir":"/tmp/example","mode":"sub","quality":"best","discord_webhook_url":"https://discord.com/api/webhooks/123456/test-token","discord_webhook_events":["runtime_error","watchlist_refresh_failed","bad"]}'
|
||||
handler = DummyHandler("/api/config", body=body, content_length=len(body))
|
||||
@@ -2723,6 +2750,25 @@ class HandlerRouteTests(unittest.TestCase):
|
||||
self.assertEqual(handler.error_status, HTTPStatus.BAD_REQUEST)
|
||||
self.assertIn("official discord webhook host", handler.error_message.lower())
|
||||
|
||||
def test_config_post_partial_update_preserves_existing_paths(self):
|
||||
with tempfile.TemporaryDirectory() as existing_root:
|
||||
APP.save_runtime_config(
|
||||
{
|
||||
"download_dir": existing_root,
|
||||
"mode": "sub",
|
||||
"quality": "best",
|
||||
"jellyfin_tv_dir": existing_root,
|
||||
}
|
||||
)
|
||||
body = b'{"mode":"dub"}'
|
||||
handler = DummyHandler("/api/config", body=body, content_length=len(body))
|
||||
APP.Handler.do_POST(handler)
|
||||
|
||||
self.assertEqual(handler.json_status, HTTPStatus.OK)
|
||||
self.assertEqual(handler.json_payload["download_dir"], existing_root)
|
||||
self.assertEqual(handler.json_payload["jellyfin_tv_dir"], existing_root)
|
||||
self.assertEqual(handler.json_payload["mode"], "dub")
|
||||
|
||||
def test_remote_config_post_rejects_download_dir_outside_allowed_roots(self):
|
||||
with tempfile.TemporaryDirectory() as allowed_root, tempfile.TemporaryDirectory() as blocked_root:
|
||||
APP.save_runtime_config({"download_dir": allowed_root, "mode": "sub", "quality": "best"})
|
||||
@@ -3058,6 +3104,7 @@ class TemplateHelperTests(unittest.TestCase):
|
||||
self.assertIn('class="ghost browse-path-btn"', APP.CONFIG_HTML)
|
||||
self.assertIn('id="pathBrowserOverlay"', APP.CONFIG_HTML)
|
||||
self.assertIn('/api/fs/browse?path=${encodeURIComponent(path || state.pathBrowser.path || "")}', APP.CONFIG_HTML)
|
||||
self.assertIn('rootGroup.className = "browser-roots";', APP.CONFIG_HTML)
|
||||
|
||||
def test_search_page_sends_watchlist_auto_download_series(self):
|
||||
self.assertIn('auto_download_series: $("seasonInput").value || "1"', APP.INDEX_HTML)
|
||||
|
||||
Reference in New Issue
Block a user