mirror of https://github.com/Squidex/squidex.git
32 changed files with 939 additions and 91 deletions
@ -0,0 +1,99 @@ |
|||
// ==========================================================================
|
|||
// MongoContentEntity.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Linq; |
|||
using System.Text; |
|||
using MongoDB.Bson; |
|||
using MongoDB.Bson.Serialization.Attributes; |
|||
using Newtonsoft.Json; |
|||
using Newtonsoft.Json.Linq; |
|||
using Squidex.Core.Contents; |
|||
using Squidex.Infrastructure.MongoDb; |
|||
using Squidex.Read.Contents; |
|||
// ReSharper disable InvertIf
|
|||
|
|||
namespace Squidex.Store.MongoDb.Contents |
|||
{ |
|||
public sealed class MongoContentEntity : MongoEntity, IContentEntity |
|||
{ |
|||
private BsonDocument data; |
|||
private ContentData contentData; |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public bool IsDeleted { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public bool IsPublished { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public string Text { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public BsonDocument Data |
|||
{ |
|||
get { return data; } |
|||
set |
|||
{ |
|||
data = value; |
|||
|
|||
contentData = null; |
|||
} |
|||
} |
|||
|
|||
ContentData IContentEntity.Data |
|||
{ |
|||
get |
|||
{ |
|||
if (contentData == null) |
|||
{ |
|||
if (data != null) |
|||
{ |
|||
contentData = JsonConvert.DeserializeObject<ContentData>(data.ToJson()); |
|||
} |
|||
} |
|||
|
|||
return contentData; |
|||
} |
|||
} |
|||
|
|||
public void SetData(ContentData newContentData) |
|||
{ |
|||
data = null; |
|||
|
|||
if (newContentData != null) |
|||
{ |
|||
data = BsonDocument.Parse(JsonConvert.SerializeObject(newContentData)); |
|||
} |
|||
|
|||
Text = ExtractText(newContentData); |
|||
} |
|||
|
|||
private static string ExtractText(ContentData data) |
|||
{ |
|||
if (data == null) |
|||
{ |
|||
return string.Empty; |
|||
} |
|||
var stringBuilder = new StringBuilder(); |
|||
|
|||
foreach (var text in data.Fields.Values.SelectMany(x => x.ValueByLanguage.Values).Where(x => x != null).OfType<JValue>()) |
|||
{ |
|||
if (text.Type == JTokenType.String) |
|||
{ |
|||
stringBuilder.Append(text); |
|||
} |
|||
} |
|||
|
|||
return stringBuilder.ToString(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,214 @@ |
|||
// ==========================================================================
|
|||
// MongoContentRepository.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Driver; |
|||
using Squidex.Events; |
|||
using Squidex.Events.Contents; |
|||
using Squidex.Events.Schemas; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.CQRS; |
|||
using Squidex.Infrastructure.CQRS.Events; |
|||
using Squidex.Infrastructure.CQRS.Replay; |
|||
using Squidex.Infrastructure.Dispatching; |
|||
using Squidex.Infrastructure.Reflection; |
|||
using Squidex.Read.Contents; |
|||
using Squidex.Read.Contents.Repositories; |
|||
using Squidex.Store.MongoDb.Utils; |
|||
|
|||
namespace Squidex.Store.MongoDb.Contents |
|||
{ |
|||
public class MongoContentRepository : IContentRepository, ICatchEventConsumer, IReplayableStore |
|||
{ |
|||
private const string Prefix = "Projections_Content_"; |
|||
private readonly IMongoDatabase database; |
|||
|
|||
protected ProjectionDefinitionBuilder<MongoContentEntity> Projection |
|||
{ |
|||
get |
|||
{ |
|||
return Builders<MongoContentEntity>.Projection; |
|||
} |
|||
} |
|||
|
|||
protected SortDefinitionBuilder<MongoContentEntity> Sort |
|||
{ |
|||
get |
|||
{ |
|||
return Builders<MongoContentEntity>.Sort; |
|||
} |
|||
} |
|||
|
|||
protected UpdateDefinitionBuilder<MongoContentEntity> Update |
|||
{ |
|||
get |
|||
{ |
|||
return Builders<MongoContentEntity>.Update; |
|||
} |
|||
} |
|||
|
|||
protected FilterDefinitionBuilder<MongoContentEntity> Filter |
|||
{ |
|||
get |
|||
{ |
|||
return Builders<MongoContentEntity>.Filter; |
|||
} |
|||
} |
|||
|
|||
protected IndexKeysDefinitionBuilder<MongoContentEntity> IndexKeys |
|||
{ |
|||
get |
|||
{ |
|||
return Builders<MongoContentEntity>.IndexKeys; |
|||
} |
|||
} |
|||
|
|||
public MongoContentRepository(IMongoDatabase database) |
|||
{ |
|||
Guard.NotNull(database, nameof(database)); |
|||
|
|||
this.database = database; |
|||
} |
|||
|
|||
public async Task ClearAsync() |
|||
{ |
|||
using (var collections = await database.ListCollectionsAsync()) |
|||
{ |
|||
while (await collections.MoveNextAsync()) |
|||
{ |
|||
foreach (var collection in collections.Current) |
|||
{ |
|||
var name = collection["name"].ToString(); |
|||
|
|||
if (name.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase)) |
|||
{ |
|||
await database.DropCollectionAsync(name); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public async Task<List<IContentEntity>> QueryAsync(Guid schemaId, bool nonPublished, int? take, int? skip, string query) |
|||
{ |
|||
var cursor = BuildQuery(schemaId, nonPublished, query); |
|||
|
|||
if (take.HasValue) |
|||
{ |
|||
cursor.Limit(take.Value); |
|||
} |
|||
|
|||
if (skip.HasValue) |
|||
{ |
|||
cursor.Skip(skip.Value); |
|||
} |
|||
|
|||
cursor.SortByDescending(x => x.LastModified); |
|||
|
|||
var entities = |
|||
await cursor.ToListAsync(); |
|||
|
|||
return entities.OfType<IContentEntity>().ToList(); |
|||
} |
|||
|
|||
public Task<long> CountAsync(Guid schemaId, bool nonPublished, string query) |
|||
{ |
|||
var cursor = BuildQuery(schemaId, nonPublished, query); |
|||
|
|||
return cursor.CountAsync(); |
|||
} |
|||
|
|||
private IFindFluent<MongoContentEntity, MongoContentEntity> BuildQuery(Guid schemaId, bool nonPublished, string query) |
|||
{ |
|||
var filters = new List<FilterDefinition<MongoContentEntity>> |
|||
{ |
|||
Filter.Eq(x => x.IsDeleted, false) |
|||
}; |
|||
|
|||
if (!string.IsNullOrWhiteSpace(query)) |
|||
{ |
|||
filters.Add(Filter.Text(query, "en")); |
|||
} |
|||
|
|||
if (!nonPublished) |
|||
{ |
|||
filters.Add(Filter.Eq(x => x.IsPublished, false)); |
|||
} |
|||
|
|||
var collection = GetCollection(schemaId); |
|||
|
|||
var cursor = collection.Find(Filter.And(filters)); |
|||
|
|||
return cursor; |
|||
} |
|||
|
|||
public async Task<IContentEntity> FindContentAsync(Guid schemaId, Guid id) |
|||
{ |
|||
var collection = GetCollection(schemaId); |
|||
|
|||
var entity = |
|||
await collection.Find(x => x.Id == id).FirstOrDefaultAsync(); |
|||
|
|||
return entity; |
|||
} |
|||
|
|||
protected Task On(ContentCreated @event, EnvelopeHeaders headers) |
|||
{ |
|||
var collection = GetCollection(headers.SchemaId()); |
|||
|
|||
return collection.CreateAsync(headers, x => |
|||
{ |
|||
SimpleMapper.Map(@event, x); |
|||
|
|||
x.SetData(@event.Data); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(ContentUpdated @event, EnvelopeHeaders headers) |
|||
{ |
|||
var collection = GetCollection(headers.SchemaId()); |
|||
|
|||
return collection.UpdateAsync(headers, x => |
|||
{ |
|||
x.SetData(@event.Data); |
|||
}); |
|||
} |
|||
|
|||
protected Task On(ContentDeleted @event, EnvelopeHeaders headers) |
|||
{ |
|||
var collection = GetCollection(headers.SchemaId()); |
|||
|
|||
return collection.UpdateAsync(headers, x => |
|||
{ |
|||
x.IsDeleted = true; |
|||
}); |
|||
} |
|||
|
|||
protected Task On(SchemaCreated @event, EnvelopeHeaders headers) |
|||
{ |
|||
var collection = GetCollection(headers.AggregateId()); |
|||
|
|||
return collection.Indexes.CreateOneAsync(IndexKeys.Ascending(x => x.IsPublished).Text(x => x.Text)); |
|||
} |
|||
|
|||
public Task On(Envelope<IEvent> @event) |
|||
{ |
|||
return this.DispatchActionAsync(@event.Payload, @event.Headers); |
|||
} |
|||
|
|||
private IMongoCollection<MongoContentEntity> GetCollection(Guid schemaId) |
|||
{ |
|||
var name = $"{Prefix}{schemaId}"; |
|||
|
|||
return database.GetCollection<MongoContentEntity>(name); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
// ==========================================================================
|
|||
// EnrichWithSchemaIdProcessor.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using Squidex.Events; |
|||
using Squidex.Infrastructure.CQRS; |
|||
using Squidex.Infrastructure.CQRS.Commands; |
|||
using Squidex.Infrastructure.CQRS.Events; |
|||
using Squidex.Infrastructure.Tasks; |
|||
using Squidex.Write.Schemas; |
|||
|
|||
namespace Squidex.Write |
|||
{ |
|||
public sealed class EnrichWithSchemaIdProcessor : IEventProcessor |
|||
{ |
|||
public Task ProcessEventAsync(Envelope<IEvent> @event, IAggregate aggregate, ICommand command) |
|||
{ |
|||
var schemaDomainObject = aggregate as SchemaDomainObject; |
|||
|
|||
if (schemaDomainObject != null) |
|||
{ |
|||
@event.SetSchemaId(aggregate.Id); |
|||
} |
|||
else |
|||
{ |
|||
var schemaCommand = command as ISchemaCommand; |
|||
|
|||
if (schemaCommand != null) |
|||
{ |
|||
@event.SetSchemaId(schemaCommand.SchemaId); |
|||
} |
|||
} |
|||
|
|||
return TaskHelper.Done; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,140 @@ |
|||
// ==========================================================================
|
|||
// ContentsController.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Newtonsoft.Json.Linq; |
|||
using Squidex.Controllers.Api; |
|||
using Squidex.Controllers.ContentApi.Models; |
|||
using Squidex.Core.Contents; |
|||
using Squidex.Infrastructure.CQRS.Commands; |
|||
using Squidex.Infrastructure.Reflection; |
|||
using Squidex.Pipeline; |
|||
using Squidex.Read.Contents.Repositories; |
|||
using Squidex.Read.Schemas.Services; |
|||
using Squidex.Write.Contents.Commands; |
|||
|
|||
namespace Squidex.Controllers.ContentApi |
|||
{ |
|||
[Authorize(Roles = "app-editor,app-owner,app-developer")] |
|||
[ApiExceptionFilter] |
|||
[ServiceFilter(typeof(AppFilterAttribute))] |
|||
public class ContentsController : ControllerBase |
|||
{ |
|||
private readonly ISchemaProvider schemaProvider; |
|||
private readonly IContentRepository contentRepository; |
|||
|
|||
public ContentsController(ICommandBus commandBus, ISchemaProvider schemaProvider, IContentRepository contentRepository) |
|||
: base(commandBus) |
|||
{ |
|||
this.schemaProvider = schemaProvider; |
|||
this.contentRepository = contentRepository; |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("content/{app}/{name}")] |
|||
public async Task<IActionResult> GetContents(string name, [FromQuery] string query = null, [FromQuery] int? take = null, [FromQuery] int? skip = null, [FromQuery] bool nonPublished = false) |
|||
{ |
|||
var schemaEntity = await schemaProvider.FindSchemaByNameAsync(AppId, name); |
|||
|
|||
if (schemaEntity == null) |
|||
{ |
|||
return NotFound(); |
|||
} |
|||
|
|||
var taskForContents = contentRepository.QueryAsync(schemaEntity.Id, nonPublished, take, skip, query); |
|||
var taskForCount = contentRepository.CountAsync(schemaEntity.Id, nonPublished, query); |
|||
|
|||
await Task.WhenAll(taskForContents, taskForCount); |
|||
|
|||
var model = new ContentsDto |
|||
{ |
|||
Total = taskForCount.Result, |
|||
Items = taskForContents.Result.Select(x => |
|||
{ |
|||
var itemModel = SimpleMapper.Map(x, new ContentDto()); |
|||
|
|||
if (x.Data != null) |
|||
{ |
|||
itemModel.Data = x.Data.ToRaw(); |
|||
} |
|||
|
|||
return itemModel; |
|||
}).ToArray() |
|||
}; |
|||
|
|||
return Ok(model); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("content/{app}/{name}/{id}")] |
|||
public async Task<IActionResult> GetContent(string name, Guid id) |
|||
{ |
|||
var schemaEntity = await schemaProvider.FindSchemaByNameAsync(AppId, name); |
|||
|
|||
if (schemaEntity == null) |
|||
{ |
|||
return NotFound(); |
|||
} |
|||
|
|||
var content = await contentRepository.FindContentAsync(schemaEntity.Id, id); |
|||
|
|||
if (content == null) |
|||
{ |
|||
return NotFound(); |
|||
} |
|||
|
|||
var model = SimpleMapper.Map(content, new ContentDto()); |
|||
|
|||
if (content.Data != null) |
|||
{ |
|||
model.Data = content.Data.ToRaw(); |
|||
} |
|||
|
|||
return Ok(model); |
|||
} |
|||
|
|||
[HttpPost] |
|||
[Route("content/{app}/{name}/")] |
|||
public async Task<IActionResult> PostContent([FromBody] Dictionary<string, Dictionary<string, JToken>> request) |
|||
{ |
|||
var command = new CreateContent { Data = ContentData.Create(request), AggregateId = Guid.NewGuid() }; |
|||
|
|||
var context = await CommandBus.PublishAsync(command); |
|||
var result = context.Result<Guid>(); |
|||
|
|||
return CreatedAtAction(nameof(GetContent), new { id = result }, new EntityCreatedDto { Id = result.ToString() }); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("content/{app}/{name}/{id}")] |
|||
public async Task<IActionResult> PutContent(Guid id, [FromBody] Dictionary<string, Dictionary<string, JToken>> request) |
|||
{ |
|||
var command = new UpdateContent { AggregateId = id, Data = ContentData.Create(request) }; |
|||
|
|||
await CommandBus.PublishAsync(command); |
|||
|
|||
return NoContent(); |
|||
} |
|||
|
|||
[HttpDelete] |
|||
[Route("content/{app}/{name}/{id}")] |
|||
public async Task<IActionResult> PutContent(Guid id) |
|||
{ |
|||
var command = new DeleteContent { AggregateId = id }; |
|||
|
|||
await CommandBus.PublishAsync(command); |
|||
|
|||
return NoContent(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
// ==========================================================================
|
|||
// ContentsDto.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
namespace Squidex.Controllers.ContentApi.Models |
|||
{ |
|||
public class ContentsDto |
|||
{ |
|||
/// <summary>
|
|||
/// The total number of content items.
|
|||
/// </summary>
|
|||
public long Total { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// The content items.
|
|||
/// </summary>
|
|||
public ContentDto[] Items { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,106 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Injectable } from '@angular/core'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import 'framework/angular/http-extensions'; |
|||
|
|||
import { |
|||
ApiUrlConfig, |
|||
DateTime, |
|||
EntityCreatedDto |
|||
} from 'framework'; |
|||
|
|||
import { AuthService } from './auth.service'; |
|||
|
|||
export class ContentDto { |
|||
constructor( |
|||
public readonly id: string, |
|||
public readonly isPublished: boolean, |
|||
public readonly createdBy: string, |
|||
public readonly lastModifiedBy: string, |
|||
public readonly created: DateTime, |
|||
public readonly lastModified: DateTime, |
|||
public readonly data: any |
|||
) { |
|||
} |
|||
} |
|||
|
|||
@Injectable() |
|||
export class ContentsService { |
|||
constructor( |
|||
private readonly authService: AuthService, |
|||
private readonly apiUrl: ApiUrlConfig |
|||
) { |
|||
} |
|||
|
|||
public getContents(appName: string, schemaName: string, take: number, skip: number, query: string): Observable<ContentDto[]> { |
|||
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/?query=${query}&take=${take}&skip=${skip}&query=${query}&nonPublished=true`); |
|||
|
|||
return this.authService.authGet(url) |
|||
.map(response => response.json()) |
|||
.map(response => { |
|||
const items: any[] = response; |
|||
|
|||
return items.map(item => { |
|||
return new ContentDto( |
|||
item.id, |
|||
item.isPublished, |
|||
item.createdBy, |
|||
item.lastModifiedBy, |
|||
DateTime.parseISO(item.created), |
|||
DateTime.parseISO(item.lastModified), |
|||
item.data); |
|||
}); |
|||
}) |
|||
.catchError('Failed to load contents. Please reload.'); |
|||
} |
|||
|
|||
public getContent(appName: string, schemaName: string, id: string): Observable<ContentDto> { |
|||
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/`); |
|||
|
|||
return this.authService.authGet(url) |
|||
.map(response => response.json()) |
|||
.map(response => { |
|||
return new ContentDto( |
|||
response.id, |
|||
response.isPublished, |
|||
response.createdBy, |
|||
response.lastModifiedBy, |
|||
DateTime.parseISO(response.created), |
|||
DateTime.parseISO(response.lastModified), |
|||
response.data); |
|||
}) |
|||
.catchError('Failed to load content. Please reload.'); |
|||
} |
|||
|
|||
public postContent(appName: string, schemaName: string, dto: any): Observable<EntityCreatedDto> { |
|||
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/`); |
|||
|
|||
return this.authService.authPost(url, dto) |
|||
.map(response => response.json()) |
|||
.map(response => { |
|||
return new EntityCreatedDto(response.id); |
|||
}) |
|||
.catchError('Failed to create content. Please reload.'); |
|||
} |
|||
|
|||
public putContent(appName: string, schemaName: string, id: string, dto: any): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/`); |
|||
|
|||
return this.authService.authPut(url, dto) |
|||
.catchError('Failed to update Content. Please reload.'); |
|||
} |
|||
|
|||
public deleteContent(appName: string, schemaName: string, id: string, dto: any): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/`); |
|||
|
|||
return this.authService.authDelete(url, dto) |
|||
.catchError('Failed to delete Content. Please reload.'); |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
// ==========================================================================
|
|||
// ContentDataTests.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using FluentAssertions; |
|||
using Newtonsoft.Json.Linq; |
|||
using Xunit; |
|||
|
|||
namespace Squidex.Core.Contents |
|||
{ |
|||
public class ContentDataTests |
|||
{ |
|||
[Fact] |
|||
public void Should_convert_from_dictionary() |
|||
{ |
|||
var input = |
|||
new Dictionary<string, Dictionary<string, JToken>> |
|||
{ |
|||
["field1"] = new Dictionary<string, JToken> |
|||
{ |
|||
["en"] = "en_string", |
|||
["de"] = "de_string" |
|||
}, |
|||
["field2"] = new Dictionary<string, JToken> |
|||
{ |
|||
["en"] = 1, |
|||
["de"] = 2 |
|||
} |
|||
}; |
|||
|
|||
var actual = ContentData.Create(input); |
|||
|
|||
var expected = |
|||
ContentData.Empty |
|||
.AddField("field1", |
|||
ContentFieldData.Empty |
|||
.AddValue("en", "en_string") |
|||
.AddValue("de", "de_string")) |
|||
.AddField("field2", |
|||
ContentFieldData.Empty |
|||
.AddValue("en", 1) |
|||
.AddValue("de", 2)); |
|||
|
|||
var output = actual.ToRaw(); |
|||
|
|||
actual.ShouldBeEquivalentTo(expected); |
|||
output.ShouldBeEquivalentTo(input); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
// ==========================================================================
|
|||
// EnrichWithSchemaIdProcessorTests.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Core.Schemas; |
|||
using Squidex.Events; |
|||
using Squidex.Infrastructure.CQRS; |
|||
using Squidex.Infrastructure.CQRS.Commands; |
|||
using Squidex.Infrastructure.CQRS.Events; |
|||
using Squidex.Write.Schemas; |
|||
using Xunit; |
|||
|
|||
namespace Squidex.Write |
|||
{ |
|||
public class EnrichWithSchemaIdProcessorTests |
|||
{ |
|||
public sealed class MySchemaCommand : SchemaAggregateCommand |
|||
{ |
|||
} |
|||
|
|||
public sealed class MyNormalCommand : ICommand |
|||
{ |
|||
} |
|||
|
|||
public sealed class MyEvent : IEvent |
|||
{ |
|||
} |
|||
|
|||
private readonly EnrichWithSchemaIdProcessor sut = new EnrichWithSchemaIdProcessor(); |
|||
|
|||
[Fact] |
|||
public async Task Should_not_do_anything_if_not_app_command() |
|||
{ |
|||
var envelope = new Envelope<IEvent>(new MyEvent()); |
|||
|
|||
await sut.ProcessEventAsync(envelope, null, new MyNormalCommand()); |
|||
|
|||
Assert.False(envelope.Headers.Contains("SchemaId")); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_attach_app_id_from_domain_object() |
|||
{ |
|||
var appId = Guid.NewGuid(); |
|||
|
|||
var envelope = new Envelope<IEvent>(new MyEvent()); |
|||
|
|||
await sut.ProcessEventAsync(envelope, new SchemaDomainObject(appId, 1, new FieldRegistry()), new MyNormalCommand()); |
|||
|
|||
Assert.Equal(appId, envelope.Headers.SchemaId()); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_attach_app_id_to_event_envelope() |
|||
{ |
|||
var appId = Guid.NewGuid(); |
|||
var appCommand = new MySchemaCommand { AggregateId = appId }; |
|||
|
|||
var envelope = new Envelope<IEvent>(new MyEvent()); |
|||
|
|||
await sut.ProcessEventAsync(envelope, null, appCommand); |
|||
|
|||
Assert.Equal(appId, envelope.Headers.SchemaId()); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue