diff --git a/src/PinkParrot/Configurations/Serializers.cs b/src/PinkParrot/Configurations/Serializers.cs index cf4e1d146..4ee69921b 100644 --- a/src/PinkParrot/Configurations/Serializers.cs +++ b/src/PinkParrot/Configurations/Serializers.cs @@ -23,6 +23,7 @@ namespace PinkParrot.Configurations settings.Binder = new TypeNameSerializationBinder().Map(typeof(ModelSchema).GetTypeInfo().Assembly); settings.ContractResolver = new CamelCasePropertyNamesContractResolver(); settings.Converters.Add(new PropertiesBagConverter()); + settings.NullValueHandling = NullValueHandling.Ignore; settings.DateFormatHandling = DateFormatHandling.IsoDateFormat; settings.DateParseHandling = DateParseHandling.DateTime; settings.TypeNameHandling = TypeNameHandling.Auto; diff --git a/src/PinkParrot/Configurations/Swagger.cs b/src/PinkParrot/Configurations/Swagger.cs deleted file mode 100644 index 3089e1665..000000000 --- a/src/PinkParrot/Configurations/Swagger.cs +++ /dev/null @@ -1,44 +0,0 @@ -// ========================================================================== -// Swagger.cs -// PinkParrot Headless CMS -// ========================================================================== -// Copyright (c) PinkParrot Group -// All rights reserved. -// ========================================================================== - -using System.IO; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.PlatformAbstractions; -using PinkParrot.Pipeline.Swagger; -using Swashbuckle.Swagger.Model; - -namespace PinkParrot.Configurations -{ - public static class Swagger - { - public static void AddAppSwagger(this IServiceCollection services) - { - services.AddSwaggerGen(options => - { - options.SingleApiVersion(new Info { Title = "Pink Parrot", Version = "v1" }); - options.OperationFilter(); - options.OperationFilter(); - options.SchemaFilter(); - options.SchemaFilter(); - options.IncludeXmlComments(GetXmlCommentsPath(PlatformServices.Default.Application)); - }); - } - - public static void UseAppSwagger(this IApplicationBuilder app) - { - app.UseSwagger(); - app.UseSwaggerUi(); - } - - private static string GetXmlCommentsPath(ApplicationEnvironment appEnvironment) - { - return Path.Combine(appEnvironment.ApplicationBasePath, "PinkParrot.xml"); - } - } -} diff --git a/src/PinkParrot/Modules/Api/Schemas/SchemaFieldsController.cs b/src/PinkParrot/Modules/Api/Schemas/SchemaFieldsController.cs index d7eb58d81..a6026e2be 100644 --- a/src/PinkParrot/Modules/Api/Schemas/SchemaFieldsController.cs +++ b/src/PinkParrot/Modules/Api/Schemas/SchemaFieldsController.cs @@ -11,9 +11,6 @@ using Microsoft.AspNetCore.Mvc; using PinkParrot.Core.Schema; using PinkParrot.Infrastructure.CQRS.Commands; using PinkParrot.Write.Schema.Commands; -using Swashbuckle.SwaggerGen.Annotations; - -#pragma warning disable 1584,1711,1572,1573,1581,1580 namespace PinkParrot.Modules.Api.Schemas { @@ -23,15 +20,9 @@ namespace PinkParrot.Modules.Api.Schemas : base(commandBus) { } - - /// - /// Adds a new field to the schema with the specified name. - /// - /// The name of the schema. - /// The field properties + [HttpPost] - [Route("schemas/{name}/fields/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] + [Route("api/schemas/{name}/fields/")] public Task Add(string name, [FromBody] ModelFieldProperties field) { var command = new AddModelField { Properties = field }; @@ -39,83 +30,57 @@ namespace PinkParrot.Modules.Api.Schemas return CommandBus.PublishAsync(command); } - /// - /// Uüdates the field with the specified schema name and field id. - /// - /// The name of the schema. - /// The id of the field. - /// The field properties [HttpPut] - [Route("schemas/{name}/fields/{fieldId:long}/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - public Task Update(string name, long fieldId, [FromBody] UpdateModelField command) + [Route("api/schemas/{name}/fields/{fieldId:long}/")] + public Task Update(string name, long fieldId, [FromBody] ModelFieldProperties properties) { + var command = new UpdateModelField { FieldId = fieldId, Properties = properties }; + return CommandBus.PublishAsync(command); } - /// - /// Hides the field with the specified schema name and field id. - /// - /// The name of the schema. - /// The id of the field. [HttpPut] - [Route("schemas/{name}/fields/{fieldId:long}/hide/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - public Task Hide(string name, long fieldId, HideModelField command) + [Route("api/schemas/{name}/fields/{fieldId:long}/hide/")] + public Task Hide(string name, long fieldId) { + var command = new HideModelField { FieldId = fieldId }; + return CommandBus.PublishAsync(command); } - /// - /// Sows the field with the specified schema name and field id. - /// - /// The name of the schema. - /// The id of the field. [HttpPut] - [Route("schemas/{name}/fields/{fieldId:long}/show/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - public Task Show(string name, long fieldId, ShowModelField command) + [Route("api/schemas/{name}/fields/{fieldId:long}/show/")] + public Task Show(string name, long fieldId) { + var command = new ShowModelField { FieldId = fieldId }; + return CommandBus.PublishAsync(command); } - - /// - /// Enables the field with the specified schema name and field id. - /// - /// The name of the schema. - /// The id of the field. + [HttpPut] - [Route("schemas/{name}/fields/{fieldId:long}/enable/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - public Task Enable(string name, long fieldId, EnableModelField command) + [Route("api/schemas/{name}/fields/{fieldId:long}/enable/")] + public Task Enable(string name, long fieldId) { + var command = new EnableModelField { FieldId = fieldId }; + return CommandBus.PublishAsync(command); } - - /// - /// Disables the field with the specified schema name and field id. - /// - /// The name of the schema. - /// The id of the field. + [HttpPut] - [Route("schemas/{name}/fields/{fieldId:long}/disable/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - public Task Disable(string name, long fieldId, DisableModelField command) + [Route("api/schemas/{name}/fields/{fieldId:long}/disable/")] + public Task Disable(string name, long fieldId) { + var command = new DisableModelField { FieldId = fieldId }; + return CommandBus.PublishAsync(command); } - - /// - /// Deletes the field with the specified schema name and field id. - /// - /// The name of the schema. - /// The id of the field. [HttpDelete] - [Route("schemas/{name}/fields/{fieldId:long}/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - public Task Delete(string name, long fieldId, DeleteModelField command) + [Route("api/schemas/{name}/fields/{fieldId:long}/")] + public Task Delete(string name, long fieldId) { + var command = new DeleteModelField { FieldId = fieldId }; + return CommandBus.PublishAsync(command); } } diff --git a/src/PinkParrot/Modules/Api/Schemas/SchemasController.cs b/src/PinkParrot/Modules/Api/Schemas/SchemasController.cs index 771ab4d74..990588fea 100644 --- a/src/PinkParrot/Modules/Api/Schemas/SchemasController.cs +++ b/src/PinkParrot/Modules/Api/Schemas/SchemasController.cs @@ -17,9 +17,6 @@ using PinkParrot.Infrastructure.CQRS.Commands; using PinkParrot.Infrastructure.Reflection; using PinkParrot.Read.Repositories; using PinkParrot.Write.Schema.Commands; -using Swashbuckle.SwaggerGen.Annotations; - -#pragma warning disable 1584,1711,1572,1581,1580 namespace PinkParrot.Modules.Api.Schemas { @@ -33,13 +30,8 @@ namespace PinkParrot.Modules.Api.Schemas this.modelSchemaRepository = modelSchemaRepository; } - /// - /// Queries all your schemas. - /// [HttpGet] - [Route("schemas/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - [ProducesResponseType(typeof(List), 200)] + [Route("api/schemas/")] public async Task> Query() { var schemas = await modelSchemaRepository.QueryAllAsync(TenantId); @@ -47,15 +39,8 @@ namespace PinkParrot.Modules.Api.Schemas return schemas.Select(s => SimpleMapper.Map(s, new SchemasDto())).ToList(); } - /// - /// Gets the schema with the specified name. - /// - /// The name of the schema. - /// Schema not found [HttpGet] - [Route("schemas/{name}/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - [ProducesResponseType(typeof(SchemaDto), 200)] + [Route("api/schemas/{name}/")] public async Task Get(string name) { var entity = await modelSchemaRepository.FindSchemaAsync(TenantId, name); @@ -68,19 +53,8 @@ namespace PinkParrot.Modules.Api.Schemas return Ok(SchemaDto.Create(entity.Schema)); } - /// - /// Creates a new schema. - /// - /// The properties of the schema. - /// - /// Field can be managed later. - /// - /// Schema created - /// Schema update failed [HttpPost] - [Route("schemas/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - [ProducesResponseType(typeof(EntityCreatedDto), 201)] + [Route("api/schemas/")] public async Task Create([FromBody] ModelSchemaProperties schema) { var command = new CreateModelSchema { AggregateId = Guid.NewGuid(), Properties = schema }; @@ -90,18 +64,8 @@ namespace PinkParrot.Modules.Api.Schemas return CreatedAtAction("Query", new EntityCreatedDto { Id = command.AggregateId }); } - /// - /// Updates the schema with the specified name. - /// - /// The name of the schema. - /// The properties of the schema. - /// Schema update - /// Schema not found - /// Schema update failed [HttpPut] - [Route("schemas/{name}/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - [ProducesResponseType(typeof(void), 204)] + [Route("api/schemas/{name}/")] public async Task Update(string name, [FromBody] ModelSchemaProperties schema) { var command = new UpdateModelSchema { Properties = schema }; @@ -111,17 +75,8 @@ namespace PinkParrot.Modules.Api.Schemas return NoContent(); } - /// - /// Deletes the schema with the specified name. - /// - /// The name of the schema. - /// Schema deleted - /// Schema not found - /// Schema deletion failed [HttpDelete] - [Route("schemas/{name}/")] - [SwaggerOperation(Tags = new[] { "Schemas" })] - [ProducesResponseType(typeof(void), 204)] + [Route("api/schemas/{name}/")] public async Task Delete(string name) { await CommandBus.PublishAsync(new DeleteModelSchema()); diff --git a/src/PinkParrot/Pipeline/Swagger/CamelCaseParameterFilter.cs b/src/PinkParrot/Pipeline/Swagger/CamelCaseParameterFilter.cs deleted file mode 100644 index 7cd961884..000000000 --- a/src/PinkParrot/Pipeline/Swagger/CamelCaseParameterFilter.cs +++ /dev/null @@ -1,29 +0,0 @@ -// ========================================================================== -// CamelCaseParameterFilter.cs -// PinkParrot Headless CMS -// ========================================================================== -// Copyright (c) PinkParrot Group -// All rights reserved. -// ========================================================================== - -using Swashbuckle.Swagger.Model; -using Swashbuckle.SwaggerGen.Generator; - -namespace PinkParrot.Pipeline.Swagger -{ - public sealed class CamelCaseParameterFilter : IOperationFilter - { - public void Apply(Operation operation, OperationFilterContext context) - { - if (operation.Parameters == null) - { - return; - } - - foreach (var parameter in operation.Parameters) - { - parameter.Name = char.ToLowerInvariant(parameter.Name[0]) + parameter.Name.Substring(1); - } - } - } -} diff --git a/src/PinkParrot/Pipeline/Swagger/HidePropertyFilter.cs b/src/PinkParrot/Pipeline/Swagger/HidePropertyFilter.cs deleted file mode 100644 index 2b7d18199..000000000 --- a/src/PinkParrot/Pipeline/Swagger/HidePropertyFilter.cs +++ /dev/null @@ -1,65 +0,0 @@ -// ========================================================================== -// HidePropertyFilter.cs -// PinkParrot Headless CMS -// ========================================================================== -// Copyright (c) PinkParrot Group -// All rights reserved. -// ========================================================================== - -using System.Linq; -using System.Reflection; -using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; -using PinkParrot.Infrastructure; -using Swashbuckle.Swagger.Model; -using Swashbuckle.SwaggerGen.Generator; - -namespace PinkParrot.Pipeline.Swagger -{ - public class HidePropertyFilter : ISchemaFilter, IOperationFilter - { - public void Apply(Schema model, SchemaFilterContext context) - { - foreach (var property in context.JsonContract.UnderlyingType.GetProperties()) - { - var attribute = property.GetCustomAttribute(); - - if (attribute != null) - { - model.Properties.Remove(property.Name); - } - } - } - - public void Apply(Operation operation, OperationFilterContext context) - { - if (context?.ApiDescription.ParameterDescriptions == null) - { - return; - } - - if (operation.Parameters == null) - { - return; - } - - foreach (var parameterDescription in context.ApiDescription.ParameterDescriptions) - { - var metadata = parameterDescription.ModelMetadata as DefaultModelMetadata; - - var hasAttribute = metadata?.Attributes?.Attributes.OfType().Any(); - - if (hasAttribute != true) - { - continue; - } - - var parameter = operation.Parameters.FirstOrDefault(p => p.Name == parameterDescription.Name); - - if (parameter != null) - { - operation.Parameters.Remove(parameter); - } - } - } - } -} diff --git a/src/PinkParrot/Pipeline/Swagger/RemoveReadonlyFilter.cs b/src/PinkParrot/Pipeline/Swagger/RemoveReadonlyFilter.cs deleted file mode 100644 index e437444b3..000000000 --- a/src/PinkParrot/Pipeline/Swagger/RemoveReadonlyFilter.cs +++ /dev/null @@ -1,36 +0,0 @@ -// ========================================================================== -// RemoveReadonlyFilter.cs -// PinkParrot Headless CMS -// ========================================================================== -// Copyright (c) PinkParrot Group -// All rights reserved. -// ========================================================================== - -using Swashbuckle.Swagger.Model; -using Swashbuckle.SwaggerGen.Generator; - -namespace PinkParrot.Pipeline.Swagger -{ - public class RemoveReadonlyFilter : ISchemaFilter - { - public void Apply(Schema model, SchemaFilterContext context) - { - Apply(model); - } - - private static void Apply(Schema model) - { - model.ReadOnly = null; - - if (model.Properties == null) - { - return; - } - - foreach (var property in model.Properties) - { - Apply(property.Value); - } - } - } -} diff --git a/src/PinkParrot/Startup.cs b/src/PinkParrot/Startup.cs index 384a27e23..2a5a843bd 100644 --- a/src/PinkParrot/Startup.cs +++ b/src/PinkParrot/Startup.cs @@ -26,7 +26,6 @@ namespace PinkParrot services.AddMvc().AddAppSerializers(); services.AddRouting(); services.AddMemoryCache(); - services.AddAppSwagger(); services.AddEventFormatter(); var builder = new ContainerBuilder(); @@ -42,16 +41,15 @@ namespace PinkParrot { loggerFactory.AddConsole(); - app.UseAppTenants(); - app.UseMvc(); - app.UseStaticFiles(); - app.UseAppSwagger(); - app.UseAppEventBus(); - if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } + + app.UseAppTenants(); + app.UseMvc(); + app.UseStaticFiles(); + app.UseAppEventBus(); } } } diff --git a/src/PinkParrot/project.json b/src/PinkParrot/project.json index c65f1d414..a1d0603c9 100644 --- a/src/PinkParrot/project.json +++ b/src/PinkParrot/project.json @@ -26,8 +26,7 @@ "PinkParrot.Events": "1.0.0-*", "PinkParrot.Infrastructure": "1.0.0-*", "PinkParrot.Read": "1.0.0-*", - "PinkParrot.Write": "1.0.0-*", - "Swashbuckle": "6.0.0-beta902" + "PinkParrot.Write": "1.0.0-*" }, "tools": { diff --git a/src/pinkparrot_core/PinkParrot.Core/Schema/Json/SchemaDto.cs b/src/pinkparrot_core/PinkParrot.Core/Schema/Json/SchemaDto.cs index 7ca8e441c..909373b13 100644 --- a/src/pinkparrot_core/PinkParrot.Core/Schema/Json/SchemaDto.cs +++ b/src/pinkparrot_core/PinkParrot.Core/Schema/Json/SchemaDto.cs @@ -7,8 +7,6 @@ // ========================================================================== using System.Collections.Immutable; -using System.ComponentModel.DataAnnotations; -using System.Linq; using PinkParrot.Infrastructure; // ReSharper disable LoopCanBeConvertedToQuery @@ -18,21 +16,19 @@ namespace PinkParrot.Core.Schema.Json public class SchemaDto { private readonly ModelSchemaProperties properties; - private readonly ImmutableList fields; - - [Required] - public ImmutableList Fields + private readonly ImmutableDictionary fields; + + public ImmutableDictionary Fields { get { return fields; } } - [Required] public ModelSchemaProperties Properties { get { return properties; } } - public SchemaDto(ModelSchemaProperties properties, ImmutableList fields) + public SchemaDto(ModelSchemaProperties properties, ImmutableDictionary fields) { Guard.NotNull(fields, nameof(fields)); Guard.NotNull(properties, nameof(properties)); @@ -46,7 +42,7 @@ namespace PinkParrot.Core.Schema.Json { Guard.NotNull(schema, nameof(schema)); - var fields = schema.Fields.Select(kvp => new FieldDto(kvp.Key, kvp.Value.RawProperties)).ToImmutableList(); + var fields = schema.Fields.ToImmutableDictionary(x => x.Key, x => x.Value.RawProperties); return new SchemaDto(schema.Properties, fields); } @@ -59,7 +55,7 @@ namespace PinkParrot.Core.Schema.Json foreach (var field in fields) { - schema = schema.AddField(field.Id, field.Properties, factory); + schema = schema.AddField(field.Key, field.Value, factory); } return schema; diff --git a/src/pinkparrot_core/PinkParrot.Core/Schema/ModelField.cs b/src/pinkparrot_core/PinkParrot.Core/Schema/ModelField.cs index 3845a3ef4..b41ad697a 100644 --- a/src/pinkparrot_core/PinkParrot.Core/Schema/ModelField.cs +++ b/src/pinkparrot_core/PinkParrot.Core/Schema/ModelField.cs @@ -54,7 +54,7 @@ namespace PinkParrot.Core.Schema this.id = id; } - public abstract ModelField Configure(ModelFieldProperties newProperties, IList errors); + public abstract ModelField Configure(ModelFieldProperties newProperties); public Task ValidateAsync(PropertyValue property, ICollection errors) { diff --git a/src/pinkparrot_core/PinkParrot.Core/Schema/ModelField_Generic.cs b/src/pinkparrot_core/PinkParrot.Core/Schema/ModelField_Generic.cs index bbac67ea1..d9eedf239 100644 --- a/src/pinkparrot_core/PinkParrot.Core/Schema/ModelField_Generic.cs +++ b/src/pinkparrot_core/PinkParrot.Core/Schema/ModelField_Generic.cs @@ -7,7 +7,6 @@ // ========================================================================== using System; -using System.Collections.Generic; using PinkParrot.Infrastructure; namespace PinkParrot.Core.Schema @@ -28,7 +27,7 @@ namespace PinkParrot.Core.Schema public override string Label { - get { return properties.Label; } + get { return properties.Label ?? properties.Name; } } public override string Hints @@ -54,10 +53,9 @@ namespace PinkParrot.Core.Schema this.properties = properties; } - public override ModelField Configure(ModelFieldProperties newProperties, IList errors) + public override ModelField Configure(ModelFieldProperties newProperties) { Guard.NotNull(newProperties, nameof(newProperties)); - Guard.NotNull(errors, nameof(errors)); var typedProperties = newProperties as T; @@ -66,8 +64,6 @@ namespace PinkParrot.Core.Schema throw new ArgumentException($"Properties must be of type '{typeof(T)}", nameof(newProperties)); } - newProperties.Validate(errors); - return Update>(clone => clone.properties = typedProperties); } } diff --git a/src/pinkparrot_core/PinkParrot.Core/Schema/ModelSchema.cs b/src/pinkparrot_core/PinkParrot.Core/Schema/ModelSchema.cs index 7ad79cb61..137aebdfe 100644 --- a/src/pinkparrot_core/PinkParrot.Core/Schema/ModelSchema.cs +++ b/src/pinkparrot_core/PinkParrot.Core/Schema/ModelSchema.cs @@ -32,22 +32,6 @@ namespace PinkParrot.Core.Schema fieldsByName = fields.Values.ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); } - public static ModelSchema Create(ModelSchemaProperties properties) - { - Guard.NotNull(properties, nameof(properties)); - - var errors = new List(); - - properties.Validate(errors); - - if (errors.Any()) - { - throw new ValidationException("Failed to create a new model schema.", errors); - } - - return new ModelSchema(properties, ImmutableDictionary.Empty); - } - public ImmutableDictionary Fields { get { return fieldsById; } @@ -58,11 +42,22 @@ namespace PinkParrot.Core.Schema get { return properties; } } - public ModelSchema Update(ModelSchemaProperties newMetadata) + public static ModelSchema Create(ModelSchemaProperties newProperties) + { + Guard.NotNull(newProperties, nameof(newProperties)); + + newProperties.Validate(() => "Failed to create a new model schema."); + + return new ModelSchema(newProperties, ImmutableDictionary.Empty); + } + + public ModelSchema Update(ModelSchemaProperties newProperties) { - Guard.NotNull(newMetadata, nameof(newMetadata)); + Guard.NotNull(newProperties, nameof(newProperties)); - return new ModelSchema(newMetadata, fieldsById); + newProperties.Validate(() => "Failed to update the model schema."); + + return new ModelSchema(newProperties, fieldsById); } public ModelSchema AddField(long id, ModelFieldProperties fieldProperties, ModelFieldFactory factory) @@ -78,14 +73,9 @@ namespace PinkParrot.Core.Schema return UpdateField(fieldId, field => { - var errors = new List(); - - var newField = field.Configure(fieldProperties, errors); + fieldProperties.Validate(() => $"Cannot update field with id '{fieldId}', becase the settings are invalid."); - if (errors.Any()) - { - throw new ValidationException($"Cannot update field with id '{fieldId}', becase the settings are invalid.", errors); - } + var newField = field.Configure(fieldProperties); return newField; }); @@ -142,11 +132,10 @@ namespace PinkParrot.Core.Schema return new ModelSchema(properties, fieldsById.SetItem(field.Id, field)); } - public async Task ValidateAsync(PropertiesBag data) + public async Task ValidateAsync(PropertiesBag data, IList errors) { Guard.NotNull(data, nameof(data)); - - var errors = new List(); + Guard.NotNull(errors, nameof(errors)); foreach (var kvp in data.Properties) { @@ -156,21 +145,14 @@ namespace PinkParrot.Core.Schema if (fieldsByName.TryGetValue(kvp.Key, out field)) { - var newErrors = new List(); - - await field.ValidateAsync(kvp.Value, newErrors); + await field.ValidateAsync(kvp.Value, fieldErrors); } else { fieldErrors.Add($"'{kvp.Key}' is not a known field"); } - errors.AddRange(fieldErrors.Select(x => new ValidationError(x, kvp.Key))); - } - - if (errors.Any()) - { - throw new ValidationException("The data is not valid.", errors); + fieldErrors.ForEach(error => errors.Add(new ValidationError(error, kvp.Key))); } } } diff --git a/src/pinkparrot_core/PinkParrot.Core/Schema/NamedElementProperties.cs b/src/pinkparrot_core/PinkParrot.Core/Schema/NamedElementProperties.cs index e90e18767..bbe0853c4 100644 --- a/src/pinkparrot_core/PinkParrot.Core/Schema/NamedElementProperties.cs +++ b/src/pinkparrot_core/PinkParrot.Core/Schema/NamedElementProperties.cs @@ -7,18 +7,16 @@ // ========================================================================== using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; using PinkParrot.Infrastructure; namespace PinkParrot.Core.Schema { - public abstract class NamedElementProperties + public abstract class NamedElementProperties : IValidatable { private readonly string name; private readonly string label; private readonly string hints; - - [Required] + public string Name { get { return name; } @@ -26,7 +24,7 @@ namespace PinkParrot.Core.Schema public string Label { - get { return string.IsNullOrWhiteSpace(label) ? name : label; } + get { return label; } } public string Hints diff --git a/src/pinkparrot_core/PinkParrot.Core/Schema/NumberFieldProperties.cs b/src/pinkparrot_core/PinkParrot.Core/Schema/NumberFieldProperties.cs index 0f9115f31..bffd645a8 100644 --- a/src/pinkparrot_core/PinkParrot.Core/Schema/NumberFieldProperties.cs +++ b/src/pinkparrot_core/PinkParrot.Core/Schema/NumberFieldProperties.cs @@ -48,17 +48,19 @@ namespace PinkParrot.Core.Schema errors.Add(new ValidationError("MinValue cannot be larger than max value", "MinValue", "MaxValue")); } - if (DefaultValue.HasValue) + if (!DefaultValue.HasValue) { - if (MinValue.HasValue && DefaultValue.Value < MinValue.Value) - { - errors.Add(new ValidationError("DefaultValue must be larger than the min value.", "DefaultValue")); - } + return; + } - if (MaxValue.HasValue && DefaultValue.Value > MaxValue.Value) - { - errors.Add(new ValidationError("DefaultValue must be smaller than the max value.", "DefaultValue")); - } + if (MinValue.HasValue && DefaultValue.Value < MinValue.Value) + { + errors.Add(new ValidationError("DefaultValue must be larger than the min value.", "DefaultValue")); + } + + if (MaxValue.HasValue && DefaultValue.Value > MaxValue.Value) + { + errors.Add(new ValidationError("DefaultValue must be smaller than the max value.", "DefaultValue")); } } } diff --git a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/ActionContextDispatcher.cs b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/ActionContextDispatcher.cs index 64b8cf08f..c1a602008 100644 --- a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/ActionContextDispatcher.cs +++ b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/ActionContextDispatcher.cs @@ -25,7 +25,7 @@ namespace PinkParrot.Infrastructure.Dispatching .Where(Helper.HasRightName) .Where(Helper.HasRightParameters) .Select(ActionContextDispatcherFactory.CreateActionHandler) - .ToDictionary>, Type, Action>(h => h.Item1, h => h.Item2); + .ToDictionary(h => h.Item1, h => h.Item2); } public static bool Dispatch(TTarget target, TIn input, TContext context) diff --git a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/ActionDispatcher.cs b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/ActionDispatcher.cs index ee20958f3..d0b1ede37 100644 --- a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/ActionDispatcher.cs +++ b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/ActionDispatcher.cs @@ -25,7 +25,7 @@ namespace PinkParrot.Infrastructure.Dispatching .Where(Helper.HasRightName) .Where(Helper.HasRightParameters) .Select(ActionDispatcherFactory.CreateActionHandler) - .ToDictionary>, Type, Action>(h => h.Item1, h => h.Item2); + .ToDictionary(h => h.Item1, h => h.Item2); } public static bool Dispatch(TTarget target, TIn item) diff --git a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/FuncContextDispatcher.cs b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/FuncContextDispatcher.cs index 6b6889029..dded47901 100644 --- a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/FuncContextDispatcher.cs +++ b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/FuncContextDispatcher.cs @@ -26,7 +26,7 @@ namespace PinkParrot.Infrastructure.Dispatching .Where(Helper.HasRightParameters) .Where(Helper.HasRightReturnType) .Select(FuncContextDispatcherFactory.CreateFuncHandler) - .ToDictionary>, Type, Func>(h => h.Item1, h => h.Item2); + .ToDictionary(h => h.Item1, h => h.Item2); } public static TOut Dispatch(TTarget target, TIn item, TContext context) diff --git a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/FuncDispatcher.cs b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/FuncDispatcher.cs index 027bcd24c..4ed946528 100644 --- a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/FuncDispatcher.cs +++ b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Dispatching/FuncDispatcher.cs @@ -26,7 +26,7 @@ namespace PinkParrot.Infrastructure.Dispatching .Where(Helper.HasRightParameters) .Where(Helper.HasRightReturnType) .Select(FuncDispatcherFactory.CreateFuncHandler) - .ToDictionary>, Type, Func>(h => h.Item1, h => h.Item2); + .ToDictionary(h => h.Item1, h => h.Item2); } public static TOut Dispatch(TTarget target, TIn item) diff --git a/src/pinkparrot_core/PinkParrot.Core/Schema/Json/FieldDto.cs b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/IValidatable.cs similarity index 52% rename from src/pinkparrot_core/PinkParrot.Core/Schema/Json/FieldDto.cs rename to src/pinkparrot_infrastructure/PinkParrot.Infrastructure/IValidatable.cs index 4a66528ea..4d1861345 100644 --- a/src/pinkparrot_core/PinkParrot.Core/Schema/Json/FieldDto.cs +++ b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/IValidatable.cs @@ -1,24 +1,17 @@ // ========================================================================== -// FieldDto.cs +// IValidatable.cs // PinkParrot Headless CMS // ========================================================================== // Copyright (c) PinkParrot Group // All rights reserved. // ========================================================================== -namespace PinkParrot.Core.Schema.Json +using System.Collections.Generic; + +namespace PinkParrot.Infrastructure { - public class FieldDto + public interface IValidatable { - public long Id { get; } - - public ModelFieldProperties Properties { get; } - - public FieldDto(long id, ModelFieldProperties properties) - { - Id = id; - - Properties = properties; - } + void Validate(IList errors); } } diff --git a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Reflection/SimpleMapper.cs b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Reflection/SimpleMapper.cs index 5ba6dda2c..8bbb02046 100644 --- a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Reflection/SimpleMapper.cs +++ b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Reflection/SimpleMapper.cs @@ -10,7 +10,6 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Reflection; // ReSharper disable StaticMemberInGenericType diff --git a/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/ValidationExtensions.cs b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/ValidationExtensions.cs new file mode 100644 index 000000000..80792ac86 --- /dev/null +++ b/src/pinkparrot_infrastructure/PinkParrot.Infrastructure/ValidationExtensions.cs @@ -0,0 +1,29 @@ +// ========================================================================== +// ValidationExtensions.cs +// PinkParrot Headless CMS +// ========================================================================== +// Copyright (c) PinkParrot Group +// All rights reserved. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PinkParrot.Infrastructure +{ + public static class ValidationExtensions + { + public static void Validate(this IValidatable target, Func message) + { + var errors = new List(); + + target.Validate(errors); + + if (errors.Any()) + { + throw new ValidationException(message(), errors); + } + } + } +} diff --git a/src/pinkparrot_read/PinkParrot.Read/Repositories/Implementations/EntityMapper.cs b/src/pinkparrot_read/PinkParrot.Read/Repositories/Implementations/EntityMapper.cs index cc1b0d382..9b53a6169 100644 --- a/src/pinkparrot_read/PinkParrot.Read/Repositories/Implementations/EntityMapper.cs +++ b/src/pinkparrot_read/PinkParrot.Read/Repositories/Implementations/EntityMapper.cs @@ -76,10 +76,9 @@ namespace PinkParrot.Read.Repositories.Implementations } Update(entity, headers); - updater(entity); - var result = await collection.ReplaceOneAsync(t => t.Id == entity.Id, entity); + await collection.ReplaceOneAsync(t => t.Id == entity.Id, entity); } } } diff --git a/src/pinkparrot_read/PinkParrot.Read/Repositories/Implementations/MongoModelSchemaRepository.cs b/src/pinkparrot_read/PinkParrot.Read/Repositories/Implementations/MongoModelSchemaRepository.cs index 0def84158..016ca78a3 100644 --- a/src/pinkparrot_read/PinkParrot.Read/Repositories/Implementations/MongoModelSchemaRepository.cs +++ b/src/pinkparrot_read/PinkParrot.Read/Repositories/Implementations/MongoModelSchemaRepository.cs @@ -10,7 +10,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using MongoDB.Bson; using MongoDB.Driver; using Newtonsoft.Json; using PinkParrot.Core.Schema; @@ -21,24 +20,23 @@ using PinkParrot.Infrastructure.CQRS; using PinkParrot.Infrastructure.CQRS.Events; using PinkParrot.Infrastructure.Dispatching; using PinkParrot.Infrastructure.MongoDb; -using PinkParrot.Infrastructure.Tasks; namespace PinkParrot.Read.Repositories.Implementations { public sealed class MongoModelSchemaRepository : MongoRepositoryBase, IModelSchemaRepository, ICatchEventConsumer { private readonly JsonSerializerSettings serializerSettings; - private readonly ModelFieldFactory fieldFactory; + private readonly ModelFieldFactory factory; - public MongoModelSchemaRepository(IMongoDatabase database, JsonSerializerSettings serializerSettings, ModelFieldFactory fieldFactory) + public MongoModelSchemaRepository(IMongoDatabase database, JsonSerializerSettings serializerSettings, ModelFieldFactory factory) : base(database) { Guard.NotNull(serializerSettings, nameof(serializerSettings)); - Guard.NotNull(fieldFactory, nameof(fieldFactory)); + Guard.NotNull(factory, nameof(factory)); this.serializerSettings = serializerSettings; - this.fieldFactory = fieldFactory; + this.factory = factory; } protected override Task SetupCollectionAsync(IMongoCollection collection) @@ -87,7 +85,7 @@ namespace PinkParrot.Read.Repositories.Implementations public Task On(ModelFieldAdded @event, EnvelopeHeaders headers) { - return UpdateSchema(headers, s => s.AddField(@event.FieldId, @event.Properties, fieldFactory)); + return UpdateSchema(headers, s => s.AddField(@event.FieldId, @event.Properties, factory)); } public Task On(ModelFieldDeleted @event, EnvelopeHeaders headers) @@ -124,7 +122,10 @@ namespace PinkParrot.Read.Repositories.Implementations { return Collection.UpdateAsync(headers, e => { - e.Name = @event.Properties.Name; + if (!string.IsNullOrWhiteSpace(@event.Properties.Name)) + { + e.Name = @event.Properties.Name; + } UpdateSchema(e, s => s.Update(@event.Properties)); }); @@ -166,7 +167,7 @@ namespace PinkParrot.Read.Repositories.Implementations private ModelSchema Deserialize(MongoModelSchemaEntity entity) { - return entity?.Schema.ToJsonObject(serializerSettings).ToModelSchema(fieldFactory); + return entity?.Schema.ToJsonObject(serializerSettings).ToModelSchema(factory); } } } diff --git a/src/pinkparrot_read/PinkParrot.Read/Services/Implementations/MongoStreamPositionsStorage.cs b/src/pinkparrot_read/PinkParrot.Read/Services/Implementations/MongoStreamPositionsStorage.cs index a6405a831..ae918a8ac 100644 --- a/src/pinkparrot_read/PinkParrot.Read/Services/Implementations/MongoStreamPositionsStorage.cs +++ b/src/pinkparrot_read/PinkParrot.Read/Services/Implementations/MongoStreamPositionsStorage.cs @@ -26,7 +26,7 @@ namespace PinkParrot.Read.Services.Implementations public int? ReadPosition() { - var document = Collection.Find(t => t.Id == Id).FirstOrDefault(); + var document = Collection.Find(t => t.Id == Id).FirstOrDefault(); if (document == null) { diff --git a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/AddModelField.cs b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/AddModelField.cs index 03d7cfa7c..1a27dc6fa 100644 --- a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/AddModelField.cs +++ b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/AddModelField.cs @@ -7,7 +7,6 @@ // ========================================================================== using PinkParrot.Core.Schema; -using PinkParrot.Infrastructure.CQRS.Commands; namespace PinkParrot.Write.Schema.Commands { diff --git a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelField.cs b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelField.cs index c88a30a76..f8ec9ad64 100644 --- a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelField.cs +++ b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelField.cs @@ -6,8 +6,6 @@ // All rights reserved. // ========================================================================== -using PinkParrot.Infrastructure.CQRS.Commands; - namespace PinkParrot.Write.Schema.Commands { public class DeleteModelField : TenantCommand diff --git a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelSchema.cs b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelSchema.cs index 739827842..7c5ff662b 100644 --- a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelSchema.cs +++ b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelSchema.cs @@ -6,8 +6,6 @@ // All rights reserved. // ========================================================================== -using PinkParrot.Infrastructure.CQRS.Commands; - namespace PinkParrot.Write.Schema.Commands { public class DeleteModelSchema : TenantCommand diff --git a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/EnableModelField.cs b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/EnableModelField.cs index e4b37954d..feeba187e 100644 --- a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/EnableModelField.cs +++ b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/EnableModelField.cs @@ -6,8 +6,6 @@ // All rights reserved. // ========================================================================== -using PinkParrot.Infrastructure.CQRS.Commands; - namespace PinkParrot.Write.Schema.Commands { public class EnableModelField : TenantCommand diff --git a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/HideModelField.cs b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/HideModelField.cs index 2d7ab24f1..a8b24e445 100644 --- a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/HideModelField.cs +++ b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/HideModelField.cs @@ -6,8 +6,6 @@ // All rights reserved. // ========================================================================== -using PinkParrot.Infrastructure.CQRS.Commands; - namespace PinkParrot.Write.Schema.Commands { public class HideModelField : TenantCommand diff --git a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/ShowModelField.cs b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/ShowModelField.cs index 1979676ff..8668851a2 100644 --- a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/ShowModelField.cs +++ b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/ShowModelField.cs @@ -6,8 +6,6 @@ // All rights reserved. // ========================================================================== -using PinkParrot.Infrastructure.CQRS.Commands; - namespace PinkParrot.Write.Schema.Commands { public class ShowModelField : TenantCommand diff --git a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelField.cs b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelField.cs index 2c0768b4e..2bd2a02fc 100644 --- a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelField.cs +++ b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelField.cs @@ -7,7 +7,6 @@ // ========================================================================== using PinkParrot.Core.Schema; -using PinkParrot.Infrastructure.CQRS.Commands; namespace PinkParrot.Write.Schema.Commands { diff --git a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelSchema.cs b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelSchema.cs index ae428951f..e67c4c394 100644 --- a/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelSchema.cs +++ b/src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelSchema.cs @@ -7,7 +7,6 @@ // ========================================================================== using PinkParrot.Core.Schema; -using PinkParrot.Infrastructure.CQRS.Commands; namespace PinkParrot.Write.Schema.Commands { diff --git a/src/pinkparrot_write/PinkParrot.Write/Schema/ModelSchemaDomainObject.cs b/src/pinkparrot_write/PinkParrot.Write/Schema/ModelSchemaDomainObject.cs index efc2b0b74..036b81bfa 100644 --- a/src/pinkparrot_write/PinkParrot.Write/Schema/ModelSchemaDomainObject.cs +++ b/src/pinkparrot_write/PinkParrot.Write/Schema/ModelSchemaDomainObject.cs @@ -17,9 +17,9 @@ using PinkParrot.Write.Schema.Commands; namespace PinkParrot.Write.Schema { - public class ModelSchemaDomainObject : DomainObject, IAggregate + public class ModelSchemaDomainObject : DomainObject { - private readonly ModelFieldFactory fieldFactory; + private readonly ModelFieldFactory factory; private Guid tenantId; private bool isDeleted; private long totalFields; @@ -40,15 +40,15 @@ namespace PinkParrot.Write.Schema get { return isDeleted; } } - public ModelSchemaDomainObject(Guid id, int version, ModelFieldFactory fieldFactory) + public ModelSchemaDomainObject(Guid id, int version, ModelFieldFactory factory) : base(id, version) { - this.fieldFactory = fieldFactory; + this.factory = factory; } public void On(ModelFieldAdded @event) { - schema = schema.AddField(@event.FieldId, @event.Properties, fieldFactory); + schema = schema.AddField(@event.FieldId, @event.Properties, factory); totalFields++; } @@ -106,7 +106,7 @@ namespace PinkParrot.Write.Schema var id = ++totalFields; - schema = schema.AddField(id, command.Properties, fieldFactory); + schema = schema.AddField(id, command.Properties, factory); RaiseEvent(new ModelFieldAdded { FieldId = id, Properties = command.Properties }, true); }