Browse Source

Fix SVG (#1070)

* Fix SVG

* Update editor.
pull/1071/head
Sebastian Stehle 3 years ago
committed by GitHub
parent
commit
a59fa91a26
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj
  2. 2
      backend/src/Migrations/Migrations.csproj
  3. 4
      backend/src/Migrations/OldEvents/AssetCreated.cs
  4. 4
      backend/src/Migrations/OldEvents/AssetUpdated.cs
  5. 81
      backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetMetadata.cs
  6. 29
      backend/src/Squidex.Domain.Apps.Core.Model/Assets/KnownMetadataKeys.cs
  7. 2
      backend/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj
  8. 4
      backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj
  9. 30
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AssetsValidator.cs
  10. 2
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj
  11. 9
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs
  12. 38
      backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs
  13. 20
      backend/src/Squidex.Domain.Apps.Entities/Assets/ImageAssetMetadataSource.cs
  14. 66
      backend/src/Squidex.Domain.Apps.Entities/Assets/SvgAssetMetadataSource.cs
  15. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetGraphType.cs
  16. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/EnrichedAssetEventGraphType.cs
  17. 4
      backend/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj
  18. 2
      backend/src/Squidex.Domain.Apps.Events/Squidex.Domain.Apps.Events.csproj
  19. 2
      backend/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj
  20. 2
      backend/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj
  21. 2
      backend/src/Squidex.Infrastructure.GetEventStore/Squidex.Infrastructure.GetEventStore.csproj
  22. 2
      backend/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj
  23. 14
      backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj
  24. 2
      backend/src/Squidex.Shared/Squidex.Shared.csproj
  25. 2
      backend/src/Squidex.Web/Squidex.Web.csproj
  26. 4
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetContentQueryDto.cs
  27. 4
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs
  28. 26
      backend/src/Squidex/Squidex.csproj
  29. 2
      backend/src/Squidex/wwwroot/editor/squidex-editor.js
  30. 36
      backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetMetadataTests.cs
  31. 4
      backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetTests.cs
  32. 18
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs
  33. 2
      backend/tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj
  34. 18
      backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestAssets.cs
  35. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs
  36. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetDomainObjectTests.cs
  37. 36
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/FileTagAssetMetadataSourceTests.cs
  38. 28
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs
  39. 74
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/SvgAssetMetadataSourceTests.cs
  40. 5
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/TestFiles/SvgInvalid.svg
  41. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/TestFiles/SvgValid.svg
  42. 17
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestAsset.cs
  43. 90
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.Designer.cs
  44. 135
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.resx
  45. 21
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj
  46. 2
      backend/tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj
  47. 2
      backend/tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj
  48. 2
      backend/tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj
  49. 1
      tools/TestSuite/TestSuite.ApiTests/AnonymousTests.cs
  50. 1
      tools/TestSuite/TestSuite.ApiTests/AppClientsTests.cs
  51. 1
      tools/TestSuite/TestSuite.ApiTests/AppContributorsTests.cs
  52. 1
      tools/TestSuite/TestSuite.ApiTests/AppCreationTests.cs
  53. 1
      tools/TestSuite/TestSuite.ApiTests/AppLanguagesTests.cs
  54. 1
      tools/TestSuite/TestSuite.ApiTests/AppRolesTests.cs
  55. 1
      tools/TestSuite/TestSuite.ApiTests/AppTests.cs
  56. 1
      tools/TestSuite/TestSuite.ApiTests/AppWorkflowsTests.cs
  57. 1
      tools/TestSuite/TestSuite.ApiTests/AssetFoldersTests.cs
  58. 1
      tools/TestSuite/TestSuite.ApiTests/AssetFormatTests.cs
  59. 1
      tools/TestSuite/TestSuite.ApiTests/AssetTests.cs
  60. 1
      tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs
  61. 1
      tools/TestSuite/TestSuite.ApiTests/RuleTests.cs
  62. 1
      tools/TestSuite/TestSuite.ApiTests/SchemaTests.cs
  63. 1
      tools/TestSuite/TestSuite.ApiTests/TeamContributorTests.cs
  64. 1
      tools/TestSuite/TestSuite.ApiTests/TeamTests.cs
  65. 14
      tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj
  66. 4
      tools/TestSuite/TestSuite.LoadTests/TestSuite.LoadTests.csproj
  67. 12
      tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj

4
backend/extensions/Squidex.Extensions/Squidex.Extensions.csproj

@ -11,7 +11,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Algolia.Search" Version="6.16.0" /> <PackageReference Include="Algolia.Search" Version="6.16.0" />
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.1.0" /> <PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.2.0" />
<PackageReference Include="Azure.Search.Documents" Version="11.5.1" /> <PackageReference Include="Azure.Search.Documents" Version="11.5.1" />
<PackageReference Include="Confluent.SchemaRegistry.Serdes.Avro" Version="2.3.0" /> <PackageReference Include="Confluent.SchemaRegistry.Serdes.Avro" Version="2.3.0" />
<PackageReference Include="CoreTweet" Version="1.0.0.483" /> <PackageReference Include="CoreTweet" Version="1.0.0.483" />
@ -19,7 +19,7 @@
<PackageReference Include="Google.Cloud.Diagnostics.Common" Version="5.1.0" /> <PackageReference Include="Google.Cloud.Diagnostics.Common" Version="5.1.0" />
<PackageReference Include="Google.Cloud.Logging.V2" Version="4.1.0" /> <PackageReference Include="Google.Cloud.Logging.V2" Version="4.1.0" />
<PackageReference Include="Google.Cloud.Monitoring.V3" Version="3.5.0" /> <PackageReference Include="Google.Cloud.Monitoring.V3" Version="3.5.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

2
backend/src/Migrations/Migrations.csproj

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

4
backend/src/Migrations/OldEvents/AssetCreated.cs

@ -50,8 +50,8 @@ public sealed class AssetCreated : AssetEvent, IMigrated<IEvent>
{ {
result.Type = AssetType.Image; result.Type = AssetType.Image;
result.Metadata.SetPixelWidth(PixelWidth.Value); result.Metadata[KnownMetadataKeys.PixelWidth] = PixelWidth.Value;
result.Metadata.SetPixelHeight(PixelHeight.Value); result.Metadata[KnownMetadataKeys.PixelHeight] = PixelHeight.Value;
} }
return result; return result;

4
backend/src/Migrations/OldEvents/AssetUpdated.cs

@ -41,8 +41,8 @@ public sealed class AssetUpdated : AssetEvent, IMigrated<IEvent>
{ {
result.Type = AssetType.Image; result.Type = AssetType.Image;
result.Metadata.SetPixelWidth(PixelWidth.Value); result.Metadata[KnownMetadataKeys.PixelWidth] = PixelWidth.Value;
result.Metadata.SetPixelHeight(PixelHeight.Value); result.Metadata[KnownMetadataKeys.PixelHeight] = PixelHeight.Value;
} }
return result; return result;

81
backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetMetadata.cs

@ -14,86 +14,7 @@ public sealed class AssetMetadata : Dictionary<string, JsonValue>
{ {
private static readonly char[] PathSeparators = ['.', '[', ']']; private static readonly char[] PathSeparators = ['.', '[', ']'];
public const string FocusX = "focusX"; public int? GetInt32(string name)
public const string FocusY = "focusY";
public const string PixelWidth = "pixelWidth";
public const string PixelHeight = "pixelHeight";
public const string VideoWidth = "videoWidth";
public const string VideoHeight = "videoHeight";
public AssetMetadata SetFocusX(float value)
{
this[FocusX] = (double)value;
return this;
}
public AssetMetadata SetFocusY(float value)
{
this[FocusY] = (double)value;
return this;
}
public AssetMetadata SetPixelWidth(int value)
{
this[PixelWidth] = value;
return this;
}
public AssetMetadata SetPixelHeight(int value)
{
this[PixelHeight] = value;
return this;
}
public AssetMetadata SetVideoWidth(int value)
{
this[VideoWidth] = value;
return this;
}
public AssetMetadata SetVideoHeight(int value)
{
this[VideoHeight] = value;
return this;
}
public float? GetFocusX()
{
return GetSingle(FocusX);
}
public float? GetFocusY()
{
return GetSingle(FocusY);
}
public int? GetPixelWidth()
{
return GetIn32(PixelWidth);
}
public int? GetPixelHeight()
{
return GetIn32(PixelHeight);
}
public int? GetVideoWidth()
{
return GetIn32(VideoWidth);
}
public int? GetVideoHeight()
{
return GetIn32(VideoHeight);
}
public int? GetIn32(string name)
{ {
if (TryGetValue(name, out var value) && value.Value is double n) if (TryGetValue(name, out var value) && value.Value is double n)
{ {

29
backend/src/Squidex.Domain.Apps.Core.Model/Assets/KnownMetadataKeys.cs

@ -0,0 +1,29 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Domain.Apps.Core.Assets;
public static class KnownMetadataKeys
{
public const string AudioBitrate = "audioBitrate";
public const string AudioChannels = "audioChannels";
public const string AudioSampleRate = "audioSampleRate";
public const string BitsPerSample = "bitsPerSample";
public const string Created = "created";
public const string Description = "description";
public const string Duration = "duration";
public const string FocusX = "focusX";
public const string FocusY = "focusY";
public const string ImageQuality = "imageQuality";
public const string Latitude = "latitude";
public const string Longitude = "longitude";
public const string PixelHeight = "pixelHeight";
public const string PixelWidth = "pixelWidth";
public const string VideoHeight = "videoHeight";
public const string VideoWidth = "videoWidth";
public const string ViewBox = "viewBox";
}

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

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

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

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

30
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AssetsValidator.cs

@ -63,9 +63,9 @@ public sealed class AssetsValidator : IValidator
foreach (var assetId in assetIds) foreach (var assetId in assetIds)
{ {
var assetPath = context.Path.Enqueue($"[{index}]"); var assetPath = context.Path.Enqueue($"[{index}]");
var assetItem = assets.FirstOrDefault(x => x.Id == assetId); var assetFound = assets.FirstOrDefault(x => x.Id == assetId);
if (assetItem == null) if (assetFound == null)
{ {
if (context.Action == ValidationAction.Upsert) if (context.Action == ValidationAction.Upsert)
{ {
@ -75,29 +75,25 @@ public sealed class AssetsValidator : IValidator
continue; continue;
} }
foundIds.Add(assetItem.Id); foundIds.Add(assetFound.Id);
ValidateCommon(assetItem, assetPath, context); ValidateCommon(assetFound, assetPath, context);
ValidateType(assetItem, assetPath, context); ValidateType(assetFound, assetPath, context);
if (assetItem.Type == AssetType.Image) if (assetFound.Type == AssetType.Image)
{ {
var w = assetItem.Metadata.GetPixelWidth(); if (assetFound.Metadata.TryGetNumber(KnownMetadataKeys.PixelWidth, out var w) &&
var h = assetItem.Metadata.GetPixelHeight(); assetFound.Metadata.TryGetNumber(KnownMetadataKeys.PixelHeight, out var h))
if (w != null && h != null)
{ {
ValidateDimensions(w.Value, h.Value, assetPath, context); ValidateDimensions((int)w, (int)h, assetPath, context);
} }
} }
else if (assetItem.Type == AssetType.Video) else if (assetFound.Type == AssetType.Video)
{ {
var w = assetItem.Metadata.GetVideoWidth(); if (assetFound.Metadata.TryGetNumber(KnownMetadataKeys.VideoWidth, out var w) &&
var h = assetItem.Metadata.GetVideoHeight(); assetFound.Metadata.TryGetNumber(KnownMetadataKeys.VideoHeight, out var h))
if (w != null && h != null)
{ {
ValidateDimensions(w.Value, h.Value, assetPath, context); ValidateDimensions((int)w, (int)h, assetPath, context);
} }
} }

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

@ -19,7 +19,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Lucene.Net.QueryParser" Version="4.8.0-beta00016" /> <PackageReference Include="Lucene.Net.QueryParser" Version="4.8.0-beta00016" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

9
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetChangedTriggerHandler.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.HandleRules;
using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents;
@ -58,8 +59,8 @@ public sealed class AssetChangedTriggerHandler : IRuleTriggerHandler, ISubscript
SimpleMapper.Map(asset, result); SimpleMapper.Map(asset, result);
result.Actor = asset.LastModifiedBy; result.Actor = asset.LastModifiedBy;
result.PixelHeight = asset.Metadata?.GetPixelHeight(); result.PixelHeight = asset.Metadata?.GetInt32(KnownMetadataKeys.PixelHeight);
result.PixelWidth = asset.Metadata?.GetPixelWidth(); result.PixelWidth = asset.Metadata?.GetInt32(KnownMetadataKeys.PixelWidth);
result.Name = "AssetQueried"; result.Name = "AssetQueried";
yield return result; yield return result;
@ -95,8 +96,8 @@ public sealed class AssetChangedTriggerHandler : IRuleTriggerHandler, ISubscript
{ {
SimpleMapper.Map(asset, result); SimpleMapper.Map(asset, result);
result.PixelHeight = asset.Metadata?.GetPixelHeight(); result.PixelHeight = asset.Metadata?.GetInt32(KnownMetadataKeys.PixelHeight);
result.PixelWidth = asset.Metadata?.GetPixelWidth(); result.PixelWidth = asset.Metadata?.GetInt32(KnownMetadataKeys.PixelWidth);
result.AssetType = asset.Type; result.AssetType = asset.Type;
} }

38
backend/src/Squidex.Domain.Apps.Entities/Assets/FileTagAssetMetadataSource.cs

@ -79,8 +79,8 @@ public sealed class FileTagAssetMetadataSource : IAssetMetadataSource
if (pw > 0 && ph > 0) if (pw > 0 && ph > 0)
{ {
command.Metadata.SetPixelWidth(pw); command.Metadata[KnownMetadataKeys.PixelWidth] = pw;
command.Metadata.SetPixelHeight(ph); command.Metadata[KnownMetadataKeys.PixelHeight] = ph;
} }
void TryAddString(string name, string? value) void TryAddString(string name, string? value)
@ -117,24 +117,24 @@ public sealed class FileTagAssetMetadataSource : IAssetMetadataSource
if (file.Tag is ImageTag imageTag) if (file.Tag is ImageTag imageTag)
{ {
TryAddDouble("latitude", imageTag.Latitude); TryAddDouble(KnownMetadataKeys.Latitude, imageTag.Latitude);
TryAddDouble("longitude", imageTag.Longitude); TryAddDouble(KnownMetadataKeys.Longitude, imageTag.Longitude);
TryAddString("created", imageTag.DateTime?.ToIso8601()); TryAddString(KnownMetadataKeys.Created, imageTag.DateTime?.ToIso8601());
} }
TryAddTimeSpan("duration", file.Properties.Duration); TryAddTimeSpan(KnownMetadataKeys.Duration, file.Properties.Duration);
TryAddInt("bitsPerSample", file.Properties.BitsPerSample); TryAddInt(KnownMetadataKeys.BitsPerSample, file.Properties.BitsPerSample);
TryAddInt("audioBitrate", file.Properties.AudioBitrate); TryAddInt(KnownMetadataKeys.AudioBitrate, file.Properties.AudioBitrate);
TryAddInt("audioChannels", file.Properties.AudioChannels); TryAddInt(KnownMetadataKeys.AudioChannels, file.Properties.AudioChannels);
TryAddInt("audioSampleRate", file.Properties.AudioSampleRate); TryAddInt(KnownMetadataKeys.AudioSampleRate, file.Properties.AudioSampleRate);
TryAddInt("imageQuality", file.Properties.PhotoQuality); TryAddInt(KnownMetadataKeys.ImageQuality, file.Properties.PhotoQuality);
TryAddInt(AssetMetadata.VideoWidth, file.Properties.VideoWidth); TryAddInt(KnownMetadataKeys.VideoWidth, file.Properties.VideoWidth);
TryAddInt(AssetMetadata.VideoHeight, file.Properties.VideoHeight); TryAddInt(KnownMetadataKeys.VideoHeight, file.Properties.VideoHeight);
TryAddString("description", file.Properties.Description); TryAddString(KnownMetadataKeys.Description, file.Properties.Description);
} }
return Task.CompletedTask; return Task.CompletedTask;
@ -149,22 +149,20 @@ public sealed class FileTagAssetMetadataSource : IAssetMetadataSource
{ {
if (asset.Type == AssetType.Video) if (asset.Type == AssetType.Video)
{ {
var w = asset.Metadata.GetVideoWidth(); if (asset.Metadata.TryGetNumber(KnownMetadataKeys.VideoWidth, out var w) &&
var h = asset.Metadata.GetVideoHeight(); asset.Metadata.TryGetNumber(KnownMetadataKeys.VideoHeight, out var h))
if (w != null && h != null)
{ {
yield return $"{w}x{h}pt"; yield return $"{w}x{h}pt";
} }
if (asset.Metadata.TryGetString("duration", out var duration)) if (asset.Metadata.TryGetString(KnownMetadataKeys.Duration, out var duration))
{ {
yield return duration; yield return duration;
} }
} }
else if (asset.Type == AssetType.Audio) else if (asset.Type == AssetType.Audio)
{ {
if (asset.Metadata.TryGetString("duration", out var duration)) if (asset.Metadata.TryGetString(KnownMetadataKeys.Duration, out var duration))
{ {
yield return duration; yield return duration;
} }

20
backend/src/Squidex.Domain.Apps.Entities/Assets/ImageAssetMetadataSource.cs

@ -66,8 +66,8 @@ public sealed class ImageAssetMetadataSource : IAssetMetadataSource
{ {
command.Type = AssetType.Image; command.Type = AssetType.Image;
command.Metadata.SetPixelWidth(imageInfo.PixelWidth); command.Metadata[KnownMetadataKeys.PixelWidth] = imageInfo.PixelWidth;
command.Metadata.SetPixelHeight(imageInfo.PixelHeight); command.Metadata[KnownMetadataKeys.PixelHeight] = imageInfo.PixelHeight;
} }
} }
} }
@ -81,7 +81,7 @@ public sealed class ImageAssetMetadataSource : IAssetMetadataSource
{ {
command.Tags.Add("image"); command.Tags.Add("image");
var wh = command.Metadata.GetPixelWidth() + command.Metadata.GetPixelWidth(); var wh = command.Metadata.GetInt32(KnownMetadataKeys.PixelWidth) + command.Metadata.GetInt32(KnownMetadataKeys.PixelWidth);
if (wh > 2000) if (wh > 2000)
{ {
@ -100,15 +100,15 @@ public sealed class ImageAssetMetadataSource : IAssetMetadataSource
public IEnumerable<string> Format(Asset asset) public IEnumerable<string> Format(Asset asset)
{ {
if (asset.Type == AssetType.Image) if (asset.Type != AssetType.Image)
{ {
var w = asset.Metadata.GetPixelWidth(); yield break;
var h = asset.Metadata.GetPixelHeight(); }
if (w != null && h != null) if (asset.Metadata.TryGetNumber(KnownMetadataKeys.PixelWidth, out var w) &&
{ asset.Metadata.TryGetNumber(KnownMetadataKeys.PixelHeight, out var h))
yield return $"{w}x{h}px"; {
} yield return $"{w}x{h}px";
} }
} }
} }

66
backend/src/Squidex.Domain.Apps.Entities/Assets/SvgAssetMetadataSource.cs

@ -24,38 +24,68 @@ public sealed class SvgAssetMetadataSource : IAssetMetadataSource
command.File.MimeType == "image/svg+xml" || command.File.MimeType == "image/svg+xml" ||
command.File.FileName.EndsWith(".svg", StringComparison.OrdinalIgnoreCase); command.File.FileName.EndsWith(".svg", StringComparison.OrdinalIgnoreCase);
if (isSvg) if (!isSvg)
{ {
command.Tags.Add("image"); return;
}
command.Tags.Add("image");
if (command.File.FileSize >= FileSizeLimit)
{
return;
}
if (command.File.FileSize < FileSizeLimit) try
{
using (var reader = new StreamReader(command.File.OpenRead()))
{ {
try var text = await reader.ReadToEndAsync(ct);
if (!text.IsValidSvg())
{ {
using (var reader = new StreamReader(command.File.OpenRead())) throw new ValidationException(T.Get("validation.notAnValidSvg"));
{
var text = await reader.ReadToEndAsync();
if (!text.IsValidSvg())
{
throw new ValidationException(T.Get("validation.notAnValidSvg"));
}
}
} }
catch (ValidationException)
var (width, height, viewBox) = text.GetSvgMetadata();
if (!string.IsNullOrWhiteSpace(width) && !string.IsNullOrWhiteSpace(height))
{ {
throw; command.Metadata[KnownMetadataKeys.PixelWidth] = width;
command.Metadata[KnownMetadataKeys.PixelHeight] = height;
} }
catch
if (!string.IsNullOrWhiteSpace(viewBox))
{ {
return; command.Metadata[KnownMetadataKeys.ViewBox] = viewBox;
} }
} }
} }
catch (ValidationException)
{
throw;
}
catch
{
return;
}
} }
public IEnumerable<string> Format(Asset asset) public IEnumerable<string> Format(Asset asset)
{ {
yield break; var isSvg =
asset.MimeType == "image/svg+xml" ||
asset.FileName.EndsWith(".svg", StringComparison.OrdinalIgnoreCase);
if (!isSvg)
{
yield break;
}
if (asset.Metadata.TryGetString(KnownMetadataKeys.PixelWidth, out var w) &&
asset.Metadata.TryGetString(KnownMetadataKeys.PixelHeight, out var h))
{
yield return $"{w}x{h}";
}
} }
} }

4
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/AssetGraphType.cs

@ -188,7 +188,7 @@ internal sealed class AssetGraphType : SharedObjectGraphType<EnrichedAsset>
{ {
Name = "pixelWidth", Name = "pixelWidth",
ResolvedType = Scalars.Int, ResolvedType = Scalars.Int,
Resolver = Resolve(x => x.Metadata.GetPixelWidth()), Resolver = Resolve(x => x.Metadata.GetInt32(KnownMetadataKeys.PixelWidth)),
Description = FieldDescriptions.AssetPixelWidth, Description = FieldDescriptions.AssetPixelWidth,
DeprecationReason = "Use 'metadata' field instead." DeprecationReason = "Use 'metadata' field instead."
}); });
@ -197,7 +197,7 @@ internal sealed class AssetGraphType : SharedObjectGraphType<EnrichedAsset>
{ {
Name = "pixelHeight", Name = "pixelHeight",
ResolvedType = Scalars.Int, ResolvedType = Scalars.Int,
Resolver = Resolve(x => x.Metadata.GetPixelHeight()), Resolver = Resolve(x => x.Metadata.GetInt32(KnownMetadataKeys.PixelHeight)),
Description = FieldDescriptions.AssetPixelHeight, Description = FieldDescriptions.AssetPixelHeight,
DeprecationReason = "Use 'metadata' field instead." DeprecationReason = "Use 'metadata' field instead."
}); });

4
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Assets/EnrichedAssetEventGraphType.cs

@ -195,7 +195,7 @@ internal sealed class EnrichedAssetEventGraphType : SharedObjectGraphType<Enrich
{ {
Name = "pixelWidth", Name = "pixelWidth",
ResolvedType = Scalars.Int, ResolvedType = Scalars.Int,
Resolver = Resolve(x => x.Metadata.GetPixelWidth()), Resolver = Resolve(x => x.Metadata.GetInt32(KnownMetadataKeys.PixelWidth)),
Description = FieldDescriptions.AssetPixelWidth, Description = FieldDescriptions.AssetPixelWidth,
DeprecationReason = "Use 'metadata' field instead." DeprecationReason = "Use 'metadata' field instead."
}); });
@ -204,7 +204,7 @@ internal sealed class EnrichedAssetEventGraphType : SharedObjectGraphType<Enrich
{ {
Name = "pixelHeight", Name = "pixelHeight",
ResolvedType = Scalars.Int, ResolvedType = Scalars.Int,
Resolver = Resolve(x => x.Metadata.GetPixelHeight()), Resolver = Resolve(x => x.Metadata.GetInt32(KnownMetadataKeys.PixelHeight)),
Description = FieldDescriptions.AssetPixelHeight, Description = FieldDescriptions.AssetPixelHeight,
DeprecationReason = "Use 'metadata' field instead." DeprecationReason = "Use 'metadata' field instead."
}); });

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

@ -24,10 +24,10 @@
<ProjectReference Include="..\Squidex.Shared\Squidex.Shared.csproj" /> <ProjectReference Include="..\Squidex.Shared\Squidex.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CsvHelper" Version="30.0.3" /> <PackageReference Include="CsvHelper" Version="30.1.0" />
<PackageReference Include="GraphQL" Version="7.7.2" /> <PackageReference Include="GraphQL" Version="7.7.2" />
<PackageReference Include="GraphQL.DataLoader" Version="7.7.2" /> <PackageReference Include="GraphQL.DataLoader" Version="7.7.2" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

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

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

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

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

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

@ -18,7 +18,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="IdentityModel" Version="6.2.0" /> <PackageReference Include="IdentityModel" Version="6.2.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

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

@ -15,7 +15,7 @@
<PackageReference Include="EventStore.Client.Grpc.ProjectionManagement" 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="EventStore.Client.Grpc.Streams" Version="23.1.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.60.0" /> <PackageReference Include="Grpc.Net.Client" Version="2.60.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

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

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

14
backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj

@ -13,7 +13,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="MailKit" Version="4.3.0" /> <PackageReference Include="MailKit" Version="4.3.0" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" /> <PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
@ -24,12 +24,12 @@
<PackageReference Include="NodaTime" Version="3.1.10" /> <PackageReference Include="NodaTime" Version="3.1.10" />
<PackageReference Include="OpenTelemetry.Api" Version="1.7.0" /> <PackageReference Include="OpenTelemetry.Api" Version="1.7.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets" Version="6.3.6" /> <PackageReference Include="Squidex.Assets" Version="6.3.7" />
<PackageReference Include="Squidex.Caching" Version="6.3.6" /> <PackageReference Include="Squidex.Caching" Version="6.3.7" />
<PackageReference Include="Squidex.Hosting.Abstractions" Version="6.3.6" /> <PackageReference Include="Squidex.Hosting.Abstractions" Version="6.3.7" />
<PackageReference Include="Squidex.Log" Version="6.3.6" /> <PackageReference Include="Squidex.Log" Version="6.3.7" />
<PackageReference Include="Squidex.Messaging" Version="6.3.6" /> <PackageReference Include="Squidex.Messaging" Version="6.3.7" />
<PackageReference Include="Squidex.Text" Version="6.3.6" /> <PackageReference Include="Squidex.Text" Version="6.3.7" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="8.0.0" /> <PackageReference Include="System.Collections.Immutable" Version="8.0.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.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> <DebugSymbols>True</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

2
backend/src/Squidex.Web/Squidex.Web.csproj

@ -16,7 +16,7 @@
<PackageReference Include="GraphQL" Version="7.7.2" /> <PackageReference Include="GraphQL" Version="7.7.2" />
<PackageReference Include="GraphQL.SystemTextJson" Version="7.7.2" /> <PackageReference Include="GraphQL.SystemTextJson" Version="7.7.2" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="7.6.0" /> <PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="7.6.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

4
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetContentQueryDto.cs

@ -176,8 +176,8 @@ public sealed class AssetContentQueryDto
return (FocusX.Value, FocusY.Value); return (FocusX.Value, FocusY.Value);
} }
var focusX = asset.Metadata.GetFocusX(); var focusX = asset.Metadata.GetSingle(KnownMetadataKeys.FocusX);
var focusY = asset.Metadata.GetFocusY(); var focusY = asset.Metadata.GetSingle(KnownMetadataKeys.FocusY);
if (focusX != null && focusY != null) if (focusX != null && focusY != null)
{ {

4
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs

@ -138,7 +138,7 @@ public sealed class AssetDto : Resource
[Obsolete("Use 'metadata' field now.")] [Obsolete("Use 'metadata' field now.")]
public int? PixelWidth public int? PixelWidth
{ {
get => Metadata.GetPixelWidth(); get => Metadata.GetInt32(KnownMetadataKeys.PixelWidth);
} }
/// <summary> /// <summary>
@ -147,7 +147,7 @@ public sealed class AssetDto : Resource
[Obsolete("Use 'metadata' field now.")] [Obsolete("Use 'metadata' field now.")]
public int? PixelHeight public int? PixelHeight
{ {
get => Metadata.GetPixelHeight(); get => Metadata.GetInt32(KnownMetadataKeys.PixelHeight);
} }
public static AssetDto FromDomain(EnrichedAsset asset, Resources resources, bool isDuplicate = false) public static AssetDto FromDomain(EnrichedAsset asset, Resources resources, bool isDuplicate = false)

26
backend/src/Squidex/Squidex.csproj

@ -37,7 +37,7 @@
<PackageReference Include="GraphQL" Version="7.7.2" /> <PackageReference Include="GraphQL" Version="7.7.2" />
<PackageReference Include="GraphQL.MicrosoftDI" Version="7.7.2" /> <PackageReference Include="GraphQL.MicrosoftDI" Version="7.7.2" />
<PackageReference Include="GraphQL.SystemTextJson" Version="7.7.2" /> <PackageReference Include="GraphQL.SystemTextJson" Version="7.7.2" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
@ -63,18 +63,18 @@
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.0" /> <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="ReportGenerator" Version="5.2.0" PrivateAssets="all" /> <PackageReference Include="ReportGenerator" Version="5.2.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets.Azure" Version="6.3.6" /> <PackageReference Include="Squidex.Assets.Azure" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.GoogleCloud" Version="6.3.6" /> <PackageReference Include="Squidex.Assets.GoogleCloud" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.FTP" Version="6.3.6" /> <PackageReference Include="Squidex.Assets.FTP" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.ImageMagick" Version="6.3.6" /> <PackageReference Include="Squidex.Assets.ImageMagick" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.ImageSharp" Version="6.3.6" /> <PackageReference Include="Squidex.Assets.ImageSharp" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.Mongo" Version="6.3.6" /> <PackageReference Include="Squidex.Assets.Mongo" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.S3" Version="6.3.6" /> <PackageReference Include="Squidex.Assets.S3" Version="6.3.7" />
<PackageReference Include="Squidex.Assets.TusAdapter" Version="6.3.6" /> <PackageReference Include="Squidex.Assets.TusAdapter" Version="6.3.7" />
<PackageReference Include="Squidex.ClientLibrary" Version="19.0.0" /> <PackageReference Include="Squidex.ClientLibrary" Version="19.1.0" />
<PackageReference Include="Squidex.Hosting" Version="6.3.6" /> <PackageReference Include="Squidex.Hosting" Version="6.3.7" />
<PackageReference Include="Squidex.Messaging.All" Version="6.3.6" /> <PackageReference Include="Squidex.Messaging.All" Version="6.3.7" />
<PackageReference Include="Squidex.Messaging.Subscriptions" Version="6.3.6" /> <PackageReference Include="Squidex.Messaging.Subscriptions" Version="6.3.7" />
<PackageReference Include="Squidex.OpenIddict.MongoDb" Version="5.1.0" /> <PackageReference Include="Squidex.OpenIddict.MongoDb" Version="5.1.0" />
<PackageReference Include="Squidex.YDotNet" Version="0.2.9" /> <PackageReference Include="Squidex.YDotNet" Version="0.2.9" />
<PackageReference Include="Squidex.YDotNet.Native" Version="0.2.9" /> <PackageReference Include="Squidex.YDotNet.Native" Version="0.2.9" />

2
backend/src/Squidex/wwwroot/editor/squidex-editor.js

@ -6234,7 +6234,7 @@ ${u}
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y; background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y;
} }
`}),ace.define("ace/theme/github",["require","exports","module","ace/theme/github-css","ace/lib/dom"],function(n,r,o){r.isDark=!1,r.cssClass="ace-github",r.cssText=n("./github-css");var i=n("../lib/dom");i.importCssString(r.cssText,r.cssClass,!1)}),function(){ace.require(["ace/theme/github"],function(n){t&&(t.exports=n)})}()})(pge);const gge=({mode:t,value:e})=>{const n=D.useMemo(()=>{if(!PE(e))return{mode:"markdown",value:null};switch(t){case"Markdown":return{mode:"markdown",value:e};case"Html":return{mode:"html",value:mge(e||"")};default:return{mode:"markdown",value:null}}},[t,e]);return(n==null?void 0:n.value)==null?null:V.jsx(dge,{mode:n.mode,value:n.value,height:"100%",width:"100%",readOnly:!0,wrapEnabled:!0})},Z_=" ";function mge(t){let e="",n="";return t.split(/>\s*</).forEach(r=>{r.match(/^\/\w/)&&(n=n.substring(Z_.length)),e+=n+"<"+r+`>\r `}),ace.define("ace/theme/github",["require","exports","module","ace/theme/github-css","ace/lib/dom"],function(n,r,o){r.isDark=!1,r.cssClass="ace-github",r.cssText=n("./github-css");var i=n("../lib/dom");i.importCssString(r.cssText,r.cssClass,!1)}),function(){ace.require(["ace/theme/github"],function(n){t&&(t.exports=n)})}()})(pge);const gge=({mode:t,value:e})=>{const n=D.useMemo(()=>{if(!PE(e))return{mode:"markdown",value:null};switch(t){case"Markdown":return{mode:"markdown",value:e};case"Html":return{mode:"html",value:mge(e||"")};default:return{mode:"markdown",value:null}}},[t,e]);return(n==null?void 0:n.value)==null?null:V.jsx(dge,{mode:n.mode,value:n.value,height:"100%",width:"100%",readOnly:!0,wrapEnabled:!0})},Z_=" ";function mge(t){let e="",n="";return t.split(/>\s*</).forEach(r=>{r.match(/^\/\w/)&&(n=n.substring(Z_.length)),e+=n+"<"+r+`>\r
`,r.match(/^<?\w[^>]*[^/]$/)&&!r.startsWith("input")&&(n+=Z_)}),e.substring(1,e.length-3)}const vge=t=>{const{onClose:e,node:n}=t,[r,o,i]=d$(""),s=hn();D.useEffect(()=>{o(n.node.attrs.title||"")},[n,o]);const l=D.useCallback(c=>{o(c.target.value)},[o]),a=D.useCallback(()=>{s.updateNodeAttributes(n.getPos()||0,{...n.node.attrs||{},title:i.current}),e()},[s,n,e,i]),u=D.useCallback(c=>{const{code:d}=c;d==="Enter"&&a(),d==="Escape"&&e()},[e,a]);return V.jsxs(k$,{title:"Change Image Title",children:[V.jsx(x$,{value:r,onChange:l,onKeyDown:u,placeholder:"Enter Title..."}),V.jsxs(Br,{children:[V.jsx(Rt,{commandName:"submitLink",enabled:!0,onSelect:a,icon:V.jsx(eo,{type:"Check"})}),V.jsx(Rt,{commandName:"cancelLink",enabled:!0,onSelect:e,icon:V.jsx(eo,{type:"Cancel"})})]})]})};const yge=t=>{const{annotations:e,appName:n,canAddAnnotation:r,canSelectAIText:o,canSelectAssets:i,canSelectContents:s,classNames:l,isDisabled:a,mode:u,onAnnotationCreate:c,onAnnotationsFocus:d,onAnnotationsUpdate:h,onChange:f,onEditAsset:p,onEditContent:g,onSelectAIText:m,onSelectAssets:v,onSelectContents:y,onUpload:b,value:w}=t,k=D.useMemo(()=>{let L=t.baseUrl;return L.endsWith("/")&&(L=L.substring(0,L.length-1)),L},[t.baseUrl]),[x,S]=D.useState(),[T,C]=D.useState(!1),[I,_]=D.useState(!1),R=D.useCallback(()=>{C(!0)},[]),A=D.useCallback(()=>{C(!1)},[]),E=D.useCallback(()=>{S(null)},[]),M=D.useCallback(()=>{_(L=>!L)},[]),O=D.useCallback(()=>[new Nn,new yk,new pl({}),new _h({enableSpine:!0}),new su({classNames:l}),new bo({supportedLanguages:rfe}),new Mh,new Ph({appName:n,baseUrl:k,onEditContent:g}),new Ys({}),new Kg,new Yg({}),new Xg,new Afe({copyAsHtml:u==="Html"}),new Oh({uploadHandler:b}),new Ih,new gl({autoLink:!0}),new fl({enableCollapsible:!0}),new iu({copyAsMarkdown:u==="Markdown",htmlToMarkdown:wfe,markdownToHtml:xfe}),new Rh,new rm,new Nh,new ob,new $h],[n,k,l,u,g,b]),{manager:N}=MQ({stringHandler:u==="Markdown"?"markdown":"html",content:w,nodeViewComponents:{image:L=>V.jsx(Tfe,{...L,appName:n,baseUrl:k,onEditNode:S,onEditAsset:p})},extensions:O});return V.jsx(jue,{children:V.jsx(Fue,{theme:{color:{primary:"#3389ff",active:{primary:"#3389ff"}}},children:V.jsxs(LQ,{classNames:a?["squidex-editor-disabled"]:[],manager:N,children:[V.jsx("div",{className:"squidex-editor-menu",children:V.jsxs(FN,{children:[V.jsxs("fieldset",{disabled:I,className:"MuiStack-root",children:[V.jsx(Due,{}),V.jsx($ue,{showAll:!0}),V.jsxs(Br,{children:[V.jsx(Yx,{}),V.jsx(qx,{}),V.jsx(Zx,{}),V.jsx(Xx,{})]}),V.jsxs(Br,{children:[V.jsx(kue,{}),V.jsx(Sue,{}),V.jsx(wue,{})]}),V.jsxs(Br,{children:[V.jsx(Eue,{}),V.jsx(Cue,{})]}),u!=="Markdown"&&l&&l.length>0&&V.jsx(Br,{children:V.jsx(jfe,{})}),V.jsx(Br,{children:V.jsx(E$,{onEdit:R})}),V.jsxs(Br,{children:[i&&v&&V.jsx(zfe,{onSelectAssets:v}),s&&y&&V.jsx(Ffe,{onSelectContents:y}),o&&m&&V.jsx(Dfe,{onSelectAIText:m})]}),r&&c&&V.jsx(Br,{children:V.jsx(Hfe,{onAnnotationCreate:c})}),u==="Html"&&V.jsx(Br,{children:V.jsx(Bfe,{})})]}),V.jsx(Rt,{commandName:"toggleMarkup",enabled:!0,onSelect:M,label:"Show Markup (readonly)",icon:V.jsx(eo,{type:"Preview"})})]})}),V.jsxs("div",{className:"squidex-editor-main",children:[V.jsx(_fe,{mode:u,onChange:f,value:w}),V.jsx(Wy,{}),I&&V.jsx(gge,{value:w,mode:u}),T?V.jsx(Kfe,{onClose:A}):x?V.jsx(vge,{node:x,onClose:E}):V.jsx(bge,{onLinkModal:R}),V.jsx(Uue,{offset:{x:5,y:5},className:Bc(V0.LANGUAGE_SELECT_POSITIONER,V0.LANGUAGE_SELECT_WIDTH)}),V.jsx(Ufe,{annotations:e,onAnnotationsFocus:d,onAnnotationsUpdate:h})]}),V.jsx(Gfe,{})]})})})},bge=({onLinkModal:t})=>pr().codeBlock()?null:V.jsxs(Hue,{className:"squidex-editor-floating",children:[V.jsx(Yx,{}),V.jsx(qx,{}),V.jsx(Zx,{}),V.jsx(Xx,{}),V.jsx(E$,{onEdit:t})]});var D$,Q_=of;D$=Q_.createRoot,Q_.hydrateRoot;class wge{constructor(e,n){dt(this,"root");this.element=e,this.props=n,this.root=D$(this.element),this.render()}update(e){this.props={...this.props,...e},this.render()}setValue(e){this.update({value:e})}setAnnotations(e){this.update({annotations:e})}setIsDisabled(e){this.update({isDisabled:e})}destroy(){this.root.unmount()}render(){this.root.render(V.jsx(yge,{...this.props}))}}/* `,r.match(/^<?\w[^>]*[^/]$/)&&!r.startsWith("input")&&(n+=Z_)}),e.substring(1,e.length-3)}const vge=t=>{const{onClose:e,node:n}=t,[r,o,i]=d$(""),s=hn();D.useEffect(()=>{o(n.node.attrs.title||"")},[n,o]);const l=D.useCallback(c=>{o(c.target.value)},[o]),a=D.useCallback(()=>{s.updateNodeAttributes(n.getPos()||0,{...n.node.attrs||{},title:i.current}),e()},[s,n,e,i]),u=D.useCallback(c=>{const{code:d}=c;d==="Enter"&&a(),d==="Escape"&&e()},[e,a]);return V.jsxs(k$,{title:"Change Image Title",children:[V.jsx(x$,{value:r,onChange:l,onKeyDown:u,placeholder:"Enter Title..."}),V.jsxs(Br,{children:[V.jsx(Rt,{commandName:"submitLink",enabled:!0,onSelect:a,icon:V.jsx(eo,{type:"Check"})}),V.jsx(Rt,{commandName:"cancelLink",enabled:!0,onSelect:e,icon:V.jsx(eo,{type:"Cancel"})})]})]})};const yge=t=>{const{annotations:e,appName:n,canAddAnnotation:r,canSelectAIText:o,canSelectAssets:i,canSelectContents:s,classNames:l,isDisabled:a,mode:u,onAnnotationCreate:c,onAnnotationsFocus:d,onAnnotationsUpdate:h,onChange:f,onEditAsset:p,onEditContent:g,onSelectAIText:m,onSelectAssets:v,onSelectContents:y,onUpload:b,value:w}=t,k=D.useMemo(()=>{let L=t.baseUrl;return L.endsWith("/")&&(L=L.substring(0,L.length-1)),L},[t.baseUrl]),[x,S]=D.useState(),[T,C]=D.useState(!1),[I,_]=D.useState(!1),R=D.useCallback(()=>{C(!0)},[]),A=D.useCallback(()=>{C(!1)},[]),E=D.useCallback(()=>{S(null)},[]),M=D.useCallback(()=>{_(L=>!L)},[]),O=D.useCallback(()=>[new Nn,new yk,new pl({}),new _h({enableSpine:!0}),new su({classNames:l}),new bo({supportedLanguages:rfe}),new Mh,new Ph({appName:n,baseUrl:k,onEditContent:g}),new Ys({}),new Kg,new Yg({}),new Xg,new Afe({copyAsHtml:u==="Html"}),new Oh({uploadHandler:b}),new Ih,new gl({autoLink:!0}),new fl({enableCollapsible:!0}),new iu({copyAsMarkdown:u==="Markdown",htmlToMarkdown:wfe,markdownToHtml:xfe}),new Rh,new rm,new Nh,new ob,new $h],[n,k,l,u,g,b]),{manager:N}=MQ({stringHandler:u==="Markdown"?"markdown":"html",content:w,nodeViewComponents:{image:L=>V.jsx(Tfe,{...L,appName:n,baseUrl:k,onEditNode:S,onEditAsset:p})},extensions:O});return V.jsx(jue,{children:V.jsx(Fue,{theme:{color:{primary:"#3389ff",active:{primary:"#3389ff"}}},children:V.jsxs(LQ,{classNames:a?["squidex-editor-disabled"]:[],manager:N,children:[V.jsx("div",{className:"squidex-editor-menu",children:V.jsxs(FN,{children:[V.jsxs("fieldset",{disabled:I||a,className:"MuiStack-root",children:[V.jsx(Due,{}),V.jsx($ue,{showAll:!0}),V.jsxs(Br,{children:[V.jsx(Yx,{}),V.jsx(qx,{}),V.jsx(Zx,{}),V.jsx(Xx,{})]}),V.jsxs(Br,{children:[V.jsx(kue,{}),V.jsx(Sue,{}),V.jsx(wue,{})]}),V.jsxs(Br,{children:[V.jsx(Eue,{}),V.jsx(Cue,{})]}),u!=="Markdown"&&l&&l.length>0&&V.jsx(Br,{children:V.jsx(jfe,{})}),V.jsx(Br,{children:V.jsx(E$,{onEdit:R})}),V.jsxs(Br,{children:[i&&v&&V.jsx(zfe,{onSelectAssets:v}),s&&y&&V.jsx(Ffe,{onSelectContents:y}),o&&m&&V.jsx(Dfe,{onSelectAIText:m})]}),r&&c&&V.jsx(Br,{children:V.jsx(Hfe,{onAnnotationCreate:c})}),u==="Html"&&V.jsx(Br,{children:V.jsx(Bfe,{})})]}),V.jsx(Rt,{commandName:"toggleMarkup",enabled:!0,onSelect:M,label:"Show Markup (readonly)",icon:V.jsx(eo,{type:"Preview"})})]})}),V.jsxs("div",{className:"squidex-editor-main",children:[V.jsx(_fe,{mode:u,onChange:f,value:w}),V.jsx(Wy,{}),I&&V.jsx(gge,{value:w,mode:u}),T?V.jsx(Kfe,{onClose:A}):x?V.jsx(vge,{node:x,onClose:E}):V.jsx(bge,{onLinkModal:R}),V.jsx(Uue,{offset:{x:5,y:5},className:Bc(V0.LANGUAGE_SELECT_POSITIONER,V0.LANGUAGE_SELECT_WIDTH)}),V.jsx(Ufe,{annotations:e,onAnnotationsFocus:d,onAnnotationsUpdate:h})]}),V.jsx(Gfe,{})]})})})},bge=({onLinkModal:t})=>pr().codeBlock()?null:V.jsxs(Hue,{className:"squidex-editor-floating",children:[V.jsx(Yx,{}),V.jsx(qx,{}),V.jsx(Zx,{}),V.jsx(Xx,{}),V.jsx(E$,{onEdit:t})]});var D$,Q_=of;D$=Q_.createRoot,Q_.hydrateRoot;class wge{constructor(e,n){dt(this,"root");this.element=e,this.props=n,this.root=D$(this.element),this.render()}update(e){this.props={...this.props,...e},this.render()}setValue(e){this.update({value:e})}setAnnotations(e){this.update({annotations:e})}setIsDisabled(e){this.update({isDisabled:e})}destroy(){this.root.unmount()}render(){this.root.render(V.jsx(yge,{...this.props}))}}/*
* Squidex Headless CMS * Squidex Headless CMS
* *
* @license * @license

36
backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetMetadataTests.cs

@ -16,12 +16,14 @@ public class AssetMetadataTests
public void Should_return_focus_infos_if_found() public void Should_return_focus_infos_if_found()
{ {
var sut = var sut =
new AssetMetadata() new AssetMetadata
.SetFocusX(.5f) {
.SetFocusY(.2f); [KnownMetadataKeys.FocusX] = .5f,
[KnownMetadataKeys.FocusY] = .2f,
Assert.Equal(.5f, sut.GetFocusX()); };
Assert.Equal(.2f, sut.GetFocusY());
Assert.Equal(.5f, sut.GetSingle(KnownMetadataKeys.FocusX));
Assert.Equal(.2f, sut.GetSingle(KnownMetadataKeys.FocusY));
} }
[Fact] [Fact]
@ -29,20 +31,22 @@ public class AssetMetadataTests
{ {
var sut = new AssetMetadata(); var sut = new AssetMetadata();
Assert.Null(sut.GetFocusX()); Assert.Null(sut.GetSingle(KnownMetadataKeys.FocusX));
Assert.Null(sut.GetFocusY()); Assert.Null(sut.GetSingle(KnownMetadataKeys.FocusY));
} }
[Fact] [Fact]
public void Should_return_pixel_infos_if_found() public void Should_return_pixel_infos_if_found()
{ {
var sut = var sut =
new AssetMetadata() new AssetMetadata
.SetPixelWidth(800) {
.SetPixelHeight(600); [KnownMetadataKeys.PixelWidth] = 800,
[KnownMetadataKeys.PixelHeight] = 600,
Assert.Equal(800, sut.GetPixelWidth()); };
Assert.Equal(600, sut.GetPixelHeight());
Assert.Equal(800, sut.GetInt32(KnownMetadataKeys.PixelWidth));
Assert.Equal(600, sut.GetInt32(KnownMetadataKeys.PixelHeight));
} }
[Fact] [Fact]
@ -50,8 +54,8 @@ public class AssetMetadataTests
{ {
var sut = new AssetMetadata(); var sut = new AssetMetadata();
Assert.Null(sut.GetPixelWidth()); Assert.Null(sut.GetInt32(KnownMetadataKeys.PixelWidth));
Assert.Null(sut.GetPixelHeight()); Assert.Null(sut.GetInt32(KnownMetadataKeys.PixelHeight));
} }
[Fact] [Fact]

4
backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Assets/AssetTests.cs

@ -131,8 +131,8 @@ public class AssetTests
[Fact] [Fact]
public void Should_annotate_with_metadata() public void Should_annotate_with_metadata()
{ {
var newMetadata1 = new AssetMetadata().SetPixelWidth(1024); var newMetadata1 = new AssetMetadata { [KnownMetadataKeys.PixelWidth] = 1024 };
var newMetadata2 = new AssetMetadata().SetPixelWidth(1024); var newMetadata2 = new AssetMetadata { [KnownMetadataKeys.PixelWidth] = 1024 };
var asset_1 = asset_0.Annotate(metadata: newMetadata1); var asset_1 = asset_0.Annotate(metadata: newMetadata1);
var asset_2 = asset_1.Annotate(metadata: newMetadata2); var asset_2 = asset_1.Annotate(metadata: newMetadata2);

18
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs

@ -9,6 +9,7 @@ using System.Net;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Core.Scripting.Extensions; using Squidex.Domain.Apps.Core.Scripting.Extensions;
@ -680,4 +681,21 @@ public class JintScriptEngineTests : IClassFixture<TranslationsFixture>
Assert.Equal(113.0, vars["shared"]); Assert.Equal(113.0, vars["shared"]);
} }
[Fact]
public async Task Should_set_metadata()
{
var vars = new DataScriptVars
{
["metadata"] = new AssetMetadata()
};
var script = @$"
ctx.metadata['pixelWidth'] = 100;
";
await sut.ExecuteAsync(vars, script, new ScriptOptions { AsContext = true });
Assert.Equal(100, ((AssetMetadata)vars["metadata"]!).GetInt32(KnownMetadataKeys.PixelWidth));
}
} }

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

@ -16,7 +16,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FakeItEasy" Version="8.1.0" /> <PackageReference Include="FakeItEasy" Version="8.1.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" /> <PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

18
backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestAssets.cs

@ -31,10 +31,11 @@ public static class TestAssets
FileName = "MyImage.png", FileName = "MyImage.png",
FileSize = 1024 * 8, FileSize = 1024 * 8,
Type = AssetType.Image, Type = AssetType.Image,
Metadata = Metadata = new AssetMetadata
new AssetMetadata() {
.SetPixelWidth(800) [KnownMetadataKeys.PixelWidth] = 800,
.SetPixelHeight(600) [KnownMetadataKeys.PixelHeight] = 600,
}
}; };
} }
@ -46,10 +47,11 @@ public static class TestAssets
FileName = "MyImage.png", FileName = "MyImage.png",
FileSize = 1024 * 8, FileSize = 1024 * 8,
Type = AssetType.Video, Type = AssetType.Video,
Metadata = Metadata = new AssetMetadata
new AssetMetadata() {
.SetVideoWidth(800) [KnownMetadataKeys.VideoWidth] = 800,
.SetVideoHeight(600) [KnownMetadataKeys.VideoHeight] = 600,
}
}; };
} }

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs

@ -354,8 +354,8 @@ public class AssetsJintExtensionTests : GivenContext, IClassFixture<Translations
FileSize = 100, FileSize = 100,
Metadata = new AssetMetadata Metadata = new AssetMetadata
{ {
[AssetMetadata.PixelWidth] = 100, [KnownMetadataKeys.PixelWidth] = 100,
[AssetMetadata.PixelHeight] = 50, [KnownMetadataKeys.PixelHeight] = 50,
}, },
AppId = AppId AppId = AppId
}; };

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetDomainObjectTests.cs

@ -208,7 +208,7 @@ public class AssetDomainObjectTests : HandlerTestBase<Asset>
[Fact] [Fact]
public async Task AnnotateMetadata_should_create_events_and_update_metadata() public async Task AnnotateMetadata_should_create_events_and_update_metadata()
{ {
var command = new AnnotateAsset { Metadata = new AssetMetadata().SetPixelWidth(800) }; var command = new AnnotateAsset { Metadata = new AssetMetadata { [KnownMetadataKeys.PixelWidth] = 800 } };
await ExecuteCreateAsync(); await ExecuteCreateAsync();

36
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/FileTagAssetMetadataSourceTests.cs

@ -36,8 +36,8 @@ public class FileTagAssetMetadataSourceTests : GivenContext
Assert.Equal(AssetType.Image, command.Type); Assert.Equal(AssetType.Image, command.Type);
Assert.Equal(272, command.Metadata.GetPixelWidth()); Assert.Equal(272, command.Metadata.GetInt32(KnownMetadataKeys.PixelWidth));
Assert.Equal(170, command.Metadata.GetPixelHeight()); Assert.Equal(170, command.Metadata.GetInt32(KnownMetadataKeys.PixelHeight));
} }
[Fact] [Fact]
@ -47,8 +47,8 @@ public class FileTagAssetMetadataSourceTests : GivenContext
await sut.EnhanceAsync(command, default); await sut.EnhanceAsync(command, default);
Assert.Null(command.Metadata.GetPixelWidth()); Assert.Null(command.Metadata.GetInt32(KnownMetadataKeys.PixelWidth));
Assert.Null(command.Metadata.GetPixelHeight()); Assert.Null(command.Metadata.GetInt32(KnownMetadataKeys.PixelHeight));
} }
[Fact] [Fact]
@ -60,10 +60,10 @@ public class FileTagAssetMetadataSourceTests : GivenContext
Assert.Equal(AssetType.Audio, command.Type); Assert.Equal(AssetType.Audio, command.Type);
Assert.Equal(JsonValue.Create("00:00:28.2708750"), command.Metadata["duration"]); Assert.Equal(JsonValue.Create("00:00:28.2708750"), command.Metadata[KnownMetadataKeys.Duration]);
Assert.Equal(JsonValue.Create(128L), command.Metadata["audioBitrate"]); Assert.Equal(JsonValue.Create(2L), command.Metadata[KnownMetadataKeys.AudioChannels]);
Assert.Equal(JsonValue.Create(2L), command.Metadata["audioChannels"]); Assert.Equal(JsonValue.Create(128L), command.Metadata[KnownMetadataKeys.AudioBitrate]);
Assert.Equal(JsonValue.Create(44100L), command.Metadata["audioSampleRate"]); Assert.Equal(JsonValue.Create(44100L), command.Metadata[KnownMetadataKeys.AudioSampleRate]);
} }
[Fact] [Fact]
@ -75,12 +75,12 @@ public class FileTagAssetMetadataSourceTests : GivenContext
Assert.Equal(AssetType.Video, command.Type); Assert.Equal(AssetType.Video, command.Type);
Assert.Equal(JsonValue.Create("00:00:05.3120000"), command.Metadata["duration"]); Assert.Equal(JsonValue.Create("00:00:05.3120000"), command.Metadata[KnownMetadataKeys.Duration]);
Assert.Equal(JsonValue.Create(384L), command.Metadata["audioBitrate"]); Assert.Equal(JsonValue.Create(2L), command.Metadata[KnownMetadataKeys.AudioChannels]);
Assert.Equal(JsonValue.Create(2L), command.Metadata["audioChannels"]); Assert.Equal(JsonValue.Create(384L), command.Metadata[KnownMetadataKeys.AudioBitrate]);
Assert.Equal(JsonValue.Create(48000L), command.Metadata["audioSampleRate"]); Assert.Equal(JsonValue.Create(48000L), command.Metadata[KnownMetadataKeys.AudioSampleRate]);
Assert.Equal(JsonValue.Create(1280L), command.Metadata["videoWidth"]); Assert.Equal(JsonValue.Create(720L), command.Metadata[KnownMetadataKeys.VideoHeight]);
Assert.Equal(JsonValue.Create(720L), command.Metadata["videoHeight"]); Assert.Equal(JsonValue.Create(1280L), command.Metadata[KnownMetadataKeys.VideoWidth]);
} }
[Fact] [Fact]
@ -90,9 +90,9 @@ public class FileTagAssetMetadataSourceTests : GivenContext
{ {
Metadata = new AssetMetadata Metadata = new AssetMetadata
{ {
["videoWidth"] = JsonValue.Create(128), [KnownMetadataKeys.VideoWidth] = JsonValue.Create(128),
["videoHeight"] = JsonValue.Create(55), [KnownMetadataKeys.VideoHeight] = JsonValue.Create(55),
["duration"] = JsonValue.Create("00:10:12") [KnownMetadataKeys.Duration] = JsonValue.Create("00:10:12")
}, },
Type = AssetType.Video Type = AssetType.Video
}; };
@ -109,7 +109,7 @@ public class FileTagAssetMetadataSourceTests : GivenContext
{ {
Metadata = new AssetMetadata Metadata = new AssetMetadata
{ {
["duration"] = JsonValue.Create("00:10:12") [KnownMetadataKeys.Duration] = JsonValue.Create("00:10:12")
}, },
Type = AssetType.Audio Type = AssetType.Audio
}; };

28
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs

@ -61,8 +61,8 @@ public class ImageAssetMetadataSourceTests : GivenContext
await sut.EnhanceAsync(command, CancellationToken); await sut.EnhanceAsync(command, CancellationToken);
Assert.Equal(800, command.Metadata.GetPixelWidth()); Assert.Equal(800, command.Metadata.GetInt32(KnownMetadataKeys.PixelWidth));
Assert.Equal(600, command.Metadata.GetPixelHeight()); Assert.Equal(600, command.Metadata.GetInt32(KnownMetadataKeys.PixelHeight));
Assert.Equal(AssetType.Image, command.Type); Assert.Equal(AssetType.Image, command.Type);
A.CallTo(() => assetGenerator.FixAsync(stream, file.MimeType, A<Stream>._, A<CancellationToken>._)) A.CallTo(() => assetGenerator.FixAsync(stream, file.MimeType, A<Stream>._, A<CancellationToken>._))
@ -82,8 +82,8 @@ public class ImageAssetMetadataSourceTests : GivenContext
await sut.EnhanceAsync(command, CancellationToken); await sut.EnhanceAsync(command, CancellationToken);
Assert.Equal(800, command.Metadata.GetPixelWidth()); Assert.Equal(800, command.Metadata.GetInt32(KnownMetadataKeys.PixelWidth));
Assert.Equal(600, command.Metadata.GetPixelHeight()); Assert.Equal(600, command.Metadata.GetInt32(KnownMetadataKeys.PixelHeight));
Assert.Equal(AssetType.Image, command.Type); Assert.Equal(AssetType.Image, command.Type);
A.CallTo(() => assetGenerator.FixAsync(stream, file.MimeType, A<Stream>._, CancellationToken)) A.CallTo(() => assetGenerator.FixAsync(stream, file.MimeType, A<Stream>._, CancellationToken))
@ -103,8 +103,8 @@ public class ImageAssetMetadataSourceTests : GivenContext
await sut.EnhanceAsync(command, CancellationToken); await sut.EnhanceAsync(command, CancellationToken);
Assert.Equal(800, command.Metadata.GetPixelWidth()); Assert.Equal(800, command.Metadata.GetInt32(KnownMetadataKeys.PixelWidth));
Assert.Equal(600, command.Metadata.GetPixelHeight()); Assert.Equal(600, command.Metadata.GetInt32(KnownMetadataKeys.PixelHeight));
Assert.Equal(AssetType.Image, command.Type); Assert.Equal(AssetType.Image, command.Type);
A.CallTo(() => assetGenerator.FixAsync(stream, file.MimeType, A<Stream>._, CancellationToken)) A.CallTo(() => assetGenerator.FixAsync(stream, file.MimeType, A<Stream>._, CancellationToken))
@ -116,8 +116,8 @@ public class ImageAssetMetadataSourceTests : GivenContext
{ {
var command = new CreateAsset { File = file, Type = AssetType.Image }; var command = new CreateAsset { File = file, Type = AssetType.Image };
command.Metadata.SetPixelWidth(100); command.Metadata[KnownMetadataKeys.PixelWidth] = 100;
command.Metadata.SetPixelWidth(100); command.Metadata[KnownMetadataKeys.PixelHeight] = 50;
await sut.EnhanceAsync(command, CancellationToken); await sut.EnhanceAsync(command, CancellationToken);
@ -130,8 +130,8 @@ public class ImageAssetMetadataSourceTests : GivenContext
{ {
var command = new CreateAsset { File = file, Type = AssetType.Image }; var command = new CreateAsset { File = file, Type = AssetType.Image };
command.Metadata.SetPixelWidth(800); command.Metadata[KnownMetadataKeys.PixelWidth] = 800;
command.Metadata.SetPixelWidth(600); command.Metadata[KnownMetadataKeys.PixelHeight] = 600;
await sut.EnhanceAsync(command, CancellationToken); await sut.EnhanceAsync(command, CancellationToken);
@ -144,8 +144,8 @@ public class ImageAssetMetadataSourceTests : GivenContext
{ {
var command = new CreateAsset { File = file, Type = AssetType.Image }; var command = new CreateAsset { File = file, Type = AssetType.Image };
command.Metadata.SetPixelWidth(1200); command.Metadata[KnownMetadataKeys.PixelWidth] = 1400;
command.Metadata.SetPixelWidth(1400); command.Metadata[KnownMetadataKeys.PixelHeight] = 1200;
await sut.EnhanceAsync(command, CancellationToken); await sut.EnhanceAsync(command, CancellationToken);
@ -160,8 +160,8 @@ public class ImageAssetMetadataSourceTests : GivenContext
{ {
Metadata = new AssetMetadata Metadata = new AssetMetadata
{ {
["pixelWidth"] = JsonValue.Create(128), [KnownMetadataKeys.PixelWidth] = 128,
["pixelHeight"] = JsonValue.Create(55) [KnownMetadataKeys.PixelHeight] = 55
}, },
Type = AssetType.Image Type = AssetType.Image
}; };

74
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/SvgAssetMetadataSourceTests.cs

@ -5,17 +5,16 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Text;
using Squidex.Assets; using Squidex.Assets;
using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Properties; using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
namespace Squidex.Domain.Apps.Entities.Assets; namespace Squidex.Domain.Apps.Entities.Assets;
public class SvgAssetMetadataSourceTests public class SvgAssetMetadataSourceTests : GivenContext
{ {
private readonly MemoryStream stream = new MemoryStream();
private readonly SvgAssetMetadataSource sut = new SvgAssetMetadataSource(); private readonly SvgAssetMetadataSource sut = new SvgAssetMetadataSource();
public SvgAssetMetadataSourceTests() public SvgAssetMetadataSourceTests()
@ -26,9 +25,7 @@ public class SvgAssetMetadataSourceTests
[Fact] [Fact]
public async Task Should_add_image_tag_if_svg_mime() public async Task Should_add_image_tag_if_svg_mime()
{ {
var svg = new DelegateAssetFile("MyImage.png", "image/svg+xml", 1024, () => stream); var command = FakeCommand("image.svg");
var command = new CreateAsset { File = svg };
await sut.EnhanceAsync(command, default); await sut.EnhanceAsync(command, default);
@ -38,9 +35,7 @@ public class SvgAssetMetadataSourceTests
[Fact] [Fact]
public async Task Should_add_image_tag_if_svg_extension() public async Task Should_add_image_tag_if_svg_extension()
{ {
var svg = new DelegateAssetFile("MyImage.svg", "other", 1024, () => stream); var command = FakeCommand("image.svg");
var command = new CreateAsset { File = svg };
await sut.EnhanceAsync(command, default); await sut.EnhanceAsync(command, default);
@ -50,30 +45,63 @@ public class SvgAssetMetadataSourceTests
[Fact] [Fact]
public async Task Should_throw_exception_if_svg_is_malicious() public async Task Should_throw_exception_if_svg_is_malicious()
{ {
var bytes = Encoding.UTF8.GetBytes(Resources.SvgInvalid); var command = Command("SvgInvalid.svg");
stream.Write(bytes); await Assert.ThrowsAsync<ValidationException>(() => sut.EnhanceAsync(command, default));
stream.Seek(0, SeekOrigin.Begin);
var svg = new DelegateAssetFile("MyImage.svg", "other", 1024, () => stream); Assert.False(command.Metadata.ContainsKey(KnownMetadataKeys.PixelWidth));
Assert.False(command.Metadata.ContainsKey(KnownMetadataKeys.PixelHeight));
Assert.False(command.Metadata.ContainsKey(KnownMetadataKeys.ViewBox));
}
var command = new CreateAsset { File = svg }; [Fact]
public async Task Should_not_throw_exception_if_svg_is_not_malicious()
{
var command = Command("SvgValid.svg");
await Assert.ThrowsAsync<ValidationException>(() => sut.EnhanceAsync(command, default)); await sut.EnhanceAsync(command, default);
Assert.Equal("20", command.Metadata[KnownMetadataKeys.PixelWidth].AsString);
Assert.Equal("30", command.Metadata[KnownMetadataKeys.PixelHeight].AsString);
Assert.Equal("0 0 100 100", command.Metadata[KnownMetadataKeys.ViewBox].AsString);
} }
[Fact] [Fact]
public async Task Should_not_throw_exception_if_svg_is_not_malicious() public void Should_describe_metadata()
{ {
var bytes = Encoding.UTF8.GetBytes(Resources.SvgValid); var source = CreateAsset() with
{
Metadata = new AssetMetadata
{
[KnownMetadataKeys.PixelWidth] = "128",
[KnownMetadataKeys.PixelHeight] = "55"
},
MimeType = "image/svg+xml"
};
var formatted = sut.Format(source);
Assert.Equal(new[] { "128x55" }, formatted);
}
stream.Write(bytes); private static UploadAssetCommand Command(string path)
stream.Seek(0, SeekOrigin.Begin); {
var file = new FileInfo(Path.Combine("Assets", "TestFiles", path));
var svg = new DelegateAssetFile("MyImage.svg", "other", 1024, () => stream); return new CreateAsset
{
File = new DelegateAssetFile(file.Name, "mime", file.Length, file.OpenRead)
};
}
var command = new CreateAsset { File = svg }; private static UploadAssetCommand FakeCommand(string name)
{
var stream = new MemoryStream();
await sut.EnhanceAsync(command, default); return new CreateAsset
{
File = new DelegateAssetFile(name, "mime", stream.Length, () => stream)
};
} }
} }

5
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/TestFiles/SvgInvalid.svg

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" onload="alert(localStorage.getItem('oidc.user:https://cloud.squidex.io/identity-server/:squidex-frontend'))">
<path d="M30,1h40l29,29v40l-29,29h-40l-29-29v-40z" stroke="#000" fill="none"/>
<path d="M31,3h38l28,28v38l-28,28h-38l-28-28v-38z" fill="#a23"/>
<text x="50" y="68" font-size="48" fill="#FFF" text-anchor="middle"><![CDATA[410]]></text>
</svg>

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/TestFiles/SvgValid.svg

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="20" height="30">
<path d="M30,1h40l29,29v40l-29,29h-40l-29-29v-40z" stroke="#000" fill="none"/>
<path d="M31,3h38l28,28v38l-28,28h-38l-28-28v-38z" fill="#a23"/>
<text x="50" y="68" font-size="48" fill="#FFF" text-anchor="middle"><![CDATA[410]]></text>
<use id="#other"/>
</svg>

17
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestAsset.cs

@ -76,10 +76,11 @@ public static class TestAsset
MimeType = "image/png", MimeType = "image/png",
Type = AssetType.Image, Type = AssetType.Image,
MetadataText = "metadata-text", MetadataText = "metadata-text",
Metadata = Metadata =new AssetMetadata
new AssetMetadata() {
.SetPixelWidth(800) [KnownMetadataKeys.PixelWidth] = 800,
.SetPixelHeight(600), [KnownMetadataKeys.PixelHeight] = 600,
},
TagNames = new[] TagNames = new[]
{ {
"tag1", "tag1",
@ -123,8 +124,8 @@ public static class TestAsset
fileVersion = asset.FileVersion, fileVersion = asset.FileVersion,
isImage = true, isImage = true,
isProtected = asset.IsProtected, isProtected = asset.IsProtected,
pixelWidth = asset.Metadata.GetPixelWidth(), pixelWidth = asset.Metadata.GetInt32(KnownMetadataKeys.PixelWidth),
pixelHeight = asset.Metadata.GetPixelHeight(), pixelHeight = asset.Metadata.GetInt32(KnownMetadataKeys.PixelHeight),
parentId = asset.Id, parentId = asset.Id,
tags = asset.TagNames, tags = asset.TagNames,
type = "IMAGE", type = "IMAGE",
@ -133,8 +134,8 @@ public static class TestAsset
metadataUnknown = (string?)null, metadataUnknown = (string?)null,
metadata = new metadata = new
{ {
pixelWidth = asset.Metadata.GetPixelWidth(), pixelWidth = asset.Metadata.GetInt32(KnownMetadataKeys.PixelWidth),
pixelHeight = asset.Metadata.GetPixelHeight() pixelHeight = asset.Metadata.GetInt32(KnownMetadataKeys.PixelHeight)
}, },
slug = asset.Slug slug = asset.Slug
}; };

90
backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.Designer.cs

@ -1,90 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Squidex.Domain.Apps.Entities.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Squidex.Domain.Apps.Entities.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 100 100&quot; onload=&quot;alert(localStorage.getItem(&apos;oidc.user:https://cloud.squidex.io/identity-server/:squidex-frontend&apos;))&quot;&gt;
/// &lt;path d=&quot;M30,1h40l29,29v40l-29,29h-40l-29-29v-40z&quot; stroke=&quot;#000&quot; fill=&quot;none&quot;/&gt;
/// &lt;path d=&quot;M31,3h38l28,28v38l-28,28h-38l-28-28v-38z&quot; fill=&quot;#a23&quot;/&gt;
/// &lt;text x=&quot;50&quot; y=&quot;68&quot; font-size=&quot;48&quot; fill=&quot;#FFF&quot; text-anchor=&quot;middle&quot;&gt;&lt;![CDATA[410]]&gt;&lt;/text&gt;
///&lt;/svg&gt;.
/// </summary>
internal static string SvgInvalid {
get {
return ResourceManager.GetString("SvgInvalid", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 100 100&quot;&gt;
/// &lt;path d=&quot;M30,1h40l29,29v40l-29,29h-40l-29-29v-40z&quot; stroke=&quot;#000&quot; fill=&quot;none&quot;/&gt;
/// &lt;path d=&quot;M31,3h38l28,28v38l-28,28h-38l-28-28v-38z&quot; fill=&quot;#a23&quot;/&gt;
/// &lt;text x=&quot;50&quot; y=&quot;68&quot; font-size=&quot;48&quot; fill=&quot;#FFF&quot; text-anchor=&quot;middle&quot;&gt;&lt;![CDATA[410]]&gt;&lt;/text&gt;
/// &lt;use id=&quot;#other&quot;/&gt;
///&lt;/svg&gt;.
/// </summary>
internal static string SvgValid {
get {
return ResourceManager.GetString("SvgValid", resourceCulture);
}
}
}
}

135
backend/tests/Squidex.Domain.Apps.Entities.Tests/Properties/Resources.resx

@ -1,135 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="SvgInvalid" xml:space="preserve">
<value>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" onload="alert(localStorage.getItem('oidc.user:https://cloud.squidex.io/identity-server/:squidex-frontend'))"&gt;
&lt;path d="M30,1h40l29,29v40l-29,29h-40l-29-29v-40z" stroke="#000" fill="none"/&gt;
&lt;path d="M31,3h38l28,28v38l-28,28h-38l-28-28v-38z" fill="#a23"/&gt;
&lt;text x="50" y="68" font-size="48" fill="#FFF" text-anchor="middle"&gt;&lt;![CDATA[410]]&gt;&lt;/text&gt;
&lt;/svg&gt;</value>
</data>
<data name="SvgValid" xml:space="preserve">
<value>&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"&gt;
&lt;path d="M30,1h40l29,29v40l-29,29h-40l-29-29v-40z" stroke="#000" fill="none"/&gt;
&lt;path d="M31,3h38l28,28v38l-28,28h-38l-28-28v-38z" fill="#a23"/&gt;
&lt;text x="50" y="68" font-size="48" fill="#FFF" text-anchor="middle"&gt;&lt;![CDATA[410]]&gt;&lt;/text&gt;
&lt;use id="#other"/&gt;
&lt;/svg&gt;</value>
</data>
</root>

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

@ -27,7 +27,7 @@
<PackageReference Include="GraphQL" Version="7.7.2" /> <PackageReference Include="GraphQL" Version="7.7.2" />
<PackageReference Include="GraphQL.SystemTextJson" Version="7.7.2" /> <PackageReference Include="GraphQL.SystemTextJson" Version="7.7.2" />
<PackageReference Include="Lorem.Universal.Net" Version="4.0.80" /> <PackageReference Include="Lorem.Universal.Net" Version="4.0.80" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
@ -54,19 +54,6 @@
<ItemGroup> <ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" /> <AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="Assets\TestFiles\SampleAudio_0.4mb.mp3"> <None Update="Assets\TestFiles\SampleAudio_0.4mb.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@ -77,5 +64,11 @@
<None Update="Assets\TestFiles\SampleVideo_1280x720_1mb.mp4"> <None Update="Assets\TestFiles\SampleVideo_1280x720_1mb.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="Assets\TestFiles\SvgInvalid.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\TestFiles\SvgValid.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
</Project> </Project>

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

@ -16,7 +16,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FakeItEasy" Version="8.1.0" /> <PackageReference Include="FakeItEasy" Version="8.1.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" /> <PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

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

@ -16,7 +16,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FakeItEasy" Version="8.1.0" /> <PackageReference Include="FakeItEasy" Version="8.1.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" /> <PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

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

@ -16,7 +16,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FakeItEasy" Version="8.1.0" /> <PackageReference Include="FakeItEasy" Version="8.1.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" /> <PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.138"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

1
tools/TestSuite/TestSuite.ApiTests/AnonymousTests.cs

@ -14,7 +14,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public class AnonymousTests : IClassFixture<ClientFixture> public class AnonymousTests : IClassFixture<ClientFixture>
{ {
private readonly string appName = Guid.NewGuid().ToString(); private readonly string appName = Guid.NewGuid().ToString();

1
tools/TestSuite/TestSuite.ApiTests/AppClientsTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public sealed class AppClientsTests : IClassFixture<ClientFixture> public sealed class AppClientsTests : IClassFixture<ClientFixture>
{ {
private readonly string id = Guid.NewGuid().ToString(); private readonly string id = Guid.NewGuid().ToString();

1
tools/TestSuite/TestSuite.ApiTests/AppContributorsTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public sealed class AppContributorsTests : IClassFixture<ClientFixture> public sealed class AppContributorsTests : IClassFixture<ClientFixture>
{ {
public ClientFixture _ { get; } public ClientFixture _ { get; }

1
tools/TestSuite/TestSuite.ApiTests/AppCreationTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public class AppCreationTests : IClassFixture<ClientFixture> public class AppCreationTests : IClassFixture<ClientFixture>
{ {
private readonly string appName = Guid.NewGuid().ToString(); private readonly string appName = Guid.NewGuid().ToString();

1
tools/TestSuite/TestSuite.ApiTests/AppLanguagesTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public sealed class AppLanguagesTests : IClassFixture<ClientFixture> public sealed class AppLanguagesTests : IClassFixture<ClientFixture>
{ {
public ClientFixture _ { get; } public ClientFixture _ { get; }

1
tools/TestSuite/TestSuite.ApiTests/AppRolesTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public sealed class AppRolesTests : IClassFixture<CreatedAppFixture> public sealed class AppRolesTests : IClassFixture<CreatedAppFixture>
{ {
private readonly string roleName = Guid.NewGuid().ToString(); private readonly string roleName = Guid.NewGuid().ToString();

1
tools/TestSuite/TestSuite.ApiTests/AppTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public sealed class AppTests : IClassFixture<CreatedAppFixture> public sealed class AppTests : IClassFixture<CreatedAppFixture>
{ {
public CreatedAppFixture _ { get; } public CreatedAppFixture _ { get; }

1
tools/TestSuite/TestSuite.ApiTests/AppWorkflowsTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public sealed class AppWorkflowsTests : IClassFixture<ClientFixture> public sealed class AppWorkflowsTests : IClassFixture<ClientFixture>
{ {
private readonly string workflowName = Guid.NewGuid().ToString(); private readonly string workflowName = Guid.NewGuid().ToString();

1
tools/TestSuite/TestSuite.ApiTests/AssetFoldersTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public class AssetFoldersTests : IClassFixture<CreatedAppFixture> public class AssetFoldersTests : IClassFixture<CreatedAppFixture>
{ {
public CreatedAppFixture _ { get; } public CreatedAppFixture _ { get; }

1
tools/TestSuite/TestSuite.ApiTests/AssetFormatTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public class AssetFormatTests : IClassFixture<CreatedAppFixture> public class AssetFormatTests : IClassFixture<CreatedAppFixture>
{ {
public CreatedAppFixture _ { get; } public CreatedAppFixture _ { get; }

1
tools/TestSuite/TestSuite.ApiTests/AssetTests.cs

@ -15,7 +15,6 @@ using TestSuite.Utils;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public class AssetTests : IClassFixture<CreatedAppFixture> public class AssetTests : IClassFixture<CreatedAppFixture>
{ {
private ProgressHandler progress = new ProgressHandler(); private ProgressHandler progress = new ProgressHandler();

1
tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs

@ -16,7 +16,6 @@ using TestSuite.Model;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public class ContentUpdateTests : IClassFixture<ContentFixture> public class ContentUpdateTests : IClassFixture<ContentFixture>
{ {
public ContentFixture _ { get; } public ContentFixture _ { get; }

1
tools/TestSuite/TestSuite.ApiTests/RuleTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public class RuleTests : IClassFixture<ClientFixture> public class RuleTests : IClassFixture<ClientFixture>
{ {
private readonly string ruleName = Guid.NewGuid().ToString(); private readonly string ruleName = Guid.NewGuid().ToString();

1
tools/TestSuite/TestSuite.ApiTests/SchemaTests.cs

@ -14,7 +14,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public class SchemaTests : IClassFixture<CreatedAppFixture> public class SchemaTests : IClassFixture<CreatedAppFixture>
{ {
private readonly string schemaName = $"schema-{Guid.NewGuid()}"; private readonly string schemaName = $"schema-{Guid.NewGuid()}";

1
tools/TestSuite/TestSuite.ApiTests/TeamContributorTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public class TeamContributorTests : IClassFixture<ClientFixture> public class TeamContributorTests : IClassFixture<ClientFixture>
{ {
public ClientFixture _ { get; } public ClientFixture _ { get; }

1
tools/TestSuite/TestSuite.ApiTests/TeamTests.cs

@ -13,7 +13,6 @@ using TestSuite.Fixtures;
namespace TestSuite.ApiTests; namespace TestSuite.ApiTests;
[UsesVerify]
public class TeamTests : IClassFixture<CreatedTeamFixture> public class TeamTests : IClassFixture<CreatedTeamFixture>
{ {
public CreatedTeamFixture _ { get; } public CreatedTeamFixture _ { get; }

14
tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj

@ -7,21 +7,21 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Codeuctivity.ImageSharpCompare" Version="4.0.223" /> <PackageReference Include="Codeuctivity.ImageSharpCompare" Version="4.0.234" />
<PackageReference Include="FluentAssertions" Version="6.12.0" /> <PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="GraphQL.Client" Version="6.0.2" /> <PackageReference Include="GraphQL.Client" Version="6.0.2" />
<PackageReference Include="GraphQL.Client.Serializer.Newtonsoft" Version="6.0.2" /> <PackageReference Include="GraphQL.Client.Serializer.Newtonsoft" Version="6.0.2" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.136"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="NSwag.Core" Version="14.0.1" /> <PackageReference Include="NSwag.Core" Version="14.0.2" />
<PackageReference Include="PuppeteerSharp" Version="13.0.2" /> <PackageReference Include="PuppeteerSharp" Version="14.0.0" />
<PackageReference Include="Squidex.Assets" Version="6.3.5" /> <PackageReference Include="Squidex.Assets" Version="6.3.7" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="Verify.Xunit" Version="22.11.5" /> <PackageReference Include="Verify.Xunit" Version="23.0.1" />
<PackageReference Include="xunit" Version="2.6.5" /> <PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6"> <PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

4
tools/TestSuite/TestSuite.LoadTests/TestSuite.LoadTests.csproj

@ -7,13 +7,13 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.136"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="xunit" Version="2.6.5" /> <PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6"> <PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

12
tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj

@ -7,7 +7,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.136"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.139">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
@ -17,12 +17,12 @@
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" 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.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets" Version="6.3.5" /> <PackageReference Include="Squidex.Assets" Version="6.3.7" />
<PackageReference Include="Squidex.ClientLibrary" Version="19.0.0" /> <PackageReference Include="Squidex.ClientLibrary" Version="19.1.0" />
<PackageReference Include="Squidex.ClientLibrary.ServiceExtensions" Version="19.0.0" /> <PackageReference Include="Squidex.ClientLibrary.ServiceExtensions" Version="19.1.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="Verify" Version="22.11.5" /> <PackageReference Include="Verify" Version="23.0.1" />
<PackageReference Include="xunit" Version="2.6.5" /> <PackageReference Include="xunit" Version="2.6.6" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" /> <AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" />

Loading…
Cancel
Save