diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs index b62c86e08..1428e18f5 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs @@ -143,7 +143,7 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models if (app.Image != null) { - AddGetLink("image", resources.Url(x => nameof(x.GetImage), new { app = app.Name })); + AddGetLink("image", resources.Url(x => nameof(x.GetImage), values)); } if (isContributor) diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorDto.cs index 4114a908d..594953d95 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorDto.cs @@ -68,12 +68,16 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models if (resources.CanAssignContributor) { - AddPostLink("update", resources.Url(x => nameof(x.PostContributor), new { app })); + var values = new { app }; + + AddPostLink("update", resources.Url(x => nameof(x.PostContributor), values)); } if (resources.CanRevokeContributor) { - AddDeleteLink("delete", resources.Url(x => nameof(x.DeleteContributor), new { app, id = ContributorId })); + var values = new { app, id = ContributorId }; + + AddDeleteLink("delete", resources.Url(x => nameof(x.DeleteContributor), values)); } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs index 184aa5f85..06197ced9 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs @@ -80,12 +80,7 @@ namespace Squidex.Areas.Api.Controllers.Assets asset = await assetRepository.FindAssetBySlugAsync(AppId, idOrSlug); } - if (asset != null && queries.Version > EtagVersion.Any && asset.Version != queries.Version) - { - asset = await assetLoader.GetAsync(App.Id, asset.Id, queries.Version); - } - - return DeliverAsset(asset, queries); + return await DeliverAssetAsync(asset, queries); } /// @@ -108,10 +103,10 @@ namespace Squidex.Areas.Api.Controllers.Assets { var asset = await assetRepository.FindAssetAsync(id); - return DeliverAsset(asset, queries); + return await DeliverAssetAsync(asset, queries); } - private IActionResult DeliverAsset(IAssetEntity? asset, AssetContentQueryDto queries) + private async Task DeliverAssetAsync(IAssetEntity? asset, AssetContentQueryDto queries) { queries ??= new AssetContentQueryDto(); @@ -127,6 +122,16 @@ namespace Squidex.Areas.Api.Controllers.Assets return StatusCode(403); } + if (asset != null && queries.Version > EtagVersion.Any && asset.Version != queries.Version) + { + asset = await assetLoader.GetAsync(App.Id, asset.Id, queries.Version); + } + + if (asset == null) + { + return NotFound(); + } + var resizeOptions = queries.ToResizeOptions(asset); FileCallback callback; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs index d53172f07..687dc1fa8 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs @@ -203,13 +203,19 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models if (!string.IsNullOrWhiteSpace(response.Slug)) { - response.AddGetLink("content", resources.Url(x => nameof(x.GetAssetContentBySlug), new { app, idOrSlug = response.Id, more = response.Slug })); + var idValues = new { app, idOrSlug = response.Id, more = response.Slug }; - response.AddGetLink("content/slug", resources.Url(x => nameof(x.GetAssetContentBySlug), new { app, idOrSlug = response.Slug })); + response.AddGetLink("content", resources.Url(x => nameof(x.GetAssetContentBySlug), idValues)); + + var slugValues = new { app, idOrSlug = response.Slug }; + + response.AddGetLink("content/slug", resources.Url(x => nameof(x.GetAssetContentBySlug), slugValues)); } else { - response.AddGetLink("content", resources.Url(x => nameof(x.GetAssetContentBySlug), new { app, idOrSlug = response.Id })); + var idValues = new { app, idOrSlug = response.Id }; + + response.AddGetLink("content", resources.Url(x => nameof(x.GetAssetContentBySlug), idValues)); } return response; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs index 74b42b5ce..1e36ef767 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs @@ -70,7 +70,9 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models { AddPostLink("create", resources.Url(x => nameof(x.PostContent), values)); - AddPostLink("create/publish", resources.Url(x => nameof(x.PostContent), values) + "?publish=true"); + var publishValues = new { values.app, values.name, publish = true }; + + AddPostLink("create/publish", resources.Url(x => nameof(x.PostContent), publishValues)); } } } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs index 839d63b4d..df0edccc8 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs @@ -137,7 +137,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models if (canRun && ruleRunnerService.CanRunFromSnapshots(rule)) { - var snaphshotValues = new { app = resources.App, id = Id, fromSnapshots = true }; + var snaphshotValues = new { values.app, values.id, fromSnapshots = true }; AddPutLink("run/snapshots", resources.Url(x => nameof(x.PutRuleRun), snaphshotValues)); } diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldDto.cs index 86c9f6605..f0657055f 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/FieldDto.cs @@ -132,7 +132,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models if (Properties is ArrayFieldPropertiesDto) { - var parentValues = new { app = resources.App, name = schema, parentId = FieldId }; + var parentValues = new { values.app, values.name, parentId = FieldId }; AddPostLink("fields/add", resources.Url(x => nameof(x.PostNestedField), parentValues)); diff --git a/backend/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs b/backend/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs index a74388ccb..45a33771a 100644 --- a/backend/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs +++ b/backend/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs @@ -178,6 +178,16 @@ namespace TestSuite.ApiTests // Should return 403 when not authenticated. Assert.Contains("403", ex.Message); } + + + // STEP 6: Download asset without key and version. + using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open)) + { + var ex = await Assert.ThrowsAsync(() => _.DownloadAsync(asset_1, 0)); + + // Should return 403 when not authenticated. + Assert.Contains("403", ex.Message); + } } [Fact] diff --git a/backend/tools/TestSuite/TestSuite.Shared/Fixtures/AssetFixture.cs b/backend/tools/TestSuite/TestSuite.Shared/Fixtures/AssetFixture.cs index 09631b3ee..817c8efc7 100644 --- a/backend/tools/TestSuite/TestSuite.Shared/Fixtures/AssetFixture.cs +++ b/backend/tools/TestSuite/TestSuite.Shared/Fixtures/AssetFixture.cs @@ -17,7 +17,7 @@ namespace TestSuite.Fixtures { public IAssetsClient Assets => Squidex.Assets; - public async Task DownloadAsync(AssetDto asset) + public async Task DownloadAsync(AssetDto asset, int? version = null) { var temp = new MemoryStream(); @@ -25,6 +25,11 @@ namespace TestSuite.Fixtures { var url = $"{ServerUrl}{asset._links["content"].Href}"; + if (version > 0) + { + url += $"?version={version}"; + } + var response = await client.GetAsync(url); response.EnsureSuccessStatusCode();