diff --git a/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs b/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs index bd91cfa81..f2a68ba7a 100644 --- a/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs +++ b/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs @@ -67,10 +67,12 @@ namespace Squidex.Areas.Api.Controllers.Assets return NotFound(); } - var assetId = entity.Id.ToString(); + Response.Headers["ETag"] = $"{entity.FileVersion};{width};{height};{mode}"; return new FileCallbackResult(entity.MimeType, entity.FileName, async bodyStream => { + var assetId = entity.Id.ToString(); + if (entity.IsImage && (width.HasValue || height.HasValue)) { var assetSuffix = $"{width}_{height}_{mode}"; diff --git a/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs b/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs index 7e8fea639..98d89eda9 100644 --- a/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs +++ b/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs @@ -43,6 +43,8 @@ namespace Squidex.Areas.Api.Controllers.Languages { var response = Language.AllLanguages.Select(LanguageDto.FromLanguage).ToList(); + Response.Headers["Etag"] = "1"; + return Ok(response); } } diff --git a/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs b/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs index c94056f37..7e3f7c85a 100644 --- a/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleDto.cs @@ -14,10 +14,11 @@ using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Entities.Rules; using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; +using Squidex.Pipeline; namespace Squidex.Areas.Api.Controllers.Rules.Models { - public sealed class RuleDto + public sealed class RuleDto : IGenerateEtag { /// /// The id of the rule. @@ -49,7 +50,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models /// /// The version of the rule. /// - public int Version { get; set; } + public long Version { get; set; } /// /// Determines if the rule is enabled. diff --git a/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs b/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs index 28ee52be9..ed2e0b1df 100644 --- a/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs +++ b/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using IdentityServer4.Models; using Microsoft.AspNetCore.Mvc; using NodaTime; using Squidex.Areas.Api.Controllers.Rules.Models; @@ -32,6 +33,8 @@ namespace Squidex.Areas.Api.Controllers.Rules [MustBeAppDeveloper] public sealed class RulesController : ApiController { + private static readonly string RuleActionsEtag = string.Join(";", RuleElementRegistry.Actions.Select(x => x.Key)).Sha256(); + private static readonly string RuleTriggersEtag = string.Join(";", RuleElementRegistry.Triggers.Select(x => x.Key)).Sha256(); private readonly IAppProvider appProvider; private readonly IRuleEventRepository ruleEventsRepository; @@ -58,6 +61,8 @@ namespace Squidex.Areas.Api.Controllers.Rules { var response = RuleElementRegistry.Actions.ToDictionary(x => x.Key, x => SimpleMapper.Map(x.Value, new RuleElementDto())); + Response.Headers["Etag"] = RuleActionsEtag; + return Ok(response); } @@ -75,6 +80,8 @@ namespace Squidex.Areas.Api.Controllers.Rules { var response = RuleElementRegistry.Triggers.ToDictionary(x => x.Key, x => SimpleMapper.Map(x.Value, new RuleElementDto())); + Response.Headers["Etag"] = RuleTriggersEtag; + return Ok(response); } @@ -96,6 +103,8 @@ namespace Squidex.Areas.Api.Controllers.Rules var response = entities.Select(RuleDto.FromRule); + Response.Headers["ETag"] = response.ToManyEtag(0); + return Ok(response); } diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs index 0dc33bc92..11d441abd 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs @@ -108,7 +108,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// /// The version of the schema. /// - public int Version { get; set; } + public long Version { get; set; } public static SchemaDetailsDto FromSchema(ISchemaEntity schema) { diff --git a/src/Squidex/app/shared/services/assets.service.ts b/src/Squidex/app/shared/services/assets.service.ts index 680d905b2..25884f5f0 100644 --- a/src/Squidex/app/shared/services/assets.service.ts +++ b/src/Squidex/app/shared/services/assets.service.ts @@ -195,9 +195,7 @@ export class AssetsService { public uploadFile(appName: string, file: File, user: string, now: DateTime): Observable { const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets`); - const req = new HttpRequest('POST', url, getFormData(file), { - reportProgress: true - }); + const req = new HttpRequest('POST', url, getFormData(file), { reportProgress: true }); return this.http.request(req).pipe( filter(event => @@ -276,12 +274,7 @@ export class AssetsService { public replaceFile(appName: string, id: string, file: File, version: Version): Observable> { const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets/${id}/content`); - const req = new HttpRequest('PUT', url, getFormData(file), { - headers: new HttpHeaders({ - 'If-Match': version.value - }), - reportProgress: true - }); + const req = new HttpRequest('PUT', url, getFormData(file), { headers: new HttpHeaders().set('If-Match', version.value), reportProgress: true }); return this.http.request(req).pipe( filter(event =>