diff --git a/backend/src/Squidex.Web/UrlDecodeRouteParamsAttribute.cs b/backend/src/Squidex.Web/UrlDecodeRouteParamsAttribute.cs new file mode 100644 index 000000000..041a2a74a --- /dev/null +++ b/backend/src/Squidex.Web/UrlDecodeRouteParamsAttribute.cs @@ -0,0 +1,27 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Linq; +using System.Web; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Squidex.Web +{ + public class UrlDecodeRouteParamsAttribute : ActionFilterAttribute + { + public override void OnActionExecuting(ActionExecutingContext context) + { + foreach (var (key, value) in context.ActionArguments.ToList()) + { + if (value is string text) + { + context.ActionArguments[key] = HttpUtility.UrlDecode(text); + } + } + } + } +} diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppRolesController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppRolesController.cs index a0ddc72fa..dd67c239c 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppRolesController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppRolesController.cs @@ -123,6 +123,7 @@ namespace Squidex.Areas.Api.Controllers.Apps [ProducesResponseType(typeof(RolesDto), StatusCodes.Status200OK)] [ApiPermissionOrAnonymous(Permissions.AppRolesUpdate)] [ApiCosts(1)] + [UrlDecodeRouteParams] public async Task PutRole(string app, string roleName, [FromBody] UpdateRoleDto request) { var command = request.ToCommand(roleName); @@ -147,6 +148,7 @@ namespace Squidex.Areas.Api.Controllers.Apps [ProducesResponseType(typeof(RolesDto), StatusCodes.Status200OK)] [ApiPermissionOrAnonymous(Permissions.AppRolesDelete)] [ApiCosts(1)] + [UrlDecodeRouteParams] public async Task DeleteRole(string app, string roleName) { var command = new DeleteRole { Name = roleName }; diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/AppTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/AppTests.cs index 3a9417d26..fa3e59f1f 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/AppTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/AppTests.cs @@ -185,7 +185,8 @@ namespace TestSuite.ApiTests [Fact] public async Task Should_manage_roles() { - var roleName = Guid.NewGuid().ToString(); + // Use role name with hash to test previous bug. + var roleName = $"{Guid.NewGuid()}/1"; var roleClient = Guid.NewGuid().ToString(); var roleContributor1 = "role1@squidex.io"; var roleContributor2 = "role2@squidex.io";