diff --git a/integ_tests/common.py b/integ_tests/common.py index 9b344020..4f758238 100644 --- a/integ_tests/common.py +++ b/integ_tests/common.py @@ -30,21 +30,43 @@ from typing import Any, Generator, Optional from playwright.sync_api import BrowserContext, Page +from enum import Enum + + +class AuthType(Enum): + HTPASSWD = "htpasswd" + XREMOTE = "http_x_remote_user" + + +class SharingType(Enum): + SHARING = "sharing" + NOSHARING = "nosharing" + + @dataclass(frozen=True) class Config: name: str - auth_type: str + auth_type: AuthType + sharing_type: SharingType extra_config: str = "" SHARING_HTPASSWD = Config( name="sharing_htpasswd", - auth_type="htpasswd", + auth_type=AuthType.HTPASSWD, + sharing_type=SharingType.SHARING, ) SHARING_XREMOTE = Config( name="sharing_xremote", - auth_type="http_x_remote_user", + auth_type=AuthType.XREMOTE, + sharing_type=SharingType.SHARING, +) + +NOSHARE_HTPASSWD = Config( + name="noshare_htpasswd", + auth_type=AuthType.HTPASSWD, + sharing_type=SharingType.NOSHARING, ) @@ -71,10 +93,10 @@ hosts = 127.0.0.1:{port} [storage] filesystem_folder = {storage_path} [auth] -type = {config.auth_type} +type = {config.auth_type.value} """ ) - if config.auth_type == "htpasswd": + if config.auth_type == AuthType.HTPASSWD: f.write(f"htpasswd_filename = {user_path}\n") f.write("htpasswd_encryption = plain\n") @@ -83,7 +105,11 @@ type = {config.auth_type} type = internal [headers] Content-Security-Policy = default-src 'self'; object-src 'none' -[sharing] +""" + ) + if config.sharing_type == SharingType.SHARING: + f.write( + f"""[sharing] type = csv collection_by_map = true collection_by_token = true @@ -93,12 +119,12 @@ permit_properties_overlay = true collection_by_bday = true permit_create_bday = true database_path = {sharing_path} - -{config.extra_config} """ - ) + ) - if config.auth_type == "htpasswd": + f.write(f"\n{config.extra_config}\n") + + if config.auth_type == AuthType.HTPASSWD: with open(user_path, "w") as f: f.write( """admin:adminpassword @@ -155,14 +181,14 @@ def login( config: Config = SHARING_HTPASSWD, context: Optional[BrowserContext] = None, ) -> None: - if config.auth_type == "http_x_remote_user": + if config.auth_type == AuthType.XREMOTE: if context is None: raise ValueError("context is required for http_x_remote_user login") context.set_extra_http_headers({"X-Remote-User": "admin"}) page.goto(radicale_server) - if config.auth_type == "htpasswd": + if config.auth_type == AuthType.HTPASSWD: page.fill('#loginscene input[data-name="user"]', "admin") page.fill('#loginscene input[data-name="password"]', "adminpassword") page.click('button:has-text("Next")') diff --git a/integ_tests/test_basic_operation.py b/integ_tests/test_basic_operation.py index 1adc8731..d7f55d58 100644 --- a/integ_tests/test_basic_operation.py +++ b/integ_tests/test_basic_operation.py @@ -25,6 +25,7 @@ import pytest from playwright.sync_api import BrowserContext, Page, expect from integ_tests.common import ( + NOSHARE_HTPASSWD, SHARING_HTPASSWD, SHARING_XREMOTE, Config, @@ -40,7 +41,7 @@ def radicale_server( yield from start_radicale_server(tmp_path, config) -@pytest.mark.parametrize("config", [SHARING_HTPASSWD, SHARING_XREMOTE]) +@pytest.mark.parametrize("config", [SHARING_HTPASSWD, SHARING_XREMOTE, NOSHARE_HTPASSWD]) def test_index_html_loads(page: Page, radicale_server: str, config: Config) -> None: """Test that the index.html loads from the server.""" console_msgs: list[str] = [] @@ -52,7 +53,7 @@ def test_index_html_loads(page: Page, radicale_server: str, config: Config) -> N assert len(errors) == 0 -@pytest.mark.parametrize("config", [SHARING_HTPASSWD, SHARING_XREMOTE]) +@pytest.mark.parametrize("config", [SHARING_HTPASSWD, SHARING_XREMOTE, NOSHARE_HTPASSWD]) def test_user_login_works( context: BrowserContext, page: Page, radicale_server: str, config: Config ) -> None: diff --git a/integ_tests/test_delete.py b/integ_tests/test_delete.py index 8cd40a61..cb1b9c87 100644 --- a/integ_tests/test_delete.py +++ b/integ_tests/test_delete.py @@ -25,6 +25,7 @@ import pytest from playwright.sync_api import BrowserContext, Page, expect from integ_tests.common import ( + NOSHARE_HTPASSWD, SHARING_HTPASSWD, SHARING_XREMOTE, Config, @@ -41,7 +42,7 @@ def radicale_server( yield from start_radicale_server(tmp_path, config) -@pytest.mark.parametrize("config", [SHARING_HTPASSWD, SHARING_XREMOTE]) +@pytest.mark.parametrize("config", [SHARING_HTPASSWD, SHARING_XREMOTE, NOSHARE_HTPASSWD]) def test_delete_wrong_confirmation( context: BrowserContext, page: Page, radicale_server: str, config: Config ) -> None: @@ -67,7 +68,7 @@ def test_delete_wrong_confirmation( expect(page.locator("#deleteconfirmationscene")).to_be_visible() -@pytest.mark.parametrize("config", [SHARING_HTPASSWD, SHARING_XREMOTE]) +@pytest.mark.parametrize("config", [SHARING_HTPASSWD, SHARING_XREMOTE, NOSHARE_HTPASSWD]) def test_delete_correct_confirmation( context: BrowserContext, page: Page, radicale_server: str, config: Config ) -> None: diff --git a/integ_tests/test_download.py b/integ_tests/test_download.py index e7adaaf4..bcbd8544 100644 --- a/integ_tests/test_download.py +++ b/integ_tests/test_download.py @@ -24,6 +24,7 @@ import pytest from playwright.sync_api import BrowserContext, Page from integ_tests.common import ( + NOSHARE_HTPASSWD, SHARING_HTPASSWD, SHARING_XREMOTE, Config, @@ -32,7 +33,9 @@ from integ_tests.common import ( ) -@pytest.fixture(params=[SHARING_HTPASSWD, SHARING_XREMOTE], ids=lambda c: c.name) +@pytest.fixture( + params=[SHARING_HTPASSWD, SHARING_XREMOTE, NOSHARE_HTPASSWD], ids=lambda c: c.name +) def config(request: pytest.FixtureRequest) -> Config: return request.param diff --git a/integ_tests/test_edit.py b/integ_tests/test_edit.py index c7fda8bd..70b1b7f9 100644 --- a/integ_tests/test_edit.py +++ b/integ_tests/test_edit.py @@ -25,6 +25,7 @@ import pytest from playwright.sync_api import BrowserContext, Page, expect from integ_tests.common import ( + NOSHARE_HTPASSWD, SHARING_HTPASSWD, SHARING_XREMOTE, Config, @@ -34,7 +35,9 @@ from integ_tests.common import ( ) -@pytest.fixture(params=[SHARING_HTPASSWD, SHARING_XREMOTE], ids=lambda c: c.name) +@pytest.fixture( + params=[SHARING_HTPASSWD, SHARING_XREMOTE, NOSHARE_HTPASSWD], ids=lambda c: c.name +) def config(request: pytest.FixtureRequest) -> Config: return request.param diff --git a/integ_tests/test_scenes.py b/integ_tests/test_scenes.py index 16e5274a..67cb7d64 100644 --- a/integ_tests/test_scenes.py +++ b/integ_tests/test_scenes.py @@ -25,6 +25,7 @@ import pytest from playwright.sync_api import BrowserContext, Page, expect from integ_tests.common import ( + NOSHARE_HTPASSWD, SHARING_HTPASSWD, SHARING_XREMOTE, Config, @@ -34,7 +35,9 @@ from integ_tests.common import ( ) -@pytest.fixture(params=[SHARING_HTPASSWD, SHARING_XREMOTE], ids=lambda c: c.name) +@pytest.fixture( + params=[SHARING_HTPASSWD, SHARING_XREMOTE, NOSHARE_HTPASSWD], ids=lambda c: c.name +) def config(request: pytest.FixtureRequest) -> Config: return request.param diff --git a/integ_tests/test_scenes_login.py b/integ_tests/test_scenes_login.py index 6ccc08d6..fec13bf7 100644 --- a/integ_tests/test_scenes_login.py +++ b/integ_tests/test_scenes_login.py @@ -24,17 +24,30 @@ from typing import Any, Generator import pytest from playwright.sync_api import Page, expect -from integ_tests.common import SHARING_HTPASSWD, login, start_radicale_server +from integ_tests.common import ( + NOSHARE_HTPASSWD, + SHARING_HTPASSWD, + Config, + login, + start_radicale_server, +) + + +@pytest.fixture(params=[SHARING_HTPASSWD, NOSHARE_HTPASSWD], ids=lambda c: c.name) +def config(request: pytest.FixtureRequest) -> Config: + return request.param @pytest.fixture -def radicale_server(tmp_path: pathlib.Path) -> Generator[str, Any, None]: - yield from start_radicale_server(tmp_path, SHARING_HTPASSWD) +def radicale_server( + tmp_path: pathlib.Path, config: Config +) -> Generator[str, Any, None]: + yield from start_radicale_server(tmp_path, config) -def test_login_logout_login(page: Page, radicale_server: str) -> None: +def test_login_logout_login(page: Page, radicale_server: str, config: Config) -> None: # 1. First login - login(page, radicale_server, SHARING_HTPASSWD) + login(page, radicale_server, config) expect(page.locator("#collectionsscene")).to_be_visible() # 2. Logout @@ -43,5 +56,5 @@ def test_login_logout_login(page: Page, radicale_server: str) -> None: expect(page.locator("#collectionsscene")).to_be_hidden() # 3. Second login - login(page, radicale_server, SHARING_HTPASSWD) + login(page, radicale_server, config) expect(page.locator("#collectionsscene")).to_be_visible() diff --git a/integ_tests/test_upload.py b/integ_tests/test_upload.py index fcb6fb9d..876ae847 100644 --- a/integ_tests/test_upload.py +++ b/integ_tests/test_upload.py @@ -26,6 +26,7 @@ import pytest from playwright.sync_api import BrowserContext, Page, expect from integ_tests.common import ( + NOSHARE_HTPASSWD, SHARING_HTPASSWD, SHARING_XREMOTE, Config, @@ -34,7 +35,9 @@ from integ_tests.common import ( ) -@pytest.fixture(params=[SHARING_HTPASSWD, SHARING_XREMOTE], ids=lambda c: c.name) +@pytest.fixture( + params=[SHARING_HTPASSWD, SHARING_XREMOTE, NOSHARE_HTPASSWD], ids=lambda c: c.name +) def config(request: pytest.FixtureRequest) -> Config: return request.param diff --git a/radicale/web/internal_data/js/api/sharing.js b/radicale/web/internal_data/js/api/sharing.js index bdfa2587..4a9a3e9f 100644 --- a/radicale/web/internal_data/js/api/sharing.js +++ b/radicale/web/internal_data/js/api/sharing.js @@ -182,7 +182,10 @@ export function reload_sharing_list(user, password, collection, callback) { let shares = (parsed["Content"] || []).map((/** @type {ShareData} */ data) => new Share(data)); callback(shares, null); }, - null, // on_not_found + function () { + // sharing is disabled on the server + callback([], null); + }, function (error) { callback([], error); }, diff --git a/radicale/web/internal_data/js/scenes/ShareCollectionScene.js b/radicale/web/internal_data/js/scenes/ShareCollectionScene.js index 617ede89..96dd459d 100644 --- a/radicale/web/internal_data/js/scenes/ShareCollectionScene.js +++ b/radicale/web/internal_data/js/scenes/ShareCollectionScene.js @@ -270,11 +270,24 @@ export function maybe_enable_sharing_options(features) { let map_is_enabled = features.sharing.FeatureEnabledCollectionByMap || false; let token_is_enabled = features.sharing.FeatureEnabledCollectionByToken || false; let bday_is_enabled = features.sharing.FeatureEnabledCollectionByBday || false; - if (map_is_enabled || token_is_enabled || bday_is_enabled) { - let share_options = document.querySelectorAll("[data-name=shareoption]"); - for (let i = 0; i < share_options.length; i++) { - let share_option = share_options[i]; + let any_sharing_enabled = map_is_enabled || token_is_enabled || bday_is_enabled; + + let share_options = document.querySelectorAll("[data-name=shareoption]"); + for (let i = 0; i < share_options.length; i++) { + let share_option = share_options[i]; + if (any_sharing_enabled) { share_option.classList.remove("hidden"); + } else { + share_option.classList.add("hidden"); + } + } + + let incomingshares_btn = document.querySelector("#collectionsscene [data-name=incomingshares]"); + if (incomingshares_btn) { + if (any_sharing_enabled) { + incomingshares_btn.classList.remove("hidden"); + } else { + incomingshares_btn.classList.add("hidden"); } } }