Browse Source

Fix job cleanup (#1075)

* Fix job cleanup

* Fix assets.

* More graphql tests.

* Fix tests

* Another asset test.

* Use final image.
pull/1076/head
Sebastian Stehle 2 years ago
committed by GitHub
parent
commit
31b011f5d4
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 14
      backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj
  2. 2
      backend/src/Migrations/Migrations.csproj
  3. 2
      backend/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj
  4. 18
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringAsyncJintExtension.cs
  5. 6
      backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj
  6. 4
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj
  7. 5
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs
  8. 3
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs
  9. 29
      backend/src/Squidex.Domain.Apps.Entities/Jobs/DefaultJobService.cs
  10. 18
      backend/src/Squidex.Domain.Apps.Entities/Jobs/JobProcessor.cs
  11. 9
      backend/src/Squidex.Domain.Apps.Entities/Jobs/JobWorker.cs
  12. 2
      backend/src/Squidex.Domain.Apps.Entities/Jobs/Messages.cs
  13. 12
      backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj
  14. 2
      backend/src/Squidex.Domain.Apps.Events/Squidex.Domain.Apps.Events.csproj
  15. 4
      backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj
  16. 6
      backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj
  17. 50
      backend/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStoreSubscription.cs
  18. 10
      backend/src/Squidex.Infrastructure.GetEventStore/Squidex.Infrastructure.GetEventStore.csproj
  19. 6
      backend/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj
  20. 20
      backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj
  21. 2
      backend/src/Squidex.Shared/Squidex.Shared.csproj
  22. 8
      backend/src/Squidex.Web/Squidex.Web.csproj
  23. 4
      backend/src/Squidex/Areas/Api/Controllers/Apps/AppImageController.cs
  24. 4
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs
  25. 20
      backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs
  26. 4
      backend/src/Squidex/Config/Domain/FontendServices.cs
  27. 2
      backend/src/Squidex/Config/Domain/InfrastructureServices.cs
  28. 52
      backend/src/Squidex/Squidex.csproj
  29. 16
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs
  30. 8
      backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj
  31. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs
  32. 16
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj
  33. 8
      backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj
  34. 8
      backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj
  35. 8
      backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj
  36. 40
      tools/TestSuite/TestSuite.ApiTests/AssetFormatTests.cs
  37. 16
      tools/TestSuite/TestSuite.ApiTests/AssetScriptingTests.cs
  38. BIN
      tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_100kb.webp
  39. BIN
      tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_WithLocation.jpg
  40. 4
      tools/TestSuite/TestSuite.ApiTests/ContentLanguageTests.cs
  41. 80
      tools/TestSuite/TestSuite.ApiTests/GraphQLTests.cs
  42. 7
      tools/TestSuite/TestSuite.ApiTests/StatisticsTests.cs
  43. 20
      tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj
  44. 8
      tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_fix_orientation.verified.txt
  45. 8
      tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_jpg_and_resize.verified.txt
  46. 2
      tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_tiff_and_resize.verified.txt
  47. 8
      tools/TestSuite/TestSuite.ApiTests/Verify/AssetFormatTests.Should_upload_image_webp_and_resize.verified.txt
  48. 44
      tools/TestSuite/TestSuite.ApiTests/Verify/GraphQLTests.Should_query_assets.verified.txt

14
backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj

@ -10,26 +10,26 @@
<ProjectReference Include="..\..\src\Squidex.Web\Squidex.Web.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Algolia.Search" Version="6.16.0" />
<PackageReference Include="Algolia.Search" Version="6.17.0" />
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.2.0" />
<PackageReference Include="Azure.Search.Documents" Version="11.5.1" />
<PackageReference Include="Confluent.SchemaRegistry.Serdes.Avro" Version="2.3.0" />
<PackageReference Include="CoreTweet" Version="1.0.0.483" />
<PackageReference Include="Elasticsearch.Net" Version="7.17.5" />
<PackageReference Include="Google.Cloud.Diagnostics.Common" Version="5.1.0" />
<PackageReference Include="Google.Cloud.Logging.V2" Version="4.1.0" />
<PackageReference Include="Google.Cloud.Monitoring.V3" Version="3.5.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Google.Cloud.Logging.V2" Version="4.2.0" />
<PackageReference Include="Google.Cloud.Monitoring.V3" Version="3.6.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Azure.CognitiveServices.Vision.ComputerVision" Version="7.0.1" />
<PackageReference Include="Microsoft.Azure.SignalR.Management" Version="1.24.0" />
<PackageReference Include="Microsoft.Azure.SignalR.Management" Version="1.25.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Microsoft.OData.Core" Version="7.20.0" />
<PackageReference Include="NodaTime" Version="3.1.10" />
<PackageReference Include="OpenSearch.Net" Version="1.6.0" />
<PackageReference Include="NodaTime" Version="3.1.11" />
<PackageReference Include="OpenSearch.Net" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Exporter.Zipkin" Version="1.7.0" />

2
backend/src/Migrations/Migrations.csproj

@ -6,7 +6,7 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

2
backend/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj

@ -12,7 +12,7 @@
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

18
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<JsValue> callback);
private delegate void TextTranslateDelegate(string text, string language, Action<JsValue> 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)
{

6
backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj

@ -20,15 +20,15 @@
<ItemGroup>
<PackageReference Include="Fluid.Core" Version="2.5.0" />
<PackageReference Include="GeoJSON.Net" Version="1.2.19" />
<PackageReference Include="Jint" Version="3.0.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Jint" Version="3.0.1" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="NJsonSchema" Version="11.0.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Messaging.Subscriptions" Version="6.3.7" />
<PackageReference Include="Squidex.Messaging.Subscriptions" Version="6.4.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="8.0.0" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />

4
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj

@ -19,11 +19,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Lucene.Net.QueryParser" Version="4.8.0-beta00016" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MongoDB.Driver" Version="2.23.1" />
<PackageReference Include="MongoDB.Driver" Version="2.24.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />

5
backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs

@ -75,6 +75,7 @@ public sealed class AssetCommandMiddleware : CachingDomainObjectMiddleware<Asset
try
{
await EnrichWithMetadataAsync(command, ct);
await EnrichWithHashAndUploadAsync(command, command.FileId, ct);
if (!duplicate)
@ -95,8 +96,6 @@ public sealed class AssetCommandMiddleware : CachingDomainObjectMiddleware<Asset
}
}
await EnrichWithMetadataAsync(command, ct);
await base.HandleAsync(context, next, ct);
}
finally
@ -113,8 +112,8 @@ public sealed class AssetCommandMiddleware : CachingDomainObjectMiddleware<Asset
try
{
await EnrichWithHashAndUploadAsync(command, command.FileId, ct);
await EnrichWithMetadataAsync(command, ct);
await EnrichWithHashAndUploadAsync(command, command.FileId, ct);
await base.HandleAsync(context, next, ct);
}

3
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs

@ -43,8 +43,7 @@ public sealed class GraphQLExecutionContext : QueryExecutionContext
Context = context.Clone(b => b
.WithResolveSchemaNames()
.WithNoCleanup()
.WithNoEnrichment()
.WithNoAssetEnrichment());
.WithNoEnrichment());
this.options = options.Value;

29
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<DomainId, bool> wokenUp = [];
private readonly IMessageBus messaging;
private readonly IEnumerable<IJobRunner> runners;
private readonly IPersistenceFactory<JobsState> 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<List<Job>> 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);
}
}
}

18
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);
}

9
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<JobStart>,
IMessageHandler<JobDelete>,
IMessageHandler<JobCancel>,
IMessageHandler<JobClear>
IMessageHandler<JobClear>,
IMessageHandler<JobWakeup>
{
private readonly Dictionary<DomainId, Task<JobProcessor>> processors = [];
private readonly Func<DomainId, JobProcessor> 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<JobProcessor> GetJobProcessorAsync(DomainId appId)
{
lock (processors)

2
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);

12
backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj

@ -24,15 +24,15 @@
<ProjectReference Include="..\Squidex.Shared\Squidex.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CsvHelper" Version="30.1.0" />
<PackageReference Include="GraphQL" Version="7.7.2" />
<PackageReference Include="GraphQL.DataLoader" Version="7.7.2" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="CsvHelper" Version="31.0.2" />
<PackageReference Include="GraphQL" Version="7.8.0" />
<PackageReference Include="GraphQL.DataLoader" Version="7.8.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageReference Include="Notifo.SDK" Version="1.7.4" />
<PackageReference Include="Notifo.SDK" Version="1.7.5" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.CLI.Core" Version="13.0.0" />
<PackageReference Include="Squidex.YDotNet.Extensions" Version="0.2.9" />
@ -41,7 +41,7 @@
<PackageReference Include="System.Collections.Immutable" Version="8.0.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="taglib-sharp-netstandard2.0" Version="2.1.0" />
<PackageReference Include="tusdotnet" Version="2.7.2" />
<PackageReference Include="tusdotnet" Version="2.8.0" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" />

2
backend/src/Squidex.Domain.Apps.Events/Squidex.Domain.Apps.Events.csproj

@ -14,7 +14,7 @@
<ProjectReference Include="..\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

4
backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj

@ -19,12 +19,12 @@
<ProjectReference Include="..\Squidex.Shared\Squidex.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="MongoDB.Driver" Version="2.23.1" />
<PackageReference Include="MongoDB.Driver" Version="2.24.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />

6
backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj

@ -18,13 +18,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="IdentityModel" Version="6.2.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="8.0.2" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="OpenIddict.AspNetCore" Version="5.1.0" />
<PackageReference Include="OpenIddict.AspNetCore" Version="5.2.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="SharpPwned.NET" Version="2.0.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />

50
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<StoredEvent> 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();
}

10
backend/src/Squidex.Infrastructure.GetEventStore/Squidex.Infrastructure.GetEventStore.csproj

@ -11,11 +11,11 @@
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EventStore.Client.Grpc.PersistentSubscriptions" Version="23.1.0" />
<PackageReference Include="EventStore.Client.Grpc.ProjectionManagement" Version="23.1.0" />
<PackageReference Include="EventStore.Client.Grpc.Streams" Version="23.1.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.60.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="EventStore.Client.Grpc.PersistentSubscriptions" Version="23.2.0" />
<PackageReference Include="EventStore.Client.Grpc.ProjectionManagement" Version="23.2.0" />
<PackageReference Include="EventStore.Client.Grpc.Streams" Version="23.2.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.61.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

6
backend/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj

@ -14,12 +14,12 @@
<ProjectReference Include="..\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MongoDB.Driver" Version="2.23.1" />
<PackageReference Include="MongoDB.Driver.GridFS" Version="2.23.1" />
<PackageReference Include="MongoDB.Driver" Version="2.24.0" />
<PackageReference Include="MongoDB.Driver.GridFS" Version="2.24.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />

20
backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj

@ -11,25 +11,25 @@
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MailKit" Version="4.3.0" />
<PackageReference Include="MailKit" Version="4.4.0" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="8.0.2" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
<PackageReference Include="Microsoft.OData.Core" Version="7.20.0" />
<PackageReference Include="NodaTime" Version="3.1.10" />
<PackageReference Include="NodaTime" Version="3.1.11" />
<PackageReference Include="OpenTelemetry.Api" Version="1.7.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets" Version="6.3.7" />
<PackageReference Include="Squidex.Caching" Version="6.3.7" />
<PackageReference Include="Squidex.Hosting.Abstractions" Version="6.3.7" />
<PackageReference Include="Squidex.Log" Version="6.3.7" />
<PackageReference Include="Squidex.Messaging" Version="6.3.7" />
<PackageReference Include="Squidex.Text" Version="6.3.7" />
<PackageReference Include="Squidex.Assets" Version="6.4.1" />
<PackageReference Include="Squidex.Caching" Version="6.4.1" />
<PackageReference Include="Squidex.Hosting.Abstractions" Version="6.4.1" />
<PackageReference Include="Squidex.Log" Version="6.4.1" />
<PackageReference Include="Squidex.Messaging" Version="6.4.1" />
<PackageReference Include="Squidex.Text" Version="6.4.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="8.0.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />

2
backend/src/Squidex.Shared/Squidex.Shared.csproj

@ -10,7 +10,7 @@
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

8
backend/src/Squidex.Web/Squidex.Web.csproj

@ -13,10 +13,10 @@
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="GraphQL" Version="7.7.2" />
<PackageReference Include="GraphQL.SystemTextJson" Version="7.7.2" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="7.6.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="GraphQL" Version="7.8.0" />
<PackageReference Include="GraphQL.SystemTextJson" Version="7.8.0" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="7.7.1" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

4
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
{

4
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"))
{

20
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;
}
/// <summary>
@ -64,9 +64,17 @@ public sealed class TranslationsController : ApiController
[ApiCosts(10)]
public async Task<IActionResult> 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);
}
}
}

4
backend/src/Squidex/Config/Domain/FontendServices.cs

@ -51,9 +51,9 @@ public static class FontendServices
services.Configure<MyUIOptions>((services, options) =>
{
var chatBot = services.GetRequiredService<IChatBot>();
var chatAgent = services.GetRequiredService<IChatAgent>();
options.More["canUseChatBot"] = chatBot.IsConfigured;
options.More["canUseChatBot"] = chatAgent.IsConfigured;
});
services.Configure<MyUIOptions>((services, options) =>

2
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)

52
backend/src/Squidex/Squidex.csproj

@ -34,47 +34,47 @@
<ItemGroup>
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="8.0.0" />
<PackageReference Include="GraphQL" Version="7.7.2" />
<PackageReference Include="GraphQL.MicrosoftDI" Version="7.7.2" />
<PackageReference Include="GraphQL.SystemTextJson" Version="7.7.2" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="GraphQL" Version="7.8.0" />
<PackageReference Include="GraphQL.MicrosoftDI" Version="7.8.0" />
<PackageReference Include="GraphQL.SystemTextJson" Version="7.8.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="8.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="8.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.2" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.2" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.RulesetToEditorconfigConverter" Version="3.3.3" />
<PackageReference Include="Microsoft.Data.Edm" Version="5.8.5" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageReference Include="Microsoft.OData.Core" Version="7.20.0" />
<PackageReference Include="MongoDB.Driver" Version="2.23.1" />
<PackageReference Include="MongoDB.Driver" Version="2.24.0" />
<PackageReference Include="MongoDB.Driver.Core.Extensions.OpenTelemetry" Version="1.0.0" />
<PackageReference Include="NetTopologySuite.IO.GeoJSON4STJ" Version="4.0.0" />
<PackageReference Include="NJsonSchema" Version="11.0.0" />
<PackageReference Include="NodaTime.Serialization.SystemTextJson" Version="1.1.2" />
<PackageReference Include="NSwag.AspNetCore" Version="14.0.2" />
<PackageReference Include="NSwag.AspNetCore" Version="14.0.3" />
<PackageReference Include="OpenCover" Version="4.7.1221" PrivateAssets="all" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.1" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="ReportGenerator" Version="5.2.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets.Azure" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.GoogleCloud" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.FTP" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.ImageMagick" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.ImageSharp" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.Mongo" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.S3" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.TusAdapter" Version="6.3.7" />
<PackageReference Include="ReportGenerator" Version="5.2.2" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets.Azure" Version="6.4.1" />
<PackageReference Include="Squidex.Assets.GoogleCloud" Version="6.4.1" />
<PackageReference Include="Squidex.Assets.FTP" Version="6.4.1" />
<PackageReference Include="Squidex.Assets.ImageMagick" Version="6.4.1" />
<PackageReference Include="Squidex.Assets.ImageSharp" Version="6.4.1" />
<PackageReference Include="Squidex.Assets.Mongo" Version="6.4.1" />
<PackageReference Include="Squidex.Assets.S3" Version="6.4.1" />
<PackageReference Include="Squidex.Assets.TusAdapter" Version="6.4.1" />
<PackageReference Include="Squidex.ClientLibrary" Version="19.1.0" />
<PackageReference Include="Squidex.Hosting" Version="6.3.7" />
<PackageReference Include="Squidex.Messaging.All" Version="6.3.7" />
<PackageReference Include="Squidex.Messaging.Subscriptions" Version="6.3.7" />
<PackageReference Include="Squidex.Hosting" Version="6.4.1" />
<PackageReference Include="Squidex.Messaging.All" Version="6.4.1" />
<PackageReference Include="Squidex.Messaging.Subscriptions" Version="6.4.1" />
<PackageReference Include="Squidex.OpenIddict.MongoDb" Version="5.1.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="YDotNet" Version="0.3.0" />

16
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs

@ -24,7 +24,7 @@ public class JintScriptEngineHelperTests : IClassFixture<TranslationsFixture>
{
private readonly IHttpClientFactory httpClientFactory = A.Fake<IHttpClientFactory>();
private readonly ITranslator translator = A.Fake<ITranslator>();
private readonly IChatBot chatBot = A.Fake<IChatBot>();
private readonly IChatAgent chatAgent = A.Fake<IChatAgent>();
private readonly JintScriptEngine sut;
public JintScriptEngineHelperTests()
@ -35,7 +35,7 @@ public class JintScriptEngineHelperTests : IClassFixture<TranslationsFixture>
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<TranslationsFixture>
[Fact]
public async Task Should_generate_content()
{
A.CallTo(() => chatBot.AskQuestionAsync("prompt", A<CancellationToken>._))
.Returns(new ChatBotResult { Choices = new List<string> { "Generated" } });
A.CallTo(() => chatAgent.PromptAsync(A<string>._, "prompt", A<CancellationToken>._))
.Returns(ChatBotResponse.Success("Generated"));
var vars = new ScriptVars
{
@ -635,6 +635,9 @@ public class JintScriptEngineHelperTests : IClassFixture<TranslationsFixture>
var actual = await sut.ExecuteAsync(vars, script);
Assert.Equal("Generated", actual.ToString());
A.CallTo(() => chatAgent.StopConversationAsync(A<string>._, A<CancellationToken>._))
.MustHaveHappened();
}
[Theory]
@ -657,7 +660,10 @@ public class JintScriptEngineHelperTests : IClassFixture<TranslationsFixture>
Assert.Equal(JsonValue.Null, actual);
A.CallTo(() => chatBot.AskQuestionAsync(A<string>._, A<CancellationToken>._))
A.CallTo(() => chatAgent.PromptAsync(A<string>._, A<string>._, A<CancellationToken>._))
.MustNotHaveHappened();
A.CallTo(() => chatAgent.StopConversationAsync(A<string>._, A<CancellationToken>._))
.MustNotHaveHappened();
}

8
backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj

@ -16,19 +16,19 @@
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="8.1.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="NetTopologySuite.IO.GeoJSON4STJ" Version="4.0.0" />
<PackageReference Include="NodaTime.Serialization.SystemTextJson" Version="1.1.2" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit" Version="2.7.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs

@ -163,7 +163,7 @@ public abstract class GraphQLTestBase : IClassFixture<TranslationsFixture>
return A<Context>.That.Matches(x =>
x.App == TestApp.Default &&
x.NoCleanup() &&
x.NoAssetEnrichment());
!x.NoAssetEnrichment());
}
protected static Context MatchsContentContext()

16
backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj

@ -24,24 +24,24 @@
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="8.1.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="GraphQL" Version="7.7.2" />
<PackageReference Include="GraphQL.SystemTextJson" Version="7.7.2" />
<PackageReference Include="GraphQL" Version="7.8.0" />
<PackageReference Include="GraphQL.SystemTextJson" Version="7.8.0" />
<PackageReference Include="Lorem.Universal.Net" Version="4.0.80" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="3.1.0" />
<PackageReference Include="Squidex.YDotNet.Native" Version="0.2.9" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Reactive.Linq" Version="6.0.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="Verify.Xunit" Version="23.0.1" />
<PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="Verify.Xunit" Version="23.2.2" />
<PackageReference Include="xunit" Version="2.7.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

8
backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj

@ -16,15 +16,15 @@
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="8.1.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit" Version="2.7.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

8
backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj

@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="8.1.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@ -24,12 +24,12 @@
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="NodaTime.Serialization.SystemTextJson" Version="1.1.2" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit" Version="2.7.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

8
backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj

@ -16,14 +16,14 @@
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="8.1.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit" Version="2.7.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

40
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<CreatedAppFixture>
[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<CreatedAppFixture>
[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<CreatedAppFixture>
[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<CreatedAppFixture>
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<CreatedAppFixture>
[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<CreatedAppFixture>
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<CreatedAppFixture>
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());
}
}
}

16
tools/TestSuite/TestSuite.ApiTests/AssetScriptingTests.cs

@ -31,7 +31,7 @@ public class AssetScriptingTests : IClassFixture<ClientFixture>
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<ClientFixture>
// STEP 1: Upload jpeg.
var ex = await Assert.ThrowsAnyAsync<SquidexException>(() => client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpg"));
var ex = await Assert.ThrowsAnyAsync<SquidexException>(() => 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<ClientFixture>
// 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<ClientFixture>
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<ClientFixture>
// STEP 2: Upload jpeg.
var ex = await Assert.ThrowsAnyAsync<SquidexException>(() => client.Assets.ReplaceFileAsync(asset_0.Id, "Assets/logo-wide-rotated.jpg", "image/jpg"));
var ex = await Assert.ThrowsAnyAsync<SquidexException>(() => 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<ClientFixture>
// 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<ClientFixture>
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<ClientFixture>
// STEP 1. Upload initial jpg.
var ex = await Assert.ThrowsAnyAsync<SquidexException>(() => client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpg"));
var ex = await Assert.ThrowsAnyAsync<SquidexException>(() => client.Assets.UploadFileAsync("Assets/logo-wide-rotated.jpg", "image/jpeg"));
Assert.Contains("We do not use jpeg anymore.", ex.ToString(), StringComparison.Ordinal);
}

BIN
tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_100kb.webp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 38 KiB

BIN
tools/TestSuite/TestSuite.ApiTests/Assets/SampleImage_WithLocation.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

4
tools/TestSuite/TestSuite.ApiTests/ContentLanguageTests.cs

@ -122,8 +122,8 @@ public class ContentLanguageTests : IClassFixture<ContentFixture>
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());
}
}

80
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<GraphQLFixture>
_ = 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<JToken>(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<GraphQLFixture>
}"
};
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<GraphQLFixture>
}"
};
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<GraphQLFixture>
"X-ResolveFlow",
"X-ResolveUrls",
"X-Unpublished"
}, response.Headers.Vary.Order().ToArray());
}, httpResponse.Headers.Vary.Order().ToArray());
}
}

7
tools/TestSuite/TestSuite.ApiTests/StatisticsTests.cs

@ -31,11 +31,10 @@ public class StatisticsTests : IClassFixture<CreatedAppFixture>
// 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]

20
tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj

@ -11,18 +11,19 @@
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="GraphQL.Client" Version="6.0.2" />
<PackageReference Include="GraphQL.Client.Serializer.Newtonsoft" Version="6.0.2" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PackageReference Include="Meziantou.Analyzer" Version="2.0.145">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="NSwag.Core" Version="14.0.2" />
<PackageReference Include="PuppeteerSharp" Version="14.0.0" />
<PackageReference Include="Squidex.Assets" Version="6.3.7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="NSwag.Core" Version="14.0.3" />
<PackageReference Include="PuppeteerSharp" Version="14.1.0" />
<PackageReference Include="Squidex.Assets" Version="6.4.1" />
<PackageReference Include="Squidex.Assets.ImageSharp" Version="6.4.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="Verify.Xunit" Version="23.0.1" />
<PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="Verify.Xunit" Version="23.2.2" />
<PackageReference Include="xunit" Version="2.7.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
@ -76,6 +77,9 @@
<None Update="Assets\SampleImage_700kb.bmp">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\SampleImage_WithLocation.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\SampleJPGImage_50kbmb.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

8
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: {

8
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: {

2
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: {

8
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: {

44
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
}
}
Loading…
Cancel
Save