Browse Source

Merge branch 'master' into orleans3

# Conflicts:
#	src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs
#	src/Squidex.Infrastructure/Commands/DomainObjectBase.cs
pull/249/head
Sebastian Stehle 8 years ago
parent
commit
fb7c8ce139
  1. 6
      README.md
  2. 26
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidationExtensions.cs
  3. 6
      src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs
  4. 81
      src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs
  5. 2
      src/Squidex/Pipeline/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs
  6. 2
      src/Squidex/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs
  7. 9
      src/Squidex/app/framework/angular/date-time-editor.component.ts

6
README.md

@ -4,7 +4,7 @@
Squidex is an open source headless CMS and content management hub. In contrast to a traditional CMS Squidex provides a rich API with OData filter and Swagger definitions. It is up to you to build your UI on top of it. It can be website, a native app or just another server. We build it with ASP.NET Core and CQRS and is tested for Windows and Linux on modern browsers. Squidex is an open source headless CMS and content management hub. In contrast to a traditional CMS Squidex provides a rich API with OData filter and Swagger definitions. It is up to you to build your UI on top of it. It can be website, a native app or just another server. We build it with ASP.NET Core and CQRS and is tested for Windows and Linux on modern browsers.
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=square)](https://gitter.im/squidex-cms/Lobby) [![Slack](https://img.shields.io/badge/chat-on_slack-E01765.svg?style=square)](https://squidex-slack.herokuapp.com/) [![Build Status](http://build.squidex.io/api/badges/Squidex/squidex/status.svg)](http://build.squidex.io/Squidex/squidex) [![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg?style=square)](https://gitter.im/squidex-cms/Lobby) [![Slack](https://img.shields.io/badge/chat-on_slack-E01765.svg?style=square)](https://squidex-slack.herokuapp.com/) [![Build Status](http://build.squidex.io/api/badges/Squidex/squidex/status.svg)](http://build.squidex.io/Squidex/squidex) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FSquidex%2Fsquidex.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2FSquidex%2Fsquidex?ref=badge_shield)
Read the docs at [https://docs.squidex.io/](https://docs.squidex.io/) (work in progress) or just check out the code and play around. Read the docs at [https://docs.squidex.io/](https://docs.squidex.io/) (work in progress) or just check out the code and play around.
@ -40,3 +40,7 @@ Please create issues to report bugs, suggest new functionalities, ask questions
## Cloud Version ## Cloud Version
Although Squidex is free we are also working on a Saas version on [https://cloud.squidex.io](https://cloud.squidex.io) (More information coming soon). We have also have plans to sell a premium version with first class support and some exlusive features. But don't be afraid, our first priority is to deliver a state of the art, stable, fast and free content management hub to make the life for developers a little bit easier. Although Squidex is free we are also working on a Saas version on [https://cloud.squidex.io](https://cloud.squidex.io) (More information coming soon). We have also have plans to sell a premium version with first class support and some exlusive features. But don't be afraid, our first priority is to deliver a state of the art, stable, fast and free content management hub to make the life for developers a little bit easier.
## License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FSquidex%2Fsquidex.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FSquidex%2Fsquidex?ref=badge_large)

26
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidationExtensions.cs

@ -5,7 +5,9 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
@ -27,6 +29,18 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
} }
} }
public static async Task ValidateAsync(this NamedContentData data, ValidationContext context, Schema schema, PartitionResolver partitionResolver, Func<string> message)
{
var validator = new ContentValidator(schema, partitionResolver, context);
await validator.ValidateAsync(data);
if (validator.Errors.Count > 0)
{
throw new ValidationException(message(), validator.Errors.ToList());
}
}
public static async Task ValidatePartialAsync(this NamedContentData data, ValidationContext context, Schema schema, PartitionResolver partitionResolver, IList<ValidationError> errors) public static async Task ValidatePartialAsync(this NamedContentData data, ValidationContext context, Schema schema, PartitionResolver partitionResolver, IList<ValidationError> errors)
{ {
var validator = new ContentValidator(schema, partitionResolver, context); var validator = new ContentValidator(schema, partitionResolver, context);
@ -38,5 +52,17 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
errors.Add(error); errors.Add(error);
} }
} }
public static async Task ValidatePartialAsync(this NamedContentData data, ValidationContext context, Schema schema, PartitionResolver partitionResolver, Func<string> message)
{
var validator = new ContentValidator(schema, partitionResolver, context);
await validator.ValidatePartialAsync(data);
if (validator.Errors.Count > 0)
{
throw new ValidationException(message(), validator.Errors.ToList());
}
}
} }
} }

6
src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs

@ -91,7 +91,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
await operationContext.ExecuteScriptAndTransformAsync(x => x.ScriptCreate, "Create"); await operationContext.ExecuteScriptAndTransformAsync(x => x.ScriptCreate, "Create");
await operationContext.EnrichAsync(); await operationContext.EnrichAsync();
await operationContext.ValidateAsync(false); await operationContext.ValidateAsync();
Create(c); Create(c);
@ -105,7 +105,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
var operationContext = await CreateContext(c, () => "Failed to update content."); var operationContext = await CreateContext(c, () => "Failed to update content.");
await operationContext.ValidateAsync(true); await operationContext.ValidateAsync();
await operationContext.ExecuteScriptAndTransformAsync(x => x.ScriptUpdate, "Update"); await operationContext.ExecuteScriptAndTransformAsync(x => x.ScriptUpdate, "Update");
Update(c); Update(c);
@ -120,7 +120,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
var operationContext = await CreateContext(c, () => "Failed to patch content."); var operationContext = await CreateContext(c, () => "Failed to patch content.");
await operationContext.ValidateAsync(true); await operationContext.ValidatePartialAsync();
await operationContext.ExecuteScriptAndTransformAsync(x => x.ScriptUpdate, "Patch"); await operationContext.ExecuteScriptAndTransformAsync(x => x.ScriptUpdate, "Patch");
Patch(c); Patch(c);

81
src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs

@ -9,6 +9,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.EnrichContent; using Squidex.Domain.Apps.Core.EnrichContent;
using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Domain.Apps.Core.ValidateContent;
@ -17,7 +18,6 @@ using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
namespace Squidex.Domain.Apps.Entities.Contents namespace Squidex.Domain.Apps.Entities.Contents
@ -31,6 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
private IScriptEngine scriptEngine; private IScriptEngine scriptEngine;
private ISchemaEntity schemaEntity; private ISchemaEntity schemaEntity;
private IAppEntity appEntity; private IAppEntity appEntity;
private Guid appId;
private Func<string> message; private Func<string> message;
public static async Task<ContentOperationContext> CreateAsync( public static async Task<ContentOperationContext> CreateAsync(
@ -56,6 +57,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
var context = new ContentOperationContext var context = new ContentOperationContext
{ {
appEntity = appEntity, appEntity = appEntity,
appId = a.Id,
assetRepository = assetRepository, assetRepository = assetRepository,
contentRepository = contentRepository, contentRepository = contentRepository,
content = content, content = content,
@ -78,54 +80,35 @@ namespace Squidex.Domain.Apps.Entities.Contents
return TaskHelper.Done; return TaskHelper.Done;
} }
public async Task ValidateAsync(bool partial) public Task ValidateAsync()
{ {
if (command is ContentDataCommand dataCommand) if (command is ContentDataCommand dataCommand)
{ {
var errors = new List<ValidationError>(); var ctx = CreateValidationContext();
var ctx =
new ValidationContext(
(contentIds, schemaId) =>
{
return QueryContentsAsync(content.AppId.Id, schemaId, contentIds);
},
assetIds =>
{
return QueryAssetsAsync(content.AppId.Id, assetIds);
});
if (partial)
{
await dataCommand.Data.ValidatePartialAsync(ctx, schemaEntity.SchemaDef, appEntity.PartitionResolver(), errors);
}
else
{
await dataCommand.Data.ValidateAsync(ctx, schemaEntity.SchemaDef, appEntity.PartitionResolver(), errors);
}
if (errors.Count > 0) return dataCommand.Data.ValidateAsync(ctx, schemaEntity.SchemaDef, appEntity.PartitionResolver(), message);
{
throw new ValidationException(message(), errors.ToArray());
}
} }
}
private async Task<IReadOnlyList<IAssetInfo>> QueryAssetsAsync(Guid appId, IEnumerable<Guid> assetIds) return TaskHelper.Done;
{
return await assetRepository.QueryAsync(appId, new HashSet<Guid>(assetIds));
} }
private async Task<IReadOnlyList<Guid>> QueryContentsAsync(Guid appId, Guid schemaId, IEnumerable<Guid> contentIds) public Task ValidatePartialAsync()
{ {
return await contentRepository.QueryNotFoundAsync(appId, schemaId, contentIds.ToList()); if (command is ContentDataCommand dataCommand)
{
var ctx = CreateValidationContext();
return dataCommand.Data.ValidatePartialAsync(ctx, schemaEntity.SchemaDef, appEntity.PartitionResolver(), message);
}
return TaskHelper.Done;
} }
public Task ExecuteScriptAndTransformAsync(Func<ISchemaEntity, string> script, object operation) public Task ExecuteScriptAndTransformAsync(Func<ISchemaEntity, string> script, object operation)
{ {
if (command is ContentDataCommand dataCommand) if (command is ContentDataCommand dataCommand)
{ {
var ctx = new ScriptContext { ContentId = content.Id, OldData = content.Data, User = command.User, Operation = operation.ToString(), Data = dataCommand.Data }; var ctx = CreateScriptContext(operation, dataCommand.Data);
dataCommand.Data = scriptEngine.ExecuteAndTransform(ctx, script(schemaEntity)); dataCommand.Data = scriptEngine.ExecuteAndTransform(ctx, script(schemaEntity));
} }
@ -135,11 +118,39 @@ namespace Squidex.Domain.Apps.Entities.Contents
public Task ExecuteScriptAsync(Func<ISchemaEntity, string> script, object operation) public Task ExecuteScriptAsync(Func<ISchemaEntity, string> script, object operation)
{ {
var ctx = new ScriptContext { ContentId = content.Id, OldData = content.Data, User = command.User, Operation = operation.ToString() }; var ctx = CreateScriptContext(operation, content.Data);
scriptEngine.Execute(ctx, script(schemaEntity)); scriptEngine.Execute(ctx, script(schemaEntity));
return TaskHelper.Done; return TaskHelper.Done;
} }
private ScriptContext CreateScriptContext(object operation, NamedContentData data = null)
{
return new ScriptContext { ContentId = command.ContentId, OldData = content.Data, Data = data, User = command.User, Operation = operation.ToString() };
}
private ValidationContext CreateValidationContext()
{
return new ValidationContext(
(contentIds, schemaId) =>
{
return QueryContentsAsync(schemaId, contentIds);
},
assetIds =>
{
return QueryAssetsAsync(assetIds);
});
}
private async Task<IReadOnlyList<IAssetInfo>> QueryAssetsAsync(IEnumerable<Guid> assetIds)
{
return await assetRepository.QueryAsync(appId, new HashSet<Guid>(assetIds));
}
private async Task<IReadOnlyList<Guid>> QueryContentsAsync(Guid schemaId, IEnumerable<Guid> contentIds)
{
return await contentRepository.QueryNotFoundAsync(appId, schemaId, contentIds.ToList());
}
} }
} }

2
src/Squidex/Pipeline/CommandMiddlewares/EnrichWithAppIdCommandMiddleware.cs

@ -60,4 +60,4 @@ namespace Squidex.Pipeline.CommandMiddlewares
return new NamedId<Guid>(appFeature.App.Id, appFeature.App.Name); return new NamedId<Guid>(appFeature.App.Id, appFeature.App.Name);
} }
} }
} }

2
src/Squidex/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs

@ -101,4 +101,4 @@ namespace Squidex.Pipeline.CommandMiddlewares
return null; return null;
} }
} }
} }

9
src/Squidex/app/framework/angular/date-time-editor.component.ts

@ -191,19 +191,20 @@ export class DateTimeEditorComponent implements ControlValueAccessor, OnDestroy,
} }
private updateControls() { private updateControls() {
if (!this.dateValue) {
return;
}
this.suppressEvents = true; this.suppressEvents = true;
if (this.timeValue && this.timeValue.isValid()) { if (this.timeValue && this.timeValue.isValid()) {
this.timeControl.setValue(this.timeValue.format('HH:mm:ss'), { emitEvent: false }); this.timeControl.setValue(this.timeValue.format('HH:mm:ss'), { emitEvent: false });
} else {
this.timeControl.setValue(null, { emitEvent: false });
} }
if (this.dateValue && this.dateValue.isValid() && this.picker) { if (this.dateValue && this.dateValue.isValid() && this.picker) {
this.dateControl.setValue(this.dateValue.format('YYYY-MM-DD'), { emitEvent: false }); this.dateControl.setValue(this.dateValue.format('YYYY-MM-DD'), { emitEvent: false });
this.picker.setMoment(this.dateValue); this.picker.setMoment(this.dateValue);
} else {
this.dateControl.setValue(null, { emitEvent: false });
} }
this.suppressEvents = false; this.suppressEvents = false;

Loading…
Cancel
Save