UI: Base sharing settings on collection permissions rather than server features
This commit is contained in:
@@ -24,8 +24,8 @@ from typing import Any, Generator
|
|||||||
import pytest
|
import pytest
|
||||||
from playwright.sync_api import BrowserContext, Page, expect
|
from playwright.sync_api import BrowserContext, Page, expect
|
||||||
|
|
||||||
from integ_tests.common import (SHARING_HTPASSWD, SHARING_XREMOTE, Config,
|
from integ_tests.common import (SHARING_HTPASSWD, SHARING_XREMOTE, AuthType,
|
||||||
create_collection, login,
|
Config, SharingType, create_collection, login,
|
||||||
start_radicale_server)
|
start_radicale_server)
|
||||||
|
|
||||||
|
|
||||||
@@ -463,3 +463,99 @@ def test_bday_section_visible_for_addressbook(
|
|||||||
page.click('button[data-name="sharebymap"]')
|
page.click('button[data-name="sharebymap"]')
|
||||||
expect(page.locator("details[data-name='conversions']")).to_be_visible()
|
expect(page.locator("details[data-name='conversions']")).to_be_visible()
|
||||||
page.click('#newshare button[data-name="cancel"]')
|
page.click('#newshare button[data-name="cancel"]')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def map_disabled_server(tmp_path: pathlib.Path) -> Generator[str, Any, None]:
|
||||||
|
config = Config(
|
||||||
|
name="map_disabled",
|
||||||
|
auth_type=AuthType.HTPASSWD,
|
||||||
|
sharing_type=SharingType.NOSHARING,
|
||||||
|
extra_config=f"""[sharing]
|
||||||
|
type = csv
|
||||||
|
collection_by_map = false
|
||||||
|
collection_by_token = true
|
||||||
|
permit_create_token = true
|
||||||
|
permit_create_map = false
|
||||||
|
database_path = {tmp_path / 'sharing.csv'}
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
yield from start_radicale_server(tmp_path, config)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def token_disabled_server(tmp_path: pathlib.Path) -> Generator[str, Any, None]:
|
||||||
|
config = Config(
|
||||||
|
name="token_disabled",
|
||||||
|
auth_type=AuthType.HTPASSWD,
|
||||||
|
sharing_type=SharingType.NOSHARING,
|
||||||
|
extra_config=f"""[sharing]
|
||||||
|
type = csv
|
||||||
|
collection_by_map = true
|
||||||
|
collection_by_token = false
|
||||||
|
permit_create_token = false
|
||||||
|
permit_create_map = true
|
||||||
|
database_path = {tmp_path / 'sharing.csv'}
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
yield from start_radicale_server(tmp_path, config)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def both_disabled_server(tmp_path: pathlib.Path) -> Generator[str, Any, None]:
|
||||||
|
config = Config(
|
||||||
|
name="both_disabled",
|
||||||
|
auth_type=AuthType.HTPASSWD,
|
||||||
|
sharing_type=SharingType.NOSHARING,
|
||||||
|
extra_config=f"""[sharing]
|
||||||
|
type = csv
|
||||||
|
collection_by_map = false
|
||||||
|
collection_by_token = false
|
||||||
|
permit_create_token = false
|
||||||
|
permit_create_map = false
|
||||||
|
database_path = {tmp_path / 'sharing.csv'}
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
yield from start_radicale_server(tmp_path, config)
|
||||||
|
|
||||||
|
|
||||||
|
def test_map_sharing_disabled(
|
||||||
|
context: BrowserContext, page: Page, map_disabled_server: str
|
||||||
|
) -> None:
|
||||||
|
login(page, map_disabled_server, SHARING_HTPASSWD, context=context)
|
||||||
|
create_collection(page, map_disabled_server)
|
||||||
|
page.hover("article:not(.hidden)")
|
||||||
|
page.click('article:not(.hidden) a[data-name="share"]', force=True, strict=True)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
page.locator('#sharecollectionscene button[data-name="sharebymap"]')
|
||||||
|
).to_be_hidden()
|
||||||
|
expect(
|
||||||
|
page.locator('#sharecollectionscene button[data-name="sharebytoken"]')
|
||||||
|
).to_be_visible()
|
||||||
|
|
||||||
|
|
||||||
|
def test_token_sharing_disabled(
|
||||||
|
context: BrowserContext, page: Page, token_disabled_server: str
|
||||||
|
) -> None:
|
||||||
|
login(page, token_disabled_server, SHARING_HTPASSWD, context=context)
|
||||||
|
create_collection(page, token_disabled_server)
|
||||||
|
page.hover("article:not(.hidden)")
|
||||||
|
page.click('article:not(.hidden) a[data-name="share"]', force=True, strict=True)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
page.locator('#sharecollectionscene button[data-name="sharebytoken"]')
|
||||||
|
).to_be_hidden()
|
||||||
|
expect(
|
||||||
|
page.locator('#sharecollectionscene button[data-name="sharebymap"]')
|
||||||
|
).to_be_visible()
|
||||||
|
|
||||||
|
|
||||||
|
def test_both_sharing_disabled(
|
||||||
|
context: BrowserContext, page: Page, both_disabled_server: str
|
||||||
|
) -> None:
|
||||||
|
login(page, both_disabled_server, SHARING_HTPASSWD, context=context)
|
||||||
|
create_collection(page, both_disabled_server)
|
||||||
|
page.hover("article:not(.hidden)")
|
||||||
|
|
||||||
|
expect(page.locator('article:not(.hidden) a[data-name="share"]')).to_be_hidden()
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ import { Collection, CollectionType } from "../models/collection.js";
|
|||||||
import { collectionsCache } from "../utils/collections_cache.js";
|
import { collectionsCache } from "../utils/collections_cache.js";
|
||||||
import { ErrorHandler } from "../utils/error.js";
|
import { ErrorHandler } from "../utils/error.js";
|
||||||
import { bytesToHumanReadable, get_element, get_element_by_id } from "../utils/misc.js";
|
import { bytesToHumanReadable, get_element, get_element_by_id } from "../utils/misc.js";
|
||||||
|
import { UrlTextHandler } from "../utils/url_text.js";
|
||||||
import { CreateEditCollectionScene } from "./CreateEditCollectionScene.js";
|
import { CreateEditCollectionScene } from "./CreateEditCollectionScene.js";
|
||||||
import { DeleteConfirmationScene } from "./DeleteConfirmationScene.js";
|
import { DeleteConfirmationScene } from "./DeleteConfirmationScene.js";
|
||||||
import { IncomingSharingScene } from "./IncomingSharingScene.js";
|
import { IncomingSharingScene } from "./IncomingSharingScene.js";
|
||||||
import { Scene, push_scene } from "./scene_manager.js";
|
import { Scene, push_scene } from "./scene_manager.js";
|
||||||
import { UrlTextHandler } from "../utils/url_text.js";
|
|
||||||
import { ShareCollectionScene, maybe_enable_sharing_options } from "./ShareCollectionScene.js";
|
import { ShareCollectionScene, maybe_enable_sharing_options } from "./ShareCollectionScene.js";
|
||||||
import { UploadCollectionScene } from "./UploadCollectionScene.js";
|
import { UploadCollectionScene } from "./UploadCollectionScene.js";
|
||||||
|
|
||||||
@@ -187,6 +187,20 @@ export class CollectionsScene {
|
|||||||
get_element(node, "[data-name=" + e + "]").classList.add("hidden");
|
get_element(node, "[data-name=" + e + "]").classList.add("hidden");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let share_option = get_element(node, "[data-name=shareoption]");
|
||||||
|
let can_share = collection.permissions && (
|
||||||
|
collection.permissions.includes("RADICALE:share-map") ||
|
||||||
|
collection.permissions.includes("RADICALE:share-token")
|
||||||
|
);
|
||||||
|
if (share_option) {
|
||||||
|
if (can_share) {
|
||||||
|
share_option.classList.remove("hidden");
|
||||||
|
} else {
|
||||||
|
share_option.classList.add("hidden");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let share_info = get_element(node, "[data-name=shared-by]");
|
let share_info = get_element(node, "[data-name=shared-by]");
|
||||||
let transformed_from = get_element(node, "[data-name=transformed-from]");
|
let transformed_from = get_element(node, "[data-name=transformed-from]");
|
||||||
let share = (shares || []).find(
|
let share = (shares || []).find(
|
||||||
|
|||||||
@@ -25,14 +25,14 @@ import {
|
|||||||
reload_sharing_list,
|
reload_sharing_list,
|
||||||
} from "../api/sharing.js";
|
} from "../api/sharing.js";
|
||||||
import { Collection } from "../models/collection.js";
|
import { Collection } from "../models/collection.js";
|
||||||
import { collectionsCache } from "../utils/collections_cache.js";
|
|
||||||
import { ErrorHandler } from "../utils/error.js";
|
import { ErrorHandler } from "../utils/error.js";
|
||||||
import { get_element, get_element_by_id } from "../utils/misc.js";
|
import { get_element, get_element_by_id } from "../utils/misc.js";
|
||||||
import { displayPermissionsOrConversion } from "../utils/permissions.js";
|
import { displayPermissionsOrConversion } from "../utils/permissions.js";
|
||||||
|
import { UrlTextHandler } from "../utils/url_text.js";
|
||||||
import { CreateEditShareScene } from "./CreateEditShareScene.js";
|
import { CreateEditShareScene } from "./CreateEditShareScene.js";
|
||||||
import { DeleteConfirmationScene } from "./DeleteConfirmationScene.js";
|
import { DeleteConfirmationScene } from "./DeleteConfirmationScene.js";
|
||||||
import { Scene, pop_scene, push_scene } from "./scene_manager.js";
|
import { Scene, pop_scene, push_scene } from "./scene_manager.js";
|
||||||
import { UrlTextHandler } from "../utils/url_text.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @implements {Scene}
|
* @implements {Scene}
|
||||||
@@ -88,38 +88,30 @@ export class ShareCollectionScene {
|
|||||||
});
|
});
|
||||||
this._cancel_btn.onclick = () => this._oncancel();
|
this._cancel_btn.onclick = () => this._oncancel();
|
||||||
|
|
||||||
collectionsCache.getServerFeatures(this._user, this._password, this._errorHandler.setError, (features) => {
|
let can_share_by_token = this._collection.permissions && this._collection.permissions.includes("RADICALE:share-token");
|
||||||
if (features.sharing && features.sharing.PermittedCreateCollectionByToken) {
|
let can_share_by_map = this._collection.permissions && this._collection.permissions.includes("RADICALE:share-map");
|
||||||
if (this._share_by_token_btn) {
|
|
||||||
this._share_by_token_btn.classList.remove("hidden");
|
|
||||||
this._share_by_token_btn.onclick = () => this._onsharebytoken();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this._share_by_token_btn) this._share_by_token_btn.classList.add("hidden");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (features.sharing && features.sharing.FeatureEnabledCollectionByToken) {
|
if (can_share_by_token) {
|
||||||
if (this._share_by_token_div) this._share_by_token_div.classList.remove("hidden");
|
if (this._share_by_token_btn) {
|
||||||
} else {
|
this._share_by_token_btn.classList.remove("hidden");
|
||||||
if (this._share_by_token_div) this._share_by_token_div.classList.add("hidden");
|
this._share_by_token_btn.onclick = () => this._onsharebytoken();
|
||||||
}
|
}
|
||||||
|
if (this._share_by_token_div) this._share_by_token_div.classList.remove("hidden");
|
||||||
|
} else {
|
||||||
|
if (this._share_by_token_btn) this._share_by_token_btn.classList.add("hidden");
|
||||||
|
if (this._share_by_token_div) this._share_by_token_div.classList.add("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
if (features.sharing && features.sharing.PermittedCreateCollectionByMap) {
|
if (can_share_by_map) {
|
||||||
if (this._share_by_map_btn) {
|
if (this._share_by_map_btn) {
|
||||||
this._share_by_map_btn.classList.remove("hidden");
|
this._share_by_map_btn.classList.remove("hidden");
|
||||||
this._share_by_map_btn.onclick = () => this._onsharebymap();
|
this._share_by_map_btn.onclick = () => this._onsharebymap();
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this._share_by_map_btn) this._share_by_map_btn.classList.add("hidden");
|
|
||||||
}
|
}
|
||||||
|
if (this._share_by_map_div) this._share_by_map_div.classList.remove("hidden");
|
||||||
if (features.sharing && features.sharing.FeatureEnabledCollectionByMap) {
|
} else {
|
||||||
if (this._share_by_map_div) this._share_by_map_div.classList.remove("hidden");
|
if (this._share_by_map_btn) this._share_by_map_btn.classList.add("hidden");
|
||||||
} else {
|
if (this._share_by_map_div) this._share_by_map_div.classList.add("hidden");
|
||||||
if (this._share_by_map_div) this._share_by_map_div.classList.add("hidden");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
this._title.textContent = this._collection.displayname || this._collection.href;
|
this._title.textContent = this._collection.displayname || this._collection.href;
|
||||||
update_share_list(this._user, this._password, this._collection, this._errorHandler);
|
update_share_list(this._user, this._password, this._collection, this._errorHandler);
|
||||||
@@ -245,23 +237,11 @@ function add_share_rows(user, password, collection, shares, errorHandler) {
|
|||||||
*/
|
*/
|
||||||
export function maybe_enable_sharing_options(features) {
|
export function maybe_enable_sharing_options(features) {
|
||||||
if (!features || !features.sharing) return;
|
if (!features || !features.sharing) return;
|
||||||
let map_is_enabled = features.sharing.FeatureEnabledCollectionByMap || false;
|
let has_sharing = features.sharing.ApiVersion !== undefined;
|
||||||
let token_is_enabled = features.sharing.FeatureEnabledCollectionByToken || false;
|
|
||||||
let any_sharing_enabled = map_is_enabled || token_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]");
|
let incomingshares_btn = document.querySelector("#collectionsscene [data-name=incomingshares]");
|
||||||
if (incomingshares_btn) {
|
if (incomingshares_btn) {
|
||||||
if (any_sharing_enabled) {
|
if (has_sharing) {
|
||||||
incomingshares_btn.classList.remove("hidden");
|
incomingshares_btn.classList.remove("hidden");
|
||||||
} else {
|
} else {
|
||||||
incomingshares_btn.classList.add("hidden");
|
incomingshares_btn.classList.add("hidden");
|
||||||
|
|||||||
Reference in New Issue
Block a user