Browse Source

Add all files to commit.

pull/310/head
Sebastian 8 years ago
parent
commit
f2a9af1c48
  1. 23
      src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs
  2. 28
      src/Squidex.Domain.Apps.Entities/Assets/AssetCreatedResult.cs
  3. 24
      src/Squidex.Domain.Apps.Entities/Assets/AssetGrain.cs
  4. 3
      src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAsset.cs
  5. 27
      src/Squidex.Domain.Apps.Entities/Assets/FileTypeTagGenerator.cs
  6. 39
      src/Squidex.Domain.Apps.Entities/Assets/ImageTagGenerator.cs
  7. 16
      src/Squidex.Domain.Apps.Entities/Tags/ITagGenerator.cs
  8. 3
      src/Squidex.Domain.Apps.Events/Assets/AssetCreated.cs
  9. 16
      src/Squidex.Infrastructure/FileExtensions.cs
  10. 23
      tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs
  11. 24
      tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetGrainTests.cs
  12. 56
      tests/Squidex.Domain.Apps.Entities.Tests/Assets/FileTypeTagGeneratorTests.cs
  13. 72
      tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageTagGeneratorTests.cs
  14. 2
      tests/Squidex.Infrastructure.Tests/FileExtensionsTests.cs

23
src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs

@ -6,9 +6,11 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Orleans; using Orleans;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Tags;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Assets; using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
@ -19,18 +21,23 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
private readonly IAssetStore assetStore; private readonly IAssetStore assetStore;
private readonly IAssetThumbnailGenerator assetThumbnailGenerator; private readonly IAssetThumbnailGenerator assetThumbnailGenerator;
private readonly IEnumerable<ITagGenerator<CreateAsset>> tagGenerators;
public AssetCommandMiddleware( public AssetCommandMiddleware(
IGrainFactory grainFactory, IGrainFactory grainFactory,
IAssetStore assetStore, IAssetStore assetStore,
IAssetThumbnailGenerator assetThumbnailGenerator) IAssetThumbnailGenerator assetThumbnailGenerator,
IEnumerable<ITagGenerator<CreateAsset>> tagGenerators)
: base(grainFactory) : base(grainFactory)
{ {
Guard.NotNull(assetStore, nameof(assetStore)); Guard.NotNull(assetStore, nameof(assetStore));
Guard.NotNull(assetThumbnailGenerator, nameof(assetThumbnailGenerator)); Guard.NotNull(assetThumbnailGenerator, nameof(assetThumbnailGenerator));
Guard.NotNull(tagGenerators, nameof(tagGenerators));
this.assetStore = assetStore; this.assetStore = assetStore;
this.assetThumbnailGenerator = assetThumbnailGenerator; this.assetThumbnailGenerator = assetThumbnailGenerator;
this.tagGenerators = tagGenerators;
} }
public async override Task HandleAsync(CommandContext context, Func<Task> next) public async override Task HandleAsync(CommandContext context, Func<Task> next)
@ -39,14 +46,26 @@ namespace Squidex.Domain.Apps.Entities.Assets
{ {
case CreateAsset createAsset: case CreateAsset createAsset:
{ {
if (createAsset.Tags == null)
{
createAsset.Tags = new HashSet<string>();
}
createAsset.ImageInfo = await assetThumbnailGenerator.GetImageInfoAsync(createAsset.File.OpenRead()); createAsset.ImageInfo = await assetThumbnailGenerator.GetImageInfoAsync(createAsset.File.OpenRead());
foreach (var tagGenerator in tagGenerators)
{
tagGenerator.GenerateTags(createAsset, createAsset.Tags);
}
var originalTags = new HashSet<string>(createAsset.Tags);
await assetStore.UploadAsync(context.ContextId.ToString(), createAsset.File.OpenRead()); await assetStore.UploadAsync(context.ContextId.ToString(), createAsset.File.OpenRead());
try try
{ {
var result = await ExecuteCommandAsync(createAsset) as AssetSavedResult; var result = await ExecuteCommandAsync(createAsset) as AssetSavedResult;
context.Complete(EntityCreatedResult.Create(createAsset.AssetId, result.Version)); context.Complete(new AssetCreatedResult(createAsset.AssetId, originalTags, result.Version));
await assetStore.CopyAsync(context.ContextId.ToString(), createAsset.AssetId.ToString(), result.FileVersion, null); await assetStore.CopyAsync(context.ContextId.ToString(), createAsset.AssetId.ToString(), result.FileVersion, null);
} }

28
src/Squidex.Domain.Apps.Entities/Assets/AssetCreatedResult.cs

@ -0,0 +1,28 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using Squidex.Infrastructure.Commands;
namespace Squidex.Domain.Apps.Entities.Assets
{
public sealed class AssetCreatedResult : EntitySavedResult
{
public Guid Id { get; }
public HashSet<string> Tags { get; }
public AssetCreatedResult(Guid id, HashSet<string> tags, long version)
: base(version)
{
Id = id;
Tags = tags;
}
}
}

24
src/Squidex.Domain.Apps.Entities/Assets/AssetGrain.cs

@ -42,10 +42,12 @@ namespace Squidex.Domain.Apps.Entities.Assets
switch (command) switch (command)
{ {
case CreateAsset createRule: case CreateAsset createRule:
return CreateReturnAsync(createRule, c => return CreateReturnAsync(createRule, async c =>
{ {
GuardAsset.CanCreate(c); GuardAsset.CanCreate(c);
c.Tags = await tagService.NormalizeTagsAsync(c.AppId.Id, TagGroups.Assets, c.Tags, Snapshot.Tags);
Create(c); Create(c);
return new AssetSavedResult(Version, Snapshot.FileVersion); return new AssetSavedResult(Version, Snapshot.FileVersion);
@ -59,12 +61,14 @@ namespace Squidex.Domain.Apps.Entities.Assets
return new AssetSavedResult(Version, Snapshot.FileVersion); return new AssetSavedResult(Version, Snapshot.FileVersion);
}); });
case RenameAsset renameAsset: case TagAsset tagAsset:
return UpdateAsync(renameAsset, c => return UpdateAsync(tagAsset, async c =>
{ {
GuardAsset.CanRename(c, Snapshot.FileName); GuardAsset.CanTag(c);
Rename(c); c.Tags = await tagService.NormalizeTagsAsync(Snapshot.AppId.Id, TagGroups.Assets, c.Tags, Snapshot.Tags);
Tag(c);
}); });
case DeleteAsset deleteAsset: case DeleteAsset deleteAsset:
return UpdateAsync(deleteAsset, async c => return UpdateAsync(deleteAsset, async c =>
@ -75,14 +79,12 @@ namespace Squidex.Domain.Apps.Entities.Assets
Delete(c); Delete(c);
}); });
case TagAsset tagAsset: case RenameAsset renameAsset:
return UpdateAsync(tagAsset, async c => return UpdateAsync(renameAsset, c =>
{ {
GuardAsset.CanTag(c); GuardAsset.CanRename(c, Snapshot.FileName);
c.Tags = await tagService.NormalizeTagsAsync(Snapshot.AppId.Id, TagGroups.Assets, c.Tags, Snapshot.Tags);
Tag(c); Rename(c);
}); });
default: default:
throw new NotSupportedException(); throw new NotSupportedException();

3
src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAsset.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Collections.Generic;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Assets; using Squidex.Infrastructure.Assets;
@ -19,6 +20,8 @@ namespace Squidex.Domain.Apps.Entities.Assets.Commands
public ImageInfo ImageInfo { get; set; } public ImageInfo ImageInfo { get; set; }
public HashSet<string> Tags { get; set; }
public CreateAsset() public CreateAsset()
{ {
AssetId = Guid.NewGuid(); AssetId = Guid.NewGuid();

27
src/Squidex.Domain.Apps.Entities/Assets/FileTypeTagGenerator.cs

@ -0,0 +1,27 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Tags;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Assets
{
public sealed class FileTypeTagGenerator : ITagGenerator<CreateAsset>
{
public void GenerateTags(CreateAsset source, HashSet<string> tags)
{
var extension = source.File?.FileName?.FileType();
if (!string.IsNullOrWhiteSpace(extension))
{
tags.Add($"type/{extension.ToLowerInvariant()}");
}
}
}
}

39
src/Squidex.Domain.Apps.Entities/Assets/ImageTagGenerator.cs

@ -0,0 +1,39 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Domain.Apps.Entities.Tags;
namespace Squidex.Domain.Apps.Entities.Assets
{
public sealed class ImageTagGenerator : ITagGenerator<CreateAsset>
{
public void GenerateTags(CreateAsset source, HashSet<string> tags)
{
if (source.ImageInfo != null)
{
tags.Add("image");
var wh = source.ImageInfo.PixelWidth + source.ImageInfo.PixelHeight;
if (wh > 2000)
{
tags.Add("image/large");
}
else if (wh > 1000)
{
tags.Add("image/medium");
}
else
{
tags.Add("image/small");
}
}
}
}
}

16
src/Squidex.Domain.Apps.Entities/Tags/ITagGenerator.cs

@ -0,0 +1,16 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Domain.Apps.Entities.Tags
{
public interface ITagGenerator<T>
{
void GenerateTags(T source, HashSet<string> tags);
}
}

3
src/Squidex.Domain.Apps.Events/Assets/AssetCreated.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Collections.Generic;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Domain.Apps.Events.Assets namespace Squidex.Domain.Apps.Events.Assets
@ -25,5 +26,7 @@ namespace Squidex.Domain.Apps.Events.Assets
public int? PixelWidth { get; set; } public int? PixelWidth { get; set; }
public int? PixelHeight { get; set; } public int? PixelHeight { get; set; }
public HashSet<string> Tags { get; set; }
} }
} }

16
src/Squidex.Infrastructure/FileExtensions.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
@ -22,13 +23,26 @@ namespace Squidex.Infrastructure
"TB" "TB"
}; };
private static readonly Dictionary<string, string> UnifiedExtensions = new Dictionary<string, string>()
{
["jpeg"] = "jpg"
};
public static string FileType(this string fileName) public static string FileType(this string fileName)
{ {
try try
{ {
var fileInfo = new FileInfo(fileName); var fileInfo = new FileInfo(fileName);
var fileType = fileInfo.Extension.Substring(1).ToLowerInvariant();
return fileInfo.Extension.Substring(1).ToLowerInvariant(); if (UnifiedExtensions.TryGetValue(fileType, out var unified))
{
return unified;
}
else
{
return fileType;
}
} }
catch catch
{ {

23
tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -28,6 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
private readonly IAssetThumbnailGenerator assetThumbnailGenerator = A.Fake<IAssetThumbnailGenerator>(); private readonly IAssetThumbnailGenerator assetThumbnailGenerator = A.Fake<IAssetThumbnailGenerator>();
private readonly IAssetStore assetStore = A.Fake<IAssetStore>(); private readonly IAssetStore assetStore = A.Fake<IAssetStore>();
private readonly ITagService tagService = A.Fake<ITagService>(); private readonly ITagService tagService = A.Fake<ITagService>();
private readonly ITagGenerator<CreateAsset> tagGenerator = A.Fake<ITagGenerator<CreateAsset>>();
private readonly IGrainFactory grainFactory = A.Fake<IGrainFactory>(); private readonly IGrainFactory grainFactory = A.Fake<IGrainFactory>();
private readonly Guid assetId = Guid.NewGuid(); private readonly Guid assetId = Guid.NewGuid();
private readonly Stream stream = new MemoryStream(); private readonly Stream stream = new MemoryStream();
@ -48,23 +50,38 @@ namespace Squidex.Domain.Apps.Entities.Assets
asset = new AssetGrain(Store, tagService, A.Dummy<ISemanticLog>()); asset = new AssetGrain(Store, tagService, A.Dummy<ISemanticLog>());
asset.OnActivateAsync(Id).Wait(); asset.OnActivateAsync(Id).Wait();
A.CallTo(() => tagService.NormalizeTagsAsync(AppId, TagGroups.Assets, A<HashSet<string>>.Ignored, A<HashSet<string>>.Ignored))
.Returns(new HashSet<string>());
A.CallTo(() => grainFactory.GetGrain<IAssetGrain>(Id, null)) A.CallTo(() => grainFactory.GetGrain<IAssetGrain>(Id, null))
.Returns(asset); .Returns(asset);
sut = new AssetCommandMiddleware(grainFactory, assetStore, assetThumbnailGenerator); sut = new AssetCommandMiddleware(grainFactory, assetStore, assetThumbnailGenerator, new[] { tagGenerator });
} }
[Fact] [Fact]
public async Task Create_should_create_domain_object() public async Task Create_should_create_domain_object()
{ {
var context = CreateContextForCommand(new CreateAsset { AssetId = assetId, File = file }); var command = new CreateAsset { AssetId = assetId, File = file };
var context = CreateContextForCommand(command);
A.CallTo(() => tagGenerator.GenerateTags(command, A<HashSet<string>>.Ignored))
.Invokes(new Action<CreateAsset, HashSet<string>>((c, tags) =>
{
tags.Add("tag1");
tags.Add("tag2");
}));
SetupStore(0, context.ContextId); SetupStore(0, context.ContextId);
SetupImageInfo(); SetupImageInfo();
await sut.HandleAsync(context); await sut.HandleAsync(context);
Assert.Equal(assetId, context.Result<EntityCreatedResult<Guid>>().IdOrValue); var result = context.Result<AssetCreatedResult>();
Assert.Equal(assetId, result.Id);
Assert.Contains("tag1", result.Tags);
Assert.Contains("tag2", result.Tags);
AssertAssetHasBeenUploaded(0, context.ContextId); AssertAssetHasBeenUploaded(0, context.ContextId);
AssertAssetImageChecked(); AssertAssetImageChecked();

24
tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetGrainTests.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
@ -37,6 +38,9 @@ namespace Squidex.Domain.Apps.Entities.Assets
public AssetGrainTests() public AssetGrainTests()
{ {
A.CallTo(() => tagService.NormalizeTagsAsync(AppId, TagGroups.Assets, A<HashSet<string>>.Ignored, A<HashSet<string>>.Ignored))
.Returns(new HashSet<string>());
sut = new AssetGrain(Store, tagService, A.Dummy<ISemanticLog>()); sut = new AssetGrain(Store, tagService, A.Dummy<ISemanticLog>());
sut.OnActivateAsync(Id).Wait(); sut.OnActivateAsync(Id).Wait();
} }
@ -71,7 +75,8 @@ namespace Squidex.Domain.Apps.Entities.Assets
FileVersion = 0, FileVersion = 0,
MimeType = file.MimeType, MimeType = file.MimeType,
PixelWidth = image.PixelWidth, PixelWidth = image.PixelWidth,
PixelHeight = image.PixelHeight PixelHeight = image.PixelHeight,
Tags = new HashSet<string>()
}) })
); );
} }
@ -122,6 +127,23 @@ namespace Squidex.Domain.Apps.Entities.Assets
); );
} }
[Fact]
public async Task Tag_should_create_events()
{
var command = new TagAsset();
await ExecuteCreateAsync();
var result = await sut.ExecuteAsync(CreateAssetCommand(command));
result.ShouldBeEquivalent(new EntitySavedResult(1));
LastEvents
.ShouldHaveSameEvents(
CreateAssetEvent(new AssetTagged { Tags = new HashSet<string>() })
);
}
[Fact] [Fact]
public async Task Delete_should_create_events_with_total_file_size() public async Task Delete_should_create_events_with_total_file_size()
{ {

56
tests/Squidex.Domain.Apps.Entities.Tests/Assets/FileTypeTagGeneratorTests.cs

@ -0,0 +1,56 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure.Assets;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Assets
{
public class FileTypeTagGeneratorTests
{
private readonly HashSet<string> tags = new HashSet<string>();
private readonly FileTypeTagGenerator sut = new FileTypeTagGenerator();
[Fact]
public void Should_not_add_tag_if_no_file_info()
{
var command = new CreateAsset();
sut.GenerateTags(command, tags);
Assert.Empty(tags);
}
[Fact]
public void Should_add_file_type()
{
var command = new CreateAsset
{
File = new AssetFile("File.DOCX", "Mime", 100, () => null)
};
sut.GenerateTags(command, tags);
Assert.Contains("type/docx", tags);
}
[Fact]
public void Should_add_blob_if_without_extension()
{
var command = new CreateAsset
{
File = new AssetFile("File", "Mime", 100, () => null)
};
sut.GenerateTags(command, tags);
Assert.Contains("type/blob", tags);
}
}
}

72
tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageTagGeneratorTests.cs

@ -0,0 +1,72 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure.Assets;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Assets
{
public class ImageTagGeneratorTests
{
private readonly HashSet<string> tags = new HashSet<string>();
private readonly ImageTagGenerator sut = new ImageTagGenerator();
[Fact]
public void Should_not_add_tag_if_no_image()
{
var command = new CreateAsset();
sut.GenerateTags(command, tags);
Assert.Empty(tags);
}
[Fact]
public void Should_add_image_tag_if_small()
{
var command = new CreateAsset
{
ImageInfo = new ImageInfo(100, 100)
};
sut.GenerateTags(command, tags);
Assert.Contains("image", tags);
Assert.Contains("image/small", tags);
}
[Fact]
public void Should_add_image_tag_if_medium()
{
var command = new CreateAsset
{
ImageInfo = new ImageInfo(800, 600)
};
sut.GenerateTags(command, tags);
Assert.Contains("image", tags);
Assert.Contains("image/medium", tags);
}
[Fact]
public void Should_add_image_tag_if_large()
{
var command = new CreateAsset
{
ImageInfo = new ImageInfo(1200, 1400)
};
sut.GenerateTags(command, tags);
Assert.Contains("image", tags);
Assert.Contains("image/large", tags);
}
}
}

2
tests/Squidex.Infrastructure.Tests/FileExtensionsTests.cs

@ -16,6 +16,8 @@ namespace Squidex.Infrastructure
[InlineData("test.MP4", "mp4")] [InlineData("test.MP4", "mp4")]
[InlineData("test.txt", "txt")] [InlineData("test.txt", "txt")]
[InlineData("test.TXT", "txt")] [InlineData("test.TXT", "txt")]
[InlineData("test.jpg", "jpg")]
[InlineData("test.jpeg", "jpg")]
public void Should_calculate_file_type(string fileName, string expected) public void Should_calculate_file_type(string fileName, string expected)
{ {
var actual = fileName.FileType(); var actual = fileName.FileType();

Loading…
Cancel
Save