Merge pull request #2082 from maxberger/master
UI/Sharing: Allow explicit setting of write-properties permission
This commit is contained in:
@@ -280,6 +280,14 @@
|
||||
name="newshare_permissions"><label for="newshare_attr_permissions_ro">Readonly</label>
|
||||
<input type="radio" data-name="permissions" id="newshare_attr_permissions_rw"
|
||||
name="newshare_permissions" /><label for="newshare_attr_permissions_rw">Read/Write</label>
|
||||
<br />
|
||||
<input type="radio" data-name="properties_write" id="newshare_attr_properties_write_deny"
|
||||
name="newshare_properties_write"><label for="newshare_attr_properties_write_deny">Deny</label>
|
||||
<input type="radio" data-name="properties_write" id="newshare_attr_properties_write_allow"
|
||||
name="newshare_properties_write"><label for="newshare_attr_properties_write_allow">Allow Properties
|
||||
write</label>
|
||||
<p data-name="token_write_warning" class="red hidden">WARNING: This allows everyone who knows the URL to make
|
||||
changes.</p>
|
||||
</details>
|
||||
<details data-name="conversions" class="hidden">
|
||||
<summary>Conversions</summary>
|
||||
|
||||
@@ -99,6 +99,18 @@ export class CollectionType {
|
||||
}
|
||||
}
|
||||
|
||||
export class Permission {
|
||||
// Private Fields
|
||||
static #_WRITE_PROPERTIES = "D:write-properties";
|
||||
static #_SHARE_MAP = "RADICALE:share-map";
|
||||
static #_SHARE_TOKEN = "RADICALE:share-token";
|
||||
|
||||
// Accessors for "get" functions only (no "set" functions)
|
||||
static get WRITE_PROPERTIES() { return this.#_WRITE_PROPERTIES; }
|
||||
static get SHARE_MAP() { return this.#_SHARE_MAP; }
|
||||
static get SHARE_TOKEN() { return this.#_SHARE_TOKEN; }
|
||||
}
|
||||
|
||||
|
||||
export class Collection {
|
||||
/**
|
||||
@@ -123,4 +135,11 @@ export class Collection {
|
||||
this.size = size;
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
has_permission(/** @type {string} */ permission) {
|
||||
if (!this.permissions) {
|
||||
return false;
|
||||
}
|
||||
return this.permissions.includes(permission);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
import { delete_collection } from "../api/api.js";
|
||||
import { get_auth_header } from "../api/common.js";
|
||||
import { Collection, CollectionType } from "../models/collection.js";
|
||||
import { Collection, CollectionType, Permission } from "../models/collection.js";
|
||||
import { collectionsCache } from "../utils/collections_cache.js";
|
||||
import { ErrorHandler } from "../utils/error.js";
|
||||
import { bytesToHumanReadable, get_element, get_element_by_id } from "../utils/misc.js";
|
||||
@@ -189,10 +189,7 @@ export class CollectionsScene {
|
||||
});
|
||||
|
||||
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")
|
||||
);
|
||||
let can_share = collection.has_permission(Permission.SHARE_MAP) || collection.has_permission(Permission.SHARE_TOKEN);
|
||||
if (share_option) {
|
||||
if (can_share) {
|
||||
share_option.classList.remove("hidden");
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
import { Share, add_share_by_map, add_share_by_token, get_property_key, update_share_by_map, update_share_by_token } from "../api/sharing.js";
|
||||
import { CollectionType } from "../models/collection.js";
|
||||
import { CollectionType, Permission } from "../models/collection.js";
|
||||
import { collectionsCache } from "../utils/collections_cache.js";
|
||||
import { ErrorHandler } from "../utils/error.js";
|
||||
import { FormValidator, validate_href, validate_non_empty, validate_not_empty_or_equals } from "../utils/form_validator.js";
|
||||
@@ -56,6 +56,9 @@ export class CreateEditShareScene {
|
||||
this._hidden_checkbox = /** @type {HTMLInputElement} */ (get_element(this._html_scene, "[data-name=hidden]"));
|
||||
this._permissions_ro_radio = /** @type {HTMLInputElement} */ (get_element_by_id("newshare_attr_permissions_ro"));
|
||||
this._permissions_rw_radio = /** @type {HTMLInputElement} */ (get_element_by_id("newshare_attr_permissions_rw"));
|
||||
this._properties_write_allow = /** @type {HTMLInputElement} */ (get_element_by_id("newshare_attr_properties_write_allow"));
|
||||
this._properties_write_deny = /** @type {HTMLInputElement} */ (get_element_by_id("newshare_attr_properties_write_deny"));
|
||||
this._token_write_warning = /** @type {HTMLElement} */ (get_element(this._html_scene, "[data-name=token_write_warning]"));
|
||||
this._conversions_details = /** @type {HTMLDetailsElement} */ (get_element(this._html_scene, "[data-name=conversions]"));
|
||||
this._conversions_container = get_element(this._html_scene, "[data-name=conversions_container]");
|
||||
|
||||
@@ -103,16 +106,32 @@ export class CreateEditShareScene {
|
||||
return checked ? checked.value : "none";
|
||||
}
|
||||
|
||||
_on_permissions_change() {
|
||||
if (this._shareType === "token") {
|
||||
if (this._permissions_rw_radio.checked || this._properties_write_allow.checked) {
|
||||
this._token_write_warning.classList.remove("hidden");
|
||||
} else {
|
||||
this._token_write_warning.classList.add("hidden");
|
||||
}
|
||||
} else {
|
||||
this._token_write_warning.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
_on_conversion_change() {
|
||||
let conversion = this._get_selected_conversion();
|
||||
if (conversion != "none") {
|
||||
this._permissions_ro_radio.disabled = true;
|
||||
this._permissions_rw_radio.disabled = true;
|
||||
this._properties_write_allow.disabled = true;
|
||||
this._properties_write_deny.disabled = true;
|
||||
this._enabled_checkbox.checked = true;
|
||||
this._hidden_checkbox.checked = false;
|
||||
} else {
|
||||
this._permissions_ro_radio.disabled = false;
|
||||
this._permissions_rw_radio.disabled = false;
|
||||
this._properties_write_allow.disabled = false;
|
||||
this._properties_write_deny.disabled = false;
|
||||
}
|
||||
if (this._shareType === "map") {
|
||||
this._map_validator.validate();
|
||||
@@ -140,7 +159,10 @@ export class CreateEditShareScene {
|
||||
let enabled_by_owner = is_conversion ? true : this._enabled_checkbox.checked;
|
||||
let hidden_by_owner = is_conversion ? false : this._hidden_checkbox.checked;
|
||||
let permissions = is_conversion ? "r" : (this._permissions_rw_radio.checked ? "rw" : "r");
|
||||
if (this._shareType === "token") {
|
||||
let allowPropertiesWrite = this._properties_write_allow.checked;
|
||||
if (allowPropertiesWrite) {
|
||||
permissions = permissions + "P";
|
||||
} else {
|
||||
permissions = permissions + "p";
|
||||
}
|
||||
/** @type {string} */ let conversion_value = conversion;
|
||||
@@ -221,6 +243,12 @@ export class CreateEditShareScene {
|
||||
this._cancel_btn.onclick = () => this._oncancel();
|
||||
this._form.onsubmit = () => this._onsubmit();
|
||||
|
||||
let onChangeCallback = () => this._on_permissions_change();
|
||||
this._permissions_ro_radio.addEventListener("change", onChangeCallback);
|
||||
this._permissions_rw_radio.addEventListener("change", onChangeCallback);
|
||||
this._properties_write_allow.addEventListener("change", onChangeCallback);
|
||||
this._properties_write_deny.addEventListener("change", onChangeCallback);
|
||||
|
||||
/** @type {HTMLHeadingElement} */ let title = /** @type {HTMLHeadingElement} */ (get_element(this._html_scene, "h1"));
|
||||
title.textContent = this._edit ? "Edit Share" : "New Share";
|
||||
this._submit_btn.textContent = this._edit ? "Save" : "Create";
|
||||
@@ -230,6 +258,18 @@ export class CreateEditShareScene {
|
||||
this._enabled_checkbox.checked = (this._edit && this._share && this._share.EnabledByOwner !== null) ? this._share.EnabledByOwner : true;
|
||||
this._hidden_checkbox.checked = (this._edit && this._share && this._share.HiddenByOwner !== null) ? this._share.HiddenByOwner : false;
|
||||
|
||||
let hasWriteProperties = this._collection.has_permission(Permission.WRITE_PROPERTIES);
|
||||
|
||||
if (this._edit || this._shareType === "map") {
|
||||
if (hasWriteProperties) {
|
||||
this._properties_write_allow.checked = true;
|
||||
} else {
|
||||
this._properties_write_deny.checked = true;
|
||||
}
|
||||
} else {
|
||||
this._properties_write_deny.checked = true;
|
||||
}
|
||||
|
||||
let initial_conversion = (this._edit && this._share && this._share.Conversion) ? this._share.Conversion : "none";
|
||||
|
||||
collectionsCache.getServerFeatures(this._user, this._password, this._errorHandler.setError, (features) => {
|
||||
@@ -363,6 +403,7 @@ export class CreateEditShareScene {
|
||||
this._sharemapfields.classList.add("hidden");
|
||||
this._errorHandler.clearError();
|
||||
}
|
||||
this._on_permissions_change();
|
||||
}
|
||||
|
||||
hide() {
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
delete_share_by_token,
|
||||
reload_sharing_list,
|
||||
} from "../api/sharing.js";
|
||||
import { Collection } from "../models/collection.js";
|
||||
import { Collection, Permission } from "../models/collection.js";
|
||||
|
||||
import { ErrorHandler } from "../utils/error.js";
|
||||
import { get_element, get_element_by_id } from "../utils/misc.js";
|
||||
@@ -88,8 +88,8 @@ export class ShareCollectionScene {
|
||||
});
|
||||
this._cancel_btn.onclick = () => this._oncancel();
|
||||
|
||||
let can_share_by_token = this._collection.permissions && this._collection.permissions.includes("RADICALE:share-token");
|
||||
let can_share_by_map = this._collection.permissions && this._collection.permissions.includes("RADICALE:share-map");
|
||||
let can_share_by_token = this._collection.has_permission(Permission.SHARE_TOKEN);
|
||||
let can_share_by_map = this._collection.has_permission(Permission.SHARE_MAP);
|
||||
|
||||
if (can_share_by_token) {
|
||||
if (this._share_by_token_btn) {
|
||||
|
||||
Reference in New Issue
Block a user