mirror of https://github.com/Squidex/squidex.git
44 changed files with 1120 additions and 71 deletions
@ -0,0 +1,23 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ImageInfo.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Infrastructure.Assets |
||||
|
{ |
||||
|
public sealed class ImageInfo |
||||
|
{ |
||||
|
public int PixelWidth { get; } |
||||
|
|
||||
|
public int PixelHeight { get; } |
||||
|
|
||||
|
public ImageInfo(int pixelWidth, int pixelHeight) |
||||
|
{ |
||||
|
PixelWidth = pixelWidth; |
||||
|
PixelHeight = pixelHeight; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,59 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AssetCommandHandler.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Squidex.Infrastructure.Dispatching; |
||||
|
using Squidex.Infrastructure.Tasks; |
||||
|
using Squidex.Write.Assets.Commands; |
||||
|
|
||||
|
namespace Squidex.Write.Assets |
||||
|
{ |
||||
|
public class AssetCommandHandler : ICommandHandler |
||||
|
{ |
||||
|
private readonly IAggregateHandler handler; |
||||
|
|
||||
|
public AssetCommandHandler(IAggregateHandler handler) |
||||
|
{ |
||||
|
Guard.NotNull(handler, nameof(handler)); |
||||
|
|
||||
|
this.handler = handler; |
||||
|
} |
||||
|
|
||||
|
protected async Task On(CreateAsset command, CommandContext context) |
||||
|
{ |
||||
|
await handler.CreateAsync<AssetDomainObject>(context, c => |
||||
|
{ |
||||
|
c.Create(command); |
||||
|
|
||||
|
context.Succeed(EntityCreatedResult.Create(c.Id, c.Version)); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected async Task On(RenameAsset command, CommandContext context) |
||||
|
{ |
||||
|
await handler.UpdateAsync<AssetDomainObject>(context, c => c.Rename(command)); |
||||
|
} |
||||
|
|
||||
|
protected async Task On(UpdateAsset command, CommandContext context) |
||||
|
{ |
||||
|
await handler.UpdateAsync<AssetDomainObject>(context, c => c.Update(command)); |
||||
|
} |
||||
|
|
||||
|
protected Task On(DeleteAsset command, CommandContext context) |
||||
|
{ |
||||
|
return handler.UpdateAsync<AssetDomainObject>(context, c => c.Delete(command)); |
||||
|
} |
||||
|
|
||||
|
public Task<bool> HandleAsync(CommandContext context) |
||||
|
{ |
||||
|
return context.IsHandled ? TaskHelper.False : this.DispatchActionAsync(context.Command, context); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
// ==========================================================================
|
||||
|
// UpdateAssetCommand.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Write.Assets.Commands |
||||
|
{ |
||||
|
public class UpdateAsset : AssetAggregateCommand |
||||
|
{ |
||||
|
public string MimeType { get; set; } |
||||
|
|
||||
|
public long FileSize { get; set; } |
||||
|
|
||||
|
public bool IsImage { get; set; } |
||||
|
|
||||
|
public int? PixelWidth { get; set; } |
||||
|
|
||||
|
public int? PixelHeight { get; set; } |
||||
|
} |
||||
|
} |
||||
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 65 KiB |
@ -0,0 +1,107 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AssetDto.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using NodaTime; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Squidex.Write.Assets.Commands; |
||||
|
|
||||
|
namespace Squidex.Controllers.Api.Assets.Models |
||||
|
{ |
||||
|
public sealed class AssetDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The id of the asset.
|
||||
|
/// </summary>
|
||||
|
public Guid Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The file name.
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public string FileName { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The mime type.
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public string MimeType { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The size of the file in bytes.
|
||||
|
/// </summary>
|
||||
|
public long FileSize { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Determines of the created file is an image.
|
||||
|
/// </summary>
|
||||
|
public bool IsImage { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The width of the image in pixels if the asset is an image.
|
||||
|
/// </summary>
|
||||
|
public int? PixelWidth { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The height of the image in pixels if the asset is an image.
|
||||
|
/// </summary>
|
||||
|
public int? PixelHeight { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The user that has created the schema.
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public RefToken CreatedBy { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The user that has updated the asset.
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public RefToken LastModifiedBy { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The date and time when the asset has been created.
|
||||
|
/// </summary>
|
||||
|
public Instant Created { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The date and time when the asset has been modified last.
|
||||
|
/// </summary>
|
||||
|
public Instant LastModified { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The version of the asset.
|
||||
|
/// </summary>
|
||||
|
public long Version { get; set; } |
||||
|
|
||||
|
public static AssetDto Create(CreateAsset command, EntityCreatedResult<Guid> result) |
||||
|
{ |
||||
|
var now = SystemClock.Instance.GetCurrentInstant(); |
||||
|
|
||||
|
var response = new AssetDto |
||||
|
{ |
||||
|
Id = result.IdOrValue, |
||||
|
Version = result.Version, |
||||
|
Created = now, |
||||
|
CreatedBy = command.Actor, |
||||
|
LastModified = now, |
||||
|
LastModifiedBy = command.Actor, |
||||
|
FileName = command.FileName, |
||||
|
FileSize = command.FileSize, |
||||
|
MimeType = command.MimeType, |
||||
|
IsImage = command.IsImage, |
||||
|
PixelWidth = command.PixelWidth, |
||||
|
PixelHeight = command.PixelHeight |
||||
|
}; |
||||
|
|
||||
|
return response; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AssetsDto.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Controllers.Api.Assets.Models |
||||
|
{ |
||||
|
public sealed class AssetsDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The total number of assets.
|
||||
|
/// </summary>
|
||||
|
public long Total { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The assets.
|
||||
|
/// </summary>
|
||||
|
public AssetDto[] Items { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
<div class="card"> |
||||
|
<div class="card-block"> |
||||
|
</div> |
||||
|
<div class="card-footer"> |
||||
|
{{fileInfo}} |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,11 @@ |
|||||
|
@import '_vars'; |
||||
|
@import '_mixins'; |
||||
|
|
||||
|
$card-size: 16rem; |
||||
|
|
||||
|
.card { |
||||
|
width: $card-size; |
||||
|
height: $card-size; |
||||
|
margin-right: 1rem; |
||||
|
margin-bottom: 1rem; |
||||
|
} |
||||
@ -0,0 +1,77 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import { Component, Input, OnInit } from '@angular/core'; |
||||
|
|
||||
|
import { |
||||
|
AppComponentBase, |
||||
|
AppsStoreService, |
||||
|
AssetDto, |
||||
|
AssetsService, |
||||
|
NotificationService, |
||||
|
UsersProviderService |
||||
|
} from 'shared'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'sqx-asset', |
||||
|
styleUrls: ['./asset.component.scss'], |
||||
|
templateUrl: './asset.component.html' |
||||
|
}) |
||||
|
export class AssetComponent extends AppComponentBase implements OnInit { |
||||
|
@Input() |
||||
|
public initFile: File; |
||||
|
|
||||
|
@Input() |
||||
|
public asset: AssetDto; |
||||
|
|
||||
|
public get fileInfo(): string { |
||||
|
let result = ''; |
||||
|
|
||||
|
if (this.asset != null) { |
||||
|
if (this.asset.pixelWidth) { |
||||
|
result = `${this.asset.pixelWidth}x${this.asset.pixelHeight}px, `; |
||||
|
} |
||||
|
|
||||
|
result += fileSize(this.asset.fileSize); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
constructor(apps: AppsStoreService, notifications: NotificationService, users: UsersProviderService, |
||||
|
private readonly assetsService: AssetsService |
||||
|
) { |
||||
|
super(notifications, users, apps); |
||||
|
} |
||||
|
|
||||
|
public ngOnInit() { |
||||
|
const initFile = this.initFile; |
||||
|
|
||||
|
if (initFile) { |
||||
|
this.appName() |
||||
|
.switchMap(app => this.assetsService.uploadFile(app, initFile)) |
||||
|
.subscribe(result => { |
||||
|
if (result instanceof AssetDto) { |
||||
|
this.asset = result; |
||||
|
} |
||||
|
}, error => { |
||||
|
this.notifyError(error); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function fileSize(b: number) { |
||||
|
let u = 0, s = 1024; |
||||
|
|
||||
|
while (b >= s || -b >= s) { |
||||
|
b /= s; |
||||
|
u++; |
||||
|
} |
||||
|
|
||||
|
return (u ? b.toFixed(1) + ' ' : b) + ' kMGTPEZY'[u] + 'B'; |
||||
|
} |
||||
@ -1,2 +1,24 @@ |
|||||
@import '_vars'; |
@import '_vars'; |
||||
@import '_mixins'; |
@import '_mixins'; |
||||
|
|
||||
|
.file-drop { |
||||
|
& { |
||||
|
border: 2px dashed $color-border; |
||||
|
background: transparent; |
||||
|
padding: 1rem; |
||||
|
text-align: center; |
||||
|
margin-bottom: 1rem; |
||||
|
} |
||||
|
|
||||
|
&-or { |
||||
|
font-size: .8rem; |
||||
|
} |
||||
|
|
||||
|
&-button { |
||||
|
margin: .5rem 0; |
||||
|
} |
||||
|
|
||||
|
&-info { |
||||
|
color: $color-subtext; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import { Directive, EventEmitter, HostListener, Output } from '@angular/core'; |
||||
|
|
||||
|
@Directive({ |
||||
|
selector: '[sqxFileDrop]' |
||||
|
}) |
||||
|
export class FileDropDirective { |
||||
|
@Output('sqxFileDrop') |
||||
|
public drop = new EventEmitter<File[]>(); |
||||
|
|
||||
|
@HostListener('dragenter', ['$event']) |
||||
|
public onDragEnter(event: DragDropEvent) { |
||||
|
this.tryStopEvent(event); |
||||
|
} |
||||
|
|
||||
|
@HostListener('dragover', ['$event']) |
||||
|
public onDragOver(event: DragDropEvent) { |
||||
|
this.tryStopEvent(event); |
||||
|
} |
||||
|
|
||||
|
@HostListener('drop', ['$event']) |
||||
|
public onDrop(event: DragDropEvent) { |
||||
|
const files: File[] = []; |
||||
|
|
||||
|
// tslint:disable-next-line:prefer-for-of
|
||||
|
for (let i = 0; i < event.dataTransfer.files.length; i++) { |
||||
|
const file = event.dataTransfer.files[i]; |
||||
|
|
||||
|
files.push(file); |
||||
|
} |
||||
|
|
||||
|
this.drop.emit(files); |
||||
|
|
||||
|
this.stopEvent(event); |
||||
|
} |
||||
|
|
||||
|
private stopEvent(event: Event) { |
||||
|
event.preventDefault(); |
||||
|
event.stopPropagation(); |
||||
|
} |
||||
|
|
||||
|
private tryStopEvent(event: DragDropEvent) { |
||||
|
const hasFiles = this.hasFiles(event.dataTransfer.types); |
||||
|
|
||||
|
if (!hasFiles) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.stopEvent(event); |
||||
|
} |
||||
|
|
||||
|
private hasFiles(types: any): boolean { |
||||
|
if (!types) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (isFunction(types.indexOf)) { |
||||
|
return types.indexOf('Files') !== -1; |
||||
|
} else if (isFunction(types.contains)) { |
||||
|
return types.contains('Files'); |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function isFunction(obj: any): boolean { |
||||
|
return !!(obj && obj.constructor && obj.call && obj.apply); |
||||
|
}; |
||||
|
|
||||
|
interface DragDropEvent extends MouseEvent { |
||||
|
readonly dataTransfer: DataTransfer; |
||||
|
} |
||||
@ -0,0 +1,93 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AssetCommandHandlerTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Squidex.Write.Assets.Commands; |
||||
|
using Squidex.Write.TestHelpers; |
||||
|
using Xunit; |
||||
|
|
||||
|
// ReSharper disable ConvertToConstant.Local
|
||||
|
|
||||
|
namespace Squidex.Write.Assets |
||||
|
{ |
||||
|
public class AssetCommandHandlerTests : HandlerTestBase<AssetDomainObject> |
||||
|
{ |
||||
|
private readonly AssetCommandHandler sut; |
||||
|
private readonly AssetDomainObject asset; |
||||
|
private readonly Guid assetId = Guid.NewGuid(); |
||||
|
private readonly string fileName = "my-image.png"; |
||||
|
private readonly string mimeType = "image/png"; |
||||
|
private readonly long fileSize = 1024; |
||||
|
|
||||
|
public AssetCommandHandlerTests() |
||||
|
{ |
||||
|
asset = new AssetDomainObject(assetId, 0); |
||||
|
|
||||
|
sut = new AssetCommandHandler(Handler); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Create_should_create_asset() |
||||
|
{ |
||||
|
var context = CreateContextForCommand(new CreateAsset { AssetId = assetId, FileName = fileName, FileSize = fileSize, MimeType = mimeType }); |
||||
|
|
||||
|
await TestCreate(asset, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
Assert.Equal(assetId, context.Result<EntityCreatedResult<Guid>>().IdOrValue); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Update_should_update_domain_object() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new UpdateAsset { AssetId = assetId, FileSize = fileSize, MimeType = mimeType }); |
||||
|
|
||||
|
await TestUpdate(asset, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Rename_should_update_domain_object() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new RenameAsset { AssetId = assetId, FileName = "my-new-image.png" }); |
||||
|
|
||||
|
await TestUpdate(asset, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Delete_should_update_domain_object() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
var command = CreateContextForCommand(new DeleteAsset { AssetId = assetId }); |
||||
|
|
||||
|
await TestUpdate(asset, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(command); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void CreateAsset() |
||||
|
{ |
||||
|
asset.Create(new CreateAsset { FileName = fileName, FileSize = fileSize, MimeType = mimeType }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,211 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AssetDomainObjectTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Squidex.Events.Assets; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS; |
||||
|
using Squidex.Write.Assets.Commands; |
||||
|
using Squidex.Write.TestHelpers; |
||||
|
using Xunit; |
||||
|
|
||||
|
// ReSharper disable ConvertToConstant.Local
|
||||
|
|
||||
|
namespace Squidex.Write.Assets |
||||
|
{ |
||||
|
public class AssetDomainObjectTests : HandlerTestBase<AssetDomainObject> |
||||
|
{ |
||||
|
private readonly AssetDomainObject sut; |
||||
|
private readonly string fileName = "my-image.png"; |
||||
|
private readonly string mimeType = "image/png"; |
||||
|
private readonly long fileSize = 1024; |
||||
|
|
||||
|
public Guid AssetId { get; } = Guid.NewGuid(); |
||||
|
|
||||
|
public AssetDomainObjectTests() |
||||
|
{ |
||||
|
sut = new AssetDomainObject(AssetId, 0); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_throw_if_created() |
||||
|
{ |
||||
|
sut.Create(new CreateAsset { FileName = fileName, FileSize = fileSize, MimeType = mimeType }); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Create(CreateAssetCommand(new CreateAsset { FileName = fileName, FileSize = fileSize, MimeType = mimeType })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_create_events() |
||||
|
{ |
||||
|
sut.Create(CreateAssetCommand(new CreateAsset { FileName = fileName, FileSize = fileSize, MimeType = mimeType })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateAssetEvent(new AssetCreated { FileName = fileName, FileSize = fileSize, MimeType = mimeType }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateAssetCommand(new UpdateAsset { FileSize = fileSize, MimeType = mimeType })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_if_asset_is_deleted() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
DeleteAsset(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateAssetCommand(new UpdateAsset())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_create_events() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
sut.Update(CreateAssetCommand(new UpdateAsset { FileSize = fileSize, MimeType = mimeType })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateAssetEvent(new AssetUpdated { FileSize = fileSize, MimeType = mimeType }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Rename_should_throw_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateAssetCommand(new UpdateAsset { FileSize = fileSize, MimeType = mimeType })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Rename_should_throw_if_asset_is_deleted() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
DeleteAsset(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateAssetCommand(new UpdateAsset())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Rename_should_throw_if_command_is_not_valid() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => |
||||
|
{ |
||||
|
sut.Rename(CreateAssetCommand(new RenameAsset())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Rename_should_throw_if_new_name_is_equal_to_old_name() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => |
||||
|
{ |
||||
|
sut.Rename(CreateAssetCommand(new RenameAsset { FileName = fileName })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Rename_should_create_events() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
sut.Rename(CreateAssetCommand(new RenameAsset { FileName = "my-new-image.png" })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateAssetEvent(new AssetRenamed { FileName = "my-new-image.png" }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_throw_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Delete(CreateAssetCommand(new DeleteAsset())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_throw_if_already_deleted() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
DeleteAsset(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Delete(CreateAssetCommand(new DeleteAsset())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_update_properties_create_events() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
sut.Delete(CreateAssetCommand(new DeleteAsset())); |
||||
|
|
||||
|
Assert.True(sut.IsDeleted); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateAssetEvent(new AssetDeleted()) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private void CreateAsset() |
||||
|
{ |
||||
|
sut.Create(CreateAssetCommand(new CreateAsset { FileName = fileName, FileSize = fileSize, MimeType = mimeType })); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
private void DeleteAsset() |
||||
|
{ |
||||
|
sut.Delete(CreateAssetCommand(new DeleteAsset())); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
protected T CreateAssetEvent<T>(T @event) where T : AssetEvent |
||||
|
{ |
||||
|
@event.AssetId = AssetId; |
||||
|
|
||||
|
return CreateEvent(@event); |
||||
|
} |
||||
|
|
||||
|
protected T CreateAssetCommand<T>(T command) where T : AssetAggregateCommand |
||||
|
{ |
||||
|
command.AssetId = AssetId; |
||||
|
|
||||
|
return CreateCommand(command); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue