diff --git a/backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj b/backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj index 319d0b3e5..674e6bb5a 100644 --- a/backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj +++ b/backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj @@ -10,26 +10,26 @@ - + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + diff --git a/backend/src/Migrations/Migrations.csproj b/backend/src/Migrations/Migrations.csproj index dd5435bf3..8fc18e7dc 100644 --- a/backend/src/Migrations/Migrations.csproj +++ b/backend/src/Migrations/Migrations.csproj @@ -6,7 +6,7 @@ enable - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj b/backend/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj index 560e691de..32743858a 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj @@ -12,7 +12,7 @@ True - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringAsyncJintExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringAsyncJintExtension.cs index d8963d13c..11214ae30 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringAsyncJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringAsyncJintExtension.cs @@ -20,12 +20,12 @@ public sealed class StringAsyncJintExtension : IJintExtension, IScriptDescriptor private delegate void TextGenerateDelegate(string prompt, Action callback); private delegate void TextTranslateDelegate(string text, string language, Action callback, string sourceLanguage); private readonly ITranslator translator; - private readonly IChatBot chatBot; + private readonly IChatAgent chatAgent; - public StringAsyncJintExtension(ITranslator translator, IChatBot chatBot) + public StringAsyncJintExtension(ITranslator translator, IChatAgent chatAgent) { this.translator = translator; - this.chatBot = chatBot; + this.chatAgent = chatAgent; } public void ExtendAsync(ScriptExecutionContext context) @@ -61,9 +61,17 @@ public sealed class StringAsyncJintExtension : IJintExtension, IScriptDescriptor return; } - var result = await chatBot.AskQuestionAsync(prompt, ct); + var conversationId = Guid.NewGuid().ToString(); + try + { + var result = await chatAgent.PromptAsync(conversationId, prompt, ct); - scheduler.Run(callback, JsValue.FromObject(context.Engine, result.Choices.FirstOrDefault())); + scheduler.Run(callback, JsValue.FromObject(context.Engine, result.Text)); + } + finally + { + await chatAgent.StopConversationAsync(conversationId); + } } catch (Exception ex) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj b/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj index 712e8cd48..4803fe9d3 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj @@ -20,15 +20,15 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj index 6afe1e9d2..961367e41 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj @@ -19,11 +19,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs index 11459e171..75cffd502 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs @@ -75,6 +75,7 @@ public sealed class AssetCommandMiddleware : CachingDomainObjectMiddleware b .WithResolveSchemaNames() .WithNoCleanup() - .WithNoEnrichment() - .WithNoAssetEnrichment()); + .WithNoEnrichment()); this.options = options.Value; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Jobs/DefaultJobService.cs b/backend/src/Squidex.Domain.Apps.Entities/Jobs/DefaultJobService.cs index 2ea883fb9..5a010904a 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Jobs/DefaultJobService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Jobs/DefaultJobService.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Collections.Concurrent; using Squidex.Domain.Apps.Core.Apps; using Squidex.Infrastructure; using Squidex.Infrastructure.States; @@ -15,6 +16,7 @@ namespace Squidex.Domain.Apps.Entities.Jobs; public sealed class DefaultJobService : IJobService, IDeleter { + private readonly ConcurrentDictionary wokenUp = []; private readonly IMessageBus messaging; private readonly IEnumerable runners; private readonly IPersistenceFactory persistence; @@ -42,6 +44,7 @@ public sealed class DefaultJobService : IJobService, IDeleter throw new InvalidOperationException("Invalid job."); } + // This should never happen, but just in case we remove a task, it is there to get a proper error. var runner = runners.FirstOrDefault(x => x.Name == job.TaskName) ?? throw new InvalidOperationException("Invalid job."); @@ -51,12 +54,13 @@ public sealed class DefaultJobService : IJobService, IDeleter public async Task StartAsync(DomainId ownerId, JobRequest request, CancellationToken ct = default) { + // This should never happen, but just in case we remove a task, it is there to get a proper error. var runner = runners.FirstOrDefault(x => x.Name == request.TaskName) ?? throw new DomainException(T.Get("jobs.invalidTaskName")); - var state = await GetStateAsync(ownerId, ct); - - state.EnsureCanStart(runner); + // Wakeup the job handler to clear cancelled runs from previous incarnations of the service. + await EnsureWakeupAsync(ownerId, ct); + await EnsureCanRunAsync(ownerId, runner, ct); await messaging.PublishAsync(new JobStart(ownerId, request), null, ct); } @@ -76,6 +80,9 @@ public sealed class DefaultJobService : IJobService, IDeleter public async Task> GetJobsAsync(DomainId ownerId, CancellationToken ct = default) { + // Wakeup the job handler to clear cancelled runs from previous incarnations of the service. + await EnsureWakeupAsync(ownerId, default); + var state = await GetStateAsync(ownerId, ct); return state.Jobs; @@ -90,4 +97,20 @@ public sealed class DefaultJobService : IJobService, IDeleter return state.Value; } + + private async Task EnsureCanRunAsync(DomainId ownerId, IJobRunner runner, CancellationToken ct) + { + var state = await GetStateAsync(ownerId, ct); + + state.EnsureCanStart(runner); + } + + private async Task EnsureWakeupAsync(DomainId ownerId, + CancellationToken ct) + { + if (wokenUp.TryAdd(ownerId, true)) + { + await messaging.PublishAsync(new JobWakeup(ownerId), null, ct); + } + } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Jobs/JobProcessor.cs b/backend/src/Squidex.Domain.Apps.Entities/Jobs/JobProcessor.cs index b4b95d468..eb82ef8e9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Jobs/JobProcessor.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Jobs/JobProcessor.cs @@ -54,10 +54,24 @@ public sealed class JobProcessor { await state.LoadAsync(ct); - if (state.Value.Jobs.RemoveAll(x => x.Stopped == null) > 0) + var pending = state.Value.Jobs.Where(x => x.Stopped == null); + + if (pending.Any()) { // This should actually never happen, so we log with warning. - log.LogWarning("Removed unfinished backups for owner {ownerId} after start.", ownerId); + log.LogWarning("Removed unfinished jobs for owner {ownerId} after start.", ownerId); + + foreach (var job in pending.ToList()) + { + var runner = runners.FirstOrDefault(x => x.Name == job.TaskName); + + if (runner != null) + { + await runner.CleanupAsync(job); + } + + state.Value.Jobs.Remove(job); + } await state.WriteAsync(ct); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Jobs/JobWorker.cs b/backend/src/Squidex.Domain.Apps.Entities/Jobs/JobWorker.cs index 246c28004..c552f2dc4 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Jobs/JobWorker.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Jobs/JobWorker.cs @@ -6,6 +6,7 @@ // ========================================================================== using Microsoft.Extensions.DependencyInjection; +using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Infrastructure; using Squidex.Messaging; @@ -15,7 +16,8 @@ public sealed class JobWorker : IMessageHandler, IMessageHandler, IMessageHandler, - IMessageHandler + IMessageHandler, + IMessageHandler { private readonly Dictionary> processors = []; private readonly Func processorFactory; @@ -62,6 +64,11 @@ public sealed class JobWorker : await processor.ClearAsync(); } + public Task HandleAsync(JobWakeup message, CancellationToken ct) + { + return GetJobProcessorAsync(message.OwnerId); + } + private Task GetJobProcessorAsync(DomainId appId) { lock (processors) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Jobs/Messages.cs b/backend/src/Squidex.Domain.Apps.Entities/Jobs/Messages.cs index 3a62f3bc2..12fa102fe 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Jobs/Messages.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Jobs/Messages.cs @@ -20,4 +20,6 @@ public sealed record JobDelete(DomainId OwnerId, DomainId JobId) : JobMessage(Ow public sealed record JobClear(DomainId OwnerId) : JobMessage(OwnerId); +public sealed record JobWakeup(DomainId OwnerId) : JobMessage(OwnerId); + public abstract record JobMessage(DomainId OwnerId); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj b/backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj index 963611fba..15f54fa59 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj +++ b/backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj @@ -24,15 +24,15 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -41,7 +41,7 @@ - + diff --git a/backend/src/Squidex.Domain.Apps.Events/Squidex.Domain.Apps.Events.csproj b/backend/src/Squidex.Domain.Apps.Events/Squidex.Domain.Apps.Events.csproj index 1486d859f..d484250e7 100644 --- a/backend/src/Squidex.Domain.Apps.Events/Squidex.Domain.Apps.Events.csproj +++ b/backend/src/Squidex.Domain.Apps.Events/Squidex.Domain.Apps.Events.csproj @@ -14,7 +14,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj b/backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj index 60a317c13..dcdfa3328 100644 --- a/backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj +++ b/backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj @@ -19,12 +19,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj b/backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj index cebbfd461..8e355d2fc 100644 --- a/backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj +++ b/backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj @@ -18,13 +18,13 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + diff --git a/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStoreSubscription.cs b/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStoreSubscription.cs index 432abadff..cc9c7d802 100644 --- a/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStoreSubscription.cs +++ b/backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStoreSubscription.cs @@ -7,14 +7,12 @@ using EventStore.Client; using Squidex.Infrastructure.Json; -using Squidex.Infrastructure.Tasks; namespace Squidex.Infrastructure.EventSourcing; internal sealed class GetEventStoreSubscription : IEventSubscription { private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private StreamSubscription subscription; public GetEventStoreSubscription( IEventSubscriber eventSubscriber, @@ -25,58 +23,44 @@ internal sealed class GetEventStoreSubscription : IEventSubscription string? prefix, StreamFilter filter) { + var ct = cts.Token; + #pragma warning disable MA0134 // Observe result of async calls Task.Run(async () => { - var ct = cts.Token; - var streamName = await projectionClient.CreateProjectionAsync(filter); - async Task OnEvent(StreamSubscription subscription, ResolvedEvent @event, - CancellationToken ct) + var start = FromStream.Start; + if (!string.IsNullOrWhiteSpace(position)) { - var storedEvent = Formatter.Read(@event, prefix, serializer); - - await eventSubscriber.OnNextAsync(this, storedEvent); + start = FromStream.After(position.ToPosition(true)); } - void OnError(StreamSubscription subscription, SubscriptionDroppedReason reason, Exception? ex) + await using var subscription = client.SubscribeToStream(streamName, start, true, cancellationToken: ct); + try { - if (reason != SubscriptionDroppedReason.Disposed && - reason != SubscriptionDroppedReason.SubscriberError) + await foreach (var message in subscription.Messages) { - ex ??= new InvalidOperationException($"Subscription closed with reason {reason}."); + if (message is StreamMessage.Event @event) + { + var storedEvent = Formatter.Read(@event.ResolvedEvent, prefix, serializer); - eventSubscriber.OnErrorAsync(this, ex).AsTask().Forget(); + await eventSubscriber.OnNextAsync(this, storedEvent); + } } } - - if (!string.IsNullOrWhiteSpace(position)) - { - var from = FromStream.After(position.ToPosition(true)); - - subscription = await client.SubscribeToStreamAsync(streamName, from, - OnEvent, true, - OnError, - cancellationToken: ct); - } - else + catch (Exception ex) { - var from = FromStream.Start; + var inner = new InvalidOperationException($"Subscription closed.", ex); - subscription = await client.SubscribeToStreamAsync(streamName, from, - OnEvent, true, - OnError, - cancellationToken: ct); + await eventSubscriber.OnErrorAsync(this, ex); } - }, cts.Token); + }, ct); #pragma warning restore MA0134 // Observe result of async calls } public void Dispose() { - subscription?.Dispose(); - cts.Cancel(); } diff --git a/backend/src/Squidex.Infrastructure.GetEventStore/Squidex.Infrastructure.GetEventStore.csproj b/backend/src/Squidex.Infrastructure.GetEventStore/Squidex.Infrastructure.GetEventStore.csproj index f6081a278..c808539d7 100644 --- a/backend/src/Squidex.Infrastructure.GetEventStore/Squidex.Infrastructure.GetEventStore.csproj +++ b/backend/src/Squidex.Infrastructure.GetEventStore/Squidex.Infrastructure.GetEventStore.csproj @@ -11,11 +11,11 @@ True - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj b/backend/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj index 62b4188b5..29ac5948d 100644 --- a/backend/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj +++ b/backend/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj @@ -14,12 +14,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj b/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj index 46843f7dd..3d5701f1f 100644 --- a/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj +++ b/backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj @@ -11,25 +11,25 @@ True - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - - - - - - + + + + + + diff --git a/backend/src/Squidex.Shared/Squidex.Shared.csproj b/backend/src/Squidex.Shared/Squidex.Shared.csproj index a39f5b184..53a791d99 100644 --- a/backend/src/Squidex.Shared/Squidex.Shared.csproj +++ b/backend/src/Squidex.Shared/Squidex.Shared.csproj @@ -10,7 +10,7 @@ True - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/src/Squidex.Web/Squidex.Web.csproj b/backend/src/Squidex.Web/Squidex.Web.csproj index 414ca50c9..bb7daafc4 100644 --- a/backend/src/Squidex.Web/Squidex.Web.csproj +++ b/backend/src/Squidex.Web/Squidex.Web.csproj @@ -13,10 +13,10 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppImageController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppImageController.cs index 1e67c827b..cce7cb22d 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppImageController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppImageController.cs @@ -87,8 +87,8 @@ public sealed class AppImageController : ApiController activity?.SetTag("fileType", mimeType); - await using var assetOriginal = new TempAssetFile(resizedAsset, mimeType, 0); - await using var assetResized = new TempAssetFile(resizedAsset, mimeType, 0); + await using var assetOriginal = new TempAssetFile(resizedAsset, mimeType); + await using var assetResized = new TempAssetFile(resizedAsset, mimeType); var resizeOptions = new ResizeOptions { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs index 1f785e148..f6854fd8a 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs @@ -211,8 +211,8 @@ public sealed class AssetContentController : ApiController activity?.SetTag("fileType", asset.MimeType); activity?.SetTag("fileSize", asset.FileSize); - await using var assetOriginal = new TempAssetFile(asset.FileName, asset.MimeType, 0); - await using var assetResized = new TempAssetFile(asset.FileName, asset.MimeType, 0); + await using var assetOriginal = new TempAssetFile(asset.FileName, asset.MimeType); + await using var assetResized = new TempAssetFile(asset.FileName, asset.MimeType); using (Telemetry.Activities.StartActivity("Read")) { diff --git a/backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs index 8899dd06c..bc6bc23a8 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs @@ -23,13 +23,13 @@ namespace Squidex.Areas.Api.Controllers.Translations; public sealed class TranslationsController : ApiController { private readonly ITranslator translator; - private readonly IChatBot chatBot; + private readonly IChatAgent chatAgent; - public TranslationsController(ICommandBus commandBus, ITranslator translator, IChatBot chatBot) + public TranslationsController(ICommandBus commandBus, ITranslator translator, IChatAgent chatAgent) : base(commandBus) { this.translator = translator; - this.chatBot = chatBot; + this.chatAgent = chatAgent; } /// @@ -64,9 +64,17 @@ public sealed class TranslationsController : ApiController [ApiCosts(10)] public async Task PostQuestion(string app, [FromBody] AskDto request) { - var result = await chatBot.AskQuestionAsync(request.Prompt, HttpContext.RequestAborted); - var response = result.Choices; + var conversationId = Guid.NewGuid().ToString(); + try + { + var result = await chatAgent.PromptAsync(conversationId, request.Prompt, HttpContext.RequestAborted); + var response = new string[] { result.Text }; - return Ok(response); + return Ok(response); + } + finally + { + await chatAgent.StopConversationAsync(conversationId, default); + } } } diff --git a/backend/src/Squidex/Config/Domain/FontendServices.cs b/backend/src/Squidex/Config/Domain/FontendServices.cs index 79d7de7a4..02085dd09 100644 --- a/backend/src/Squidex/Config/Domain/FontendServices.cs +++ b/backend/src/Squidex/Config/Domain/FontendServices.cs @@ -51,9 +51,9 @@ public static class FontendServices services.Configure((services, options) => { - var chatBot = services.GetRequiredService(); + var chatAgent = services.GetRequiredService(); - options.More["canUseChatBot"] = chatBot.IsConfigured; + options.More["canUseChatBot"] = chatAgent.IsConfigured; }); services.Configure((services, options) => diff --git a/backend/src/Squidex/Config/Domain/InfrastructureServices.cs b/backend/src/Squidex/Config/Domain/InfrastructureServices.cs index 5b559795f..d9d33e812 100644 --- a/backend/src/Squidex/Config/Domain/InfrastructureServices.cs +++ b/backend/src/Squidex/Config/Domain/InfrastructureServices.cs @@ -135,7 +135,7 @@ public static class InfrastructureServices services.AddDeepLTranslations(config); services.AddGoogleCloudTranslations(config); - services.AddOpenAIChatBot(config); + services.AddOpenAIChatAgent(config); } public static void AddSquidexLocalization(this IServiceCollection services) diff --git a/backend/src/Squidex/Squidex.csproj b/backend/src/Squidex/Squidex.csproj index 0794d4439..eb24428c0 100644 --- a/backend/src/Squidex/Squidex.csproj +++ b/backend/src/Squidex/Squidex.csproj @@ -34,47 +34,47 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + - + - + - + - - + + - - - - - - - - - + + + + + + + + + - - - + + + diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs index c67cc9714..43b445a08 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs @@ -24,7 +24,7 @@ public class JintScriptEngineHelperTests : IClassFixture { private readonly IHttpClientFactory httpClientFactory = A.Fake(); private readonly ITranslator translator = A.Fake(); - private readonly IChatBot chatBot = A.Fake(); + private readonly IChatAgent chatAgent = A.Fake(); private readonly JintScriptEngine sut; public JintScriptEngineHelperTests() @@ -35,7 +35,7 @@ public class JintScriptEngineHelperTests : IClassFixture new HttpJintExtension(httpClientFactory), new StringJintExtension(), new StringWordsJintExtension(), - new StringAsyncJintExtension(translator, chatBot) + new StringAsyncJintExtension(translator, chatAgent) }; sut = new JintScriptEngine(new MemoryCache(Options.Create(new MemoryCacheOptions())), @@ -619,8 +619,8 @@ public class JintScriptEngineHelperTests : IClassFixture [Fact] public async Task Should_generate_content() { - A.CallTo(() => chatBot.AskQuestionAsync("prompt", A._)) - .Returns(new ChatBotResult { Choices = new List { "Generated" } }); + A.CallTo(() => chatAgent.PromptAsync(A._, "prompt", A._)) + .Returns(ChatBotResponse.Success("Generated")); var vars = new ScriptVars { @@ -635,6 +635,9 @@ public class JintScriptEngineHelperTests : IClassFixture var actual = await sut.ExecuteAsync(vars, script); Assert.Equal("Generated", actual.ToString()); + + A.CallTo(() => chatAgent.StopConversationAsync(A._, A._)) + .MustHaveHappened(); } [Theory] @@ -657,7 +660,10 @@ public class JintScriptEngineHelperTests : IClassFixture Assert.Equal(JsonValue.Null, actual); - A.CallTo(() => chatBot.AskQuestionAsync(A._, A._)) + A.CallTo(() => chatAgent.PromptAsync(A._, A._, A._)) + .MustNotHaveHappened(); + + A.CallTo(() => chatAgent.StopConversationAsync(A._, A._)) .MustNotHaveHappened(); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj b/backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj index d0c2147fa..8a6c45d14 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj @@ -16,19 +16,19 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + all runtime; build; native; contentfiles; analyzers diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs index b1c402935..c7f9cd338 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs @@ -163,7 +163,7 @@ public abstract class GraphQLTestBase : IClassFixture return A.That.Matches(x => x.App == TestApp.Default && x.NoCleanup() && - x.NoAssetEnrichment()); + !x.NoAssetEnrichment()); } protected static Context MatchsContentContext() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj index 607773f04..cbc60562a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj @@ -24,24 +24,24 @@ - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - - + + + all runtime; build; native; contentfiles; analyzers diff --git a/backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj b/backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj index 00edd3e24..e53f2366a 100644 --- a/backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj +++ b/backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj @@ -16,15 +16,15 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + all runtime; build; native; contentfiles; analyzers diff --git a/backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj b/backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj index 905a2660e..8fcd48eef 100644 --- a/backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj +++ b/backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj @@ -16,7 +16,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -24,12 +24,12 @@ - + - - + + all runtime; build; native; contentfiles; analyzers diff --git a/backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj b/backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj index f77956452..14f5b5c32 100644 --- a/backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj +++ b/backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj @@ -16,14 +16,14 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + all runtime; build; native; contentfiles; analyzers diff --git a/tools/TestSuite/TestSuite.ApiTests/AssetFormatTests.cs b/tools/TestSuite/TestSuite.ApiTests/AssetFormatTests.cs index fe6fc13ce..5ecb758fa 100644 --- a/tools/TestSuite/TestSuite.ApiTests/AssetFormatTests.cs +++ b/tools/TestSuite/TestSuite.ApiTests/AssetFormatTests.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using Squidex.Assets; using Squidex.ClientLibrary; using TestSuite.Fixtures; @@ -60,7 +61,7 @@ public class AssetFormatTests : IClassFixture [Fact] public async Task Should_upload_image_jpg_and_resize() { - var asset = await _.Client.Assets.UploadFileAsync("Assets/SampleImage_62kb.jpg", "image/jpg"); + var asset = await _.Client.Assets.UploadFileAsync("Assets/SampleImage_62kb.jpg", "image/jpeg"); await AssertImageAsync(asset); @@ -70,7 +71,7 @@ public class AssetFormatTests : IClassFixture [Fact] public async Task Should_upload_image_webp_and_resize() { - var asset = await _.Client.Assets.UploadFileAsync("Assets/SampleImage_100kb.webp", "image/jpg"); + var asset = await _.Client.Assets.UploadFileAsync("Assets/SampleImage_100kb.webp", "image/jpeg"); await AssertImageAsync(asset); } @@ -78,7 +79,7 @@ public class AssetFormatTests : IClassFixture [Fact] public async Task Should_upload_image_tiff_and_resize() { - var asset = await _.Client.Assets.UploadFileAsync("Assets/SampleImage_400kb.tiff", "image/jpg"); + var asset = await _.Client.Assets.UploadFileAsync("Assets/SampleImage_400kb.tiff", "image/jpeg"); await AssertImageAsync(asset); } @@ -112,6 +113,25 @@ public class AssetFormatTests : IClassFixture await Verify(asset); } + [Fact] + public async Task Should_upload_image_and_remove_location() + { + var asset = await _.Client.Assets.UploadFileAsync("Assets/SampleImage_WithLocation.jpg", "image/jpeg"); + + var url = _.Client.GenerateImageUrl(asset.Id); + + var httpClient = _.Client.CreateHttpClient(); + var httpResonse = await httpClient.GetAsync(url); + + await using (var stream = await httpResonse.Content.ReadAsStreamAsync()) + { + var imageLoader = new ImageSharpThumbnailGenerator(); + var imageInfo = await imageLoader.GetImageInfoAsync(stream, "image/jpeg"); + + Assert.False(imageInfo?.HasSensitiveMetadata); + } + } + private async Task AssertImageAsync(AssetDto asset) { await Verify(asset); @@ -132,7 +152,7 @@ public class AssetFormatTests : IClassFixture [Fact] public async Task Should_fix_orientation() { - var asset = await _.Client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpg"); + var asset = await _.Client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpeg"); // Should parse image metadata and fix orientation. Assert.True(asset.IsImage); @@ -218,10 +238,9 @@ public class AssetFormatTests : IClassFixture var url = $"{_.Client.GenerateImageUrl(imageId)}?width={width}&height={height}"; var httpClient = _.Client.CreateHttpClient(); + var httpResponse = await httpClient.GetAsync(url); - var response = await httpClient.GetAsync(url); - - await using (var stream = await response.Content.ReadAsStreamAsync()) + await using (var stream = await httpResponse.Content.ReadAsStreamAsync()) { var buffer = new MemoryStream(); @@ -236,16 +255,15 @@ public class AssetFormatTests : IClassFixture var url = $"{_.Client.GenerateImageUrl(imageId)}?format={format}"; var httpClient = _.Client.CreateHttpClient(); + var httpResponse = await httpClient.GetAsync(url); - var response = await httpClient.GetAsync(url); - - await using (var stream = await response.Content.ReadAsStreamAsync()) + await using (var stream = await httpResponse.Content.ReadAsStreamAsync()) { var buffer = new MemoryStream(); await stream.CopyToAsync(buffer); - return (buffer.Length, response.Content.Headers.ContentType?.ToString()); + return (buffer.Length, httpResponse.Content.Headers.ContentType?.ToString()); } } } diff --git a/tools/TestSuite/TestSuite.ApiTests/AssetScriptingTests.cs b/tools/TestSuite/TestSuite.ApiTests/AssetScriptingTests.cs index 67f94c944..1dc0f0f3c 100644 --- a/tools/TestSuite/TestSuite.ApiTests/AssetScriptingTests.cs +++ b/tools/TestSuite/TestSuite.ApiTests/AssetScriptingTests.cs @@ -31,7 +31,7 @@ public class AssetScriptingTests : IClassFixture var scriptRequest = new UpdateAssetScriptsDto { Create = @" - if (ctx.command.mimeType == 'image/jpg') { + if (ctx.command.mimeType == 'image/jpeg') { disallow('We do not use jpeg anymore.'); }" }; @@ -40,7 +40,7 @@ public class AssetScriptingTests : IClassFixture // STEP 1: Upload jpeg. - var ex = await Assert.ThrowsAnyAsync(() => client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpg")); + var ex = await Assert.ThrowsAnyAsync(() => client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpeg")); Assert.Contains("We do not use jpeg anymore.", ex.ToString(), StringComparison.Ordinal); } @@ -64,7 +64,7 @@ public class AssetScriptingTests : IClassFixture // STEP 1: Upload jpeg. - var asset = await client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpg"); + var asset = await client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpeg"); Assert.Equal("value1", asset.Metadata["key1"]); Assert.Equal("value2", asset.Metadata["key2"]); @@ -81,7 +81,7 @@ public class AssetScriptingTests : IClassFixture var scriptRequest = new UpdateAssetScriptsDto { Update = @" - if (ctx.command.mimeType == 'image/jpg') { + if (ctx.command.mimeType == 'image/jpeg') { disallow('We do not use jpeg anymore.'); }" }; @@ -94,7 +94,7 @@ public class AssetScriptingTests : IClassFixture // STEP 2: Upload jpeg. - var ex = await Assert.ThrowsAnyAsync(() => client.Assets.ReplaceFileAsync(asset_0.Id, "Assets/logo-wide-rotated.jpg", "image/jpg")); + var ex = await Assert.ThrowsAnyAsync(() => client.Assets.ReplaceFileAsync(asset_0.Id, "Assets/logo-wide-rotated.jpg", "image/jpeg")); Assert.Contains("We do not use jpeg anymore.", ex.ToString(), StringComparison.Ordinal); } @@ -120,7 +120,7 @@ public class AssetScriptingTests : IClassFixture // STEP 2: Upload jpeg. - var asset = await client.Assets.ReplaceFileAsync(asset_0.Id, "Assets/logo-wide-rotated.jpg", "image/jpg"); + var asset = await client.Assets.ReplaceFileAsync(asset_0.Id, "Assets/logo-wide-rotated.jpg", "image/jpeg"); Assert.Equal("value1", asset.Metadata["key1"]); Assert.Equal("value2", asset.Metadata["key2"]); @@ -135,7 +135,7 @@ public class AssetScriptingTests : IClassFixture var scriptRequest = new UpdateAssetScriptsDto { Query = @" - if (ctx.asset.mimeType == 'image/jpg') { + if (ctx.asset.mimeType == 'image/jpeg') { disallow('We do not use jpeg anymore.'); }" }; @@ -144,7 +144,7 @@ public class AssetScriptingTests : IClassFixture // STEP 1. Upload initial jpg. - var ex = await Assert.ThrowsAnyAsync(() => client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpg")); + var ex = await Assert.ThrowsAnyAsync(() => client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpeg")); Assert.Contains("We do not use jpeg anymore.", ex.ToString(), StringComparison.Ordinal); } diff --git a/tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_100kb.webp b/tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_100kb.webp index e91c03168..9c132d821 100644 Binary files a/tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_100kb.webp and b/tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_100kb.webp differ diff --git a/tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_WithLocation.jpg b/tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_WithLocation.jpg new file mode 100644 index 000000000..4a2c1552b Binary files /dev/null and b/tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_WithLocation.jpg differ diff --git a/tools/TestSuite/TestSuite.ApiTests/ContentLanguageTests.cs b/tools/TestSuite/TestSuite.ApiTests/ContentLanguageTests.cs index 014534d09..ddb5b8b2a 100644 --- a/tools/TestSuite/TestSuite.ApiTests/ContentLanguageTests.cs +++ b/tools/TestSuite/TestSuite.ApiTests/ContentLanguageTests.cs @@ -122,8 +122,8 @@ public class ContentLanguageTests : IClassFixture httpClient.DefaultRequestHeaders.TryAddWithoutValidation(key, value); } - var response = await httpClient.GetAsync(url); + var httpResponse = await httpClient.GetAsync(url); - return (response.Headers.GetValues("ETag").FirstOrDefault(), response.Headers.Vary.ToString()); + return (httpResponse.Headers.GetValues("ETag").FirstOrDefault(), httpResponse.Headers.Vary.ToString()); } } diff --git a/tools/TestSuite/TestSuite.ApiTests/GraphQLTests.cs b/tools/TestSuite/TestSuite.ApiTests/GraphQLTests.cs index d0eb405f1..78b0efda4 100644 --- a/tools/TestSuite/TestSuite.ApiTests/GraphQLTests.cs +++ b/tools/TestSuite/TestSuite.ApiTests/GraphQLTests.cs @@ -7,6 +7,7 @@ using System.Net.Http.Json; using FluentAssertions; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Squidex.ClientLibrary; using Squidex.ClientLibrary.Utils; @@ -26,6 +27,71 @@ public sealed class GraphQLTests : IClassFixture _ = fixture; } + [Fact] + public async Task Should_query_assets() + { + var asset = await _.Client.Assets.UploadFileAsync("Assets/logo-squared.png", "image/png"); + + var query = new + { + query = @" + query FindAsset($id: String!) { + findAsset(id: $id) { + id + version + created + createdBy + createdByUser { + id + email + displayName + } + editToken + lastModified + lastModifiedBy + lastModifiedByUser { + id + email + displayName + } + url + thumbnailUrl + mimeType + fileName + fileHash + fileSize + fileVersion + isImage + isProtected + pixelWidth + pixelHeight + parentId + tags + type + metadataText + metadataPixelWidth: metadata(path: ""pixelWidth"") + metadataUnknown: metadata(path: ""unknown"") + metadata + slug + } + }", + variables = new + { + id = asset.Id, + } + }; + + var result = await _.Client.SharedDynamicContents.GraphQlAsync(query); + + var settings = new VerifySettings(); + settings.IgnoreMember("editToken"); + settings.IgnoreMember("thumbnailUrl"); + settings.IgnoreMember("url"); + settings.IgnoreMember("version"); + + await VerifyJson(JsonConvert.SerializeObject(result), settings); + } + [Fact] public async Task Should_query_json() { @@ -342,12 +408,13 @@ public sealed class GraphQLTests : IClassFixture }" }; - var httpClient = _.Client.CreateHttpClient(); + var url = _.Client.GenerateUrl($"api/content/{_.AppName}/graphql/batch"); // Create the request manually to check the content type. - var response = await httpClient.PostAsync(_.Client.GenerateUrl($"api/content/{_.AppName}/graphql/batch"), query.ToContent(_.Client.Options)); + var httpClient = _.Client.CreateHttpClient(); + var httpResponse = await httpClient.PostAsync(url, query.ToContent(_.Client.Options)); - Assert.Equal("application/json", response.Content.Headers.ContentType?.MediaType); + Assert.Equal("application/json", httpResponse.Content.Headers.ContentType?.MediaType); } [Fact] @@ -445,10 +512,9 @@ public sealed class GraphQLTests : IClassFixture }" }; - var httpClient = _.Client.CreateHttpClient(); - // Create the request manually to check the headers. - var response = await httpClient.PostAsJsonAsync($"api/content/{_.AppName}/graphql", query); + var httpClient = _.Client.CreateHttpClient(); + var httpResponse = await httpClient.PostAsJsonAsync($"api/content/{_.AppName}/graphql", query); Assert.Equal(new[] { @@ -462,6 +528,6 @@ public sealed class GraphQLTests : IClassFixture "X-ResolveFlow", "X-ResolveUrls", "X-Unpublished" - }, response.Headers.Vary.Order().ToArray()); + }, httpResponse.Headers.Vary.Order().ToArray()); } } diff --git a/tools/TestSuite/TestSuite.ApiTests/StatisticsTests.cs b/tools/TestSuite/TestSuite.ApiTests/StatisticsTests.cs index a8ce093b6..6f22b2eb3 100644 --- a/tools/TestSuite/TestSuite.ApiTests/StatisticsTests.cs +++ b/tools/TestSuite/TestSuite.ApiTests/StatisticsTests.cs @@ -31,11 +31,10 @@ public class StatisticsTests : IClassFixture // STEP 2: Download log. var httpClient = _.Client.CreateHttpClient(); + var httpResponse = await httpClient.GetAsync(log.DownloadUrl); - var response = await httpClient.GetAsync(log.DownloadUrl); - - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal("text/csv", response.Content.Headers.GetValues("Content-Type").First()); + Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode); + Assert.Equal("text/csv", httpResponse.Content.Headers.GetValues("Content-Type").First()); } [Fact] diff --git a/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj b/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj index c50c3cebd..4da9f69aa 100644 --- a/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj +++ b/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj @@ -11,18 +11,19 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + + - - - + + + all runtime; build; native; contentfiles; analyzers @@ -76,6 +77,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_fix_orientation.verified.txt b/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_fix_orientation.verified.txt index e0fcca598..4ae20ba45 100644 --- a/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_fix_orientation.verified.txt +++ b/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_fix_orientation.verified.txt @@ -2,12 +2,12 @@ Id: Guid_1, ParentId: Guid_Empty, FileName: logo-wide-rotated.jpg, - FileHash: TLNAlI4UM3i8O4IF/O7ZuH3PrI3+bsz4AsBt9NrEydI=, + FileHash: XFoH3mp4QW9EIWjF50vJkm8IwnrjjO+ZiqV2GnH1GGw=, IsProtected: false, Slug: logo-wide-rotated.jpg, - MimeType: image/jpg, + MimeType: image/jpeg, FileType: jpg, - MetadataText: 600x135px, 15.1 kB, + MetadataText: 600x135px, 15.2 kB, Metadata: { description: JFIF File, imageQuality: 79, @@ -19,7 +19,7 @@ image, image/medium ], - FileSize: 15425, + FileSize: 15598, Type: Image, Links: { content: { diff --git a/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_jpg_and_resize.verified.txt b/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_jpg_and_resize.verified.txt index f37fad969..480ba9f4f 100644 --- a/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_jpg_and_resize.verified.txt +++ b/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_jpg_and_resize.verified.txt @@ -2,12 +2,12 @@ Id: Guid_1, ParentId: Guid_Empty, FileName: SampleImage_62kb.jpg, - FileHash: hmGXmHleJqbU37bbPExix+Jbu36GNq6ZPf09Uw63t8w=, + FileHash: ss/g3yq5dO3jYbWzJ9j2psJo1Nrk5TjSi78LJfCma38=, IsProtected: false, Slug: sampleimage-62kb.jpg, - MimeType: image/jpg, + MimeType: image/jpeg, FileType: jpg, - MetadataText: 600x400px, 62 kB, + MetadataText: 600x400px, 59.2 kB, Metadata: { description: JFIF File, imageQuality: 79, @@ -19,7 +19,7 @@ image, image/medium ], - FileSize: 63507, + FileSize: 60603, Type: Image, Links: { content: { diff --git a/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_tiff_and_resize.verified.txt b/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_tiff_and_resize.verified.txt index d36c9875b..750a870e8 100644 --- a/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_tiff_and_resize.verified.txt +++ b/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_tiff_and_resize.verified.txt @@ -5,7 +5,7 @@ FileHash: f+ZdTDOoK23jmThbfPhWhXL8Q9+KIQajHeFfT/MtWFU=, IsProtected: false, Slug: sampleimage-400kb.tiff, - MimeType: image/jpg, + MimeType: image/jpeg, FileType: tiff, MetadataText: 600x400px, 473.6 kB, Metadata: { diff --git a/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_webp_and_resize.verified.txt b/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_webp_and_resize.verified.txt index 3cbf0c952..d29bf5971 100644 --- a/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_webp_and_resize.verified.txt +++ b/tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_webp_and_resize.verified.txt @@ -2,12 +2,12 @@ Id: Guid_1, ParentId: Guid_Empty, FileName: SampleImage_100kb.webp, - FileHash: WwD409RVswvccG2YopnFqJzpWrCveLrd0Zj6Buw8Vao=, + FileHash: fH0g7j4+h2vR6q0/E3BabgDqtFk0FnDfxT/AkuHKkf8=, IsProtected: false, Slug: sampleimage-100kb.webp, - MimeType: image/jpg, + MimeType: image/jpeg, FileType: webp, - MetadataText: 600x400px, 109.5 kB, + MetadataText: 600x400px, 37.7 kB, Metadata: { pixelHeight: 400, pixelWidth: 600 @@ -17,7 +17,7 @@ image, image/medium ], - FileSize: 112138, + FileSize: 38580, Type: Image, Links: { content: { diff --git a/tools/TestSuite/TestSuite.ApiTests/Verify/GraphQLTests.Should_query_assets.verified.txt b/tools/TestSuite/TestSuite.ApiTests/Verify/GraphQLTests.Should_query_assets.verified.txt new file mode 100644 index 000000000..3a1bf6fde --- /dev/null +++ b/tools/TestSuite/TestSuite.ApiTests/Verify/GraphQLTests.Should_query_assets.verified.txt @@ -0,0 +1,44 @@ +{ + findAsset: { + id: Guid_1, + created: DateTimeOffset_1, + createdBy: client:root, + createdByUser: { + id: root, + email: client:root, + displayName: root + }, + lastModified: DateTimeOffset_1, + lastModifiedBy: client:root, + lastModifiedByUser: { + id: root, + email: client:root, + displayName: root + }, + mimeType: image/png, + fileName: logo-squared.png, + fileHash: pAp0RDvipkoNCCTgey1HTJekRKKEWT6Ft5JdRLuAfAc=, + fileSize: 19430, + fileVersion: 0, + isImage: true, + isProtected: false, + pixelWidth: 600, + pixelHeight: 600, + parentId: Guid_Empty, + tags: [ + type/png, + image, + image/medium + ], + type: IMAGE, + metadataText: 600x600px, 19 kB, + metadataPixelWidth: 600, + metadataUnknown: null, + metadata: { + pixelWidth: 600, + pixelHeight: 600, + description: PNG File + }, + slug: logo-squared.png + } +} \ No newline at end of file