diff --git a/integ_tests/test_sharing.py b/integ_tests/test_sharing.py index b7fc796e..f1d53c58 100644 --- a/integ_tests/test_sharing.py +++ b/integ_tests/test_sharing.py @@ -246,3 +246,36 @@ def test_edit_share_by_map(page: Page, radicale_server: str) -> None: page.click('tr:not(.hidden) button[data-name="edit"]') expect(page.locator('input[data-name="enabled"]')).not_to_be_checked() page.click('#newshare button[data-name="cancel"]') + + +def test_share_by_map_validation(page: Page, radicale_server: str) -> None: + login(page, radicale_server) + create_collection(page, radicale_server) + page.hover("article:not(.hidden)") + page.click('article:not(.hidden) a[data-name="share"]', force=True, strict=True) + + page.click('button[data-name="sharebymap"]') + + # Try empty user + page.locator('input[data-name="shareuser"]').fill("") + page.locator('input[data-name="sharehref"]').fill("1234") + page.click('#newshare button[data-name="submit"]') + expect(page.locator('#newshare [data-name="error"]:not(.hidden)')).to_contain_text( + "Share User is empty" + ) + + # Try logged in user + page.locator('input[data-name="shareuser"]').fill("admin") + page.click('#newshare button[data-name="submit"]') + expect(page.locator('#newshare [data-name="error"]:not(.hidden)')).to_contain_text( + "Share User cannot be admin" + ) + + # Valid user + page.locator('input[data-name="shareuser"]').fill("max") + page.click('#newshare button[data-name="submit"]') + + # Verify success + expect( + page.locator("tr[data-name='sharemaprowtemplate']:not(.hidden)") + ).to_have_count(1) diff --git a/radicale/web/internal_data/js/scenes/CreateEditShareScene.js b/radicale/web/internal_data/js/scenes/CreateEditShareScene.js index cb6d83d2..24b1c5a2 100644 --- a/radicale/web/internal_data/js/scenes/CreateEditShareScene.js +++ b/radicale/web/internal_data/js/scenes/CreateEditShareScene.js @@ -22,7 +22,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 { ErrorHandler } from "../utils/error.js"; -import { FormValidator, validate_href, validate_non_empty } from "../utils/form_validator.js"; +import { FormValidator, validate_href, validate_not_empty_or_equals } from "../utils/form_validator.js"; import { onCleanHREFinput, random_uuid } from "../utils/misc.js"; import { Scene, pop_scene, scene_stack } from "./scene_manager.js"; @@ -64,7 +64,7 @@ export class CreateEditShareScene { let errorHandler = new ErrorHandler(error_form); let map_validator = new FormValidator(errorHandler); - map_validator.addValidator(shareuser_input, validate_non_empty(shareuser_input, "Share User")); + map_validator.addValidator(shareuser_input, validate_not_empty_or_equals(shareuser_input, user, "Share User")); map_validator.addValidator(sharehref_input, validate_href(sharehref_input, "Share Href")); sharehref_input.addEventListener("input", onCleanHREFinput); diff --git a/radicale/web/internal_data/js/utils/form_validator.js b/radicale/web/internal_data/js/utils/form_validator.js index 21cd0826..2cd53a76 100644 --- a/radicale/web/internal_data/js/utils/form_validator.js +++ b/radicale/web/internal_data/js/utils/form_validator.js @@ -76,6 +76,27 @@ export function validate_non_empty(input, field_name) { return field_name + " is empty"; }; } + +/** + * Validates that the input is not empty and not equal to a target string. + * @param {HTMLInputElement} input + * @param {string} target + * @param {string} field_name + * @returns {function(): ?string} + */ +export function validate_not_empty_or_equals(input, target, field_name) { + return () => { + let value = input.value.trim(); + if (!value) { + return field_name + " is empty"; + } + if (value === target) { + return field_name + " cannot be " + target; + } + return null; + }; +} + /** * Validates that the input is a valid HREF. * @param {HTMLInputElement} input