diff --git a/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs index adea21e4c..536a4cd42 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs @@ -8,7 +8,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Apps.Commands; @@ -16,7 +15,6 @@ using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; -using Squidex.Infrastructure.Tasks; namespace Squidex.Domain.Apps.Entities.Apps.Templates { @@ -36,13 +34,23 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates { var appId = new NamedId(createApp.AppId, createApp.Name); + var publish = new Func(command => + { + if (command is IAppCommand appCommand) + { + appCommand.AppId = appId; + } + + return context.CommandBus.PublishAsync(command); + }); + return Task.WhenAll( - CreatePagesAsync(context.CommandBus, appId), - CreatePostsAsync(context.CommandBus, appId), - CreateClientAsync(context.CommandBus, appId)); + CreatePagesAsync(publish), + CreatePostsAsync(publish), + CreateClientAsync(publish, appId.Id)); } - return TaskHelper.Done; + return next(); } private static bool IsRightTemplate(CreateApp createApp) @@ -50,16 +58,16 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates return string.Equals(createApp.Template, TemplateName, StringComparison.OrdinalIgnoreCase); } - private static async Task CreateClientAsync(ICommandBus bus, NamedId appId) + private static async Task CreateClientAsync(Func publish, Guid appId) { - await bus.PublishAsync(new AttachClient { Id = "sample-client" }); + await publish(new AttachClient { Id = "sample-client", AppId = appId }); } - private async Task CreatePostsAsync(ICommandBus bus, NamedId appId) + private async Task CreatePostsAsync(Func publish) { - var postsId = await CreatePostsSchema(bus, appId); + var postsId = await CreatePostsSchemaAsync(publish); - await bus.PublishAsync(new CreateContent + await publish(new CreateContent { SchemaId = postsId, Data = @@ -74,11 +82,11 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates }); } - private async Task CreatePagesAsync(ICommandBus bus, NamedId appId) + private async Task CreatePagesAsync(Func publish) { - var pagesId = await CreatePagesSchema(bus, appId); + var pagesId = await CreatePagesSchemaAsync(publish); - await bus.PublishAsync(new CreateContent + await publish(new CreateContent { SchemaId = pagesId, Data = @@ -93,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates }); } - private async Task> CreatePostsSchema(ICommandBus bus, NamedId appId) + private async Task> CreatePostsSchemaAsync(Func publish) { var command = new CreateSchema { @@ -108,7 +116,6 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates new CreateSchemaField { Name = "title", - Partitioning = Partitioning.Invariant.Key, Properties = new StringFieldProperties { Editor = StringFieldEditor.Input, @@ -122,7 +129,6 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates new CreateSchemaField { Name = "slug", - Partitioning = Partitioning.Invariant.Key, Properties = new StringFieldProperties { Editor = StringFieldEditor.Slug, @@ -137,7 +143,6 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates new CreateSchemaField { Name = "text", - Partitioning = Partitioning.Invariant.Key, Properties = new StringFieldProperties { Editor = StringFieldEditor.RichText, @@ -146,15 +151,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates Label = "Text" } } - }, - AppId = appId + } }; - await bus.PublishAsync(command); + await publish(command); var schemaId = new NamedId(command.SchemaId, command.Name); - await bus.PublishAsync(new ConfigureScripts + await publish(new ConfigureScripts { SchemaId = schemaId.Id, ScriptCreate = SlugScript, @@ -164,7 +168,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates return schemaId; } - private async Task> CreatePagesSchema(ICommandBus bus, NamedId appId) + private async Task> CreatePagesSchemaAsync(Func publish) { var command = new CreateSchema { @@ -178,7 +182,6 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates new CreateSchemaField { Name = "title", - Partitioning = Partitioning.Invariant.Key, Properties = new StringFieldProperties { Editor = StringFieldEditor.Input, @@ -192,7 +195,6 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates new CreateSchemaField { Name = "slug", - Partitioning = Partitioning.Invariant.Key, Properties = new StringFieldProperties { Editor = StringFieldEditor.Slug, @@ -207,7 +209,6 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates new CreateSchemaField { Name = "text", - Partitioning = Partitioning.Invariant.Key, Properties = new StringFieldProperties { Editor = StringFieldEditor.RichText, @@ -216,15 +217,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates Label = "Text" } } - }, - AppId = appId + } }; - await bus.PublishAsync(command); + await publish(command); var schemaId = new NamedId(command.SchemaId, command.Name); - await bus.PublishAsync(new ConfigureScripts + await publish(new ConfigureScripts { SchemaId = schemaId.Id, ScriptCreate = SlugScript, diff --git a/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfileCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfileCommandMiddleware.cs new file mode 100644 index 000000000..936b0a055 --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfileCommandMiddleware.cs @@ -0,0 +1,603 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Entities.Apps.Commands; +using Squidex.Domain.Apps.Entities.Contents.Commands; +using Squidex.Domain.Apps.Entities.Schemas.Commands; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Commands; + +namespace Squidex.Domain.Apps.Entities.Apps.Templates +{ + public sealed class CreateProfileCommandMiddleware : ICommandMiddleware + { + private const string TemplateName = "Profile"; + + public Task HandleAsync(CommandContext context, Func next) + { + if (context.IsCompleted && context.Command is CreateApp createApp && IsRightTemplate(createApp)) + { + var appId = new NamedId(createApp.AppId, createApp.Name); + + var publish = new Func(command => + { + if (command is IAppCommand appCommand) + { + appCommand.AppId = appId; + } + + return context.CommandBus.PublishAsync(command); + }); + + return Task.WhenAll( + CreateBasicsAsync(publish), + CreateProjectsSchemaAsync(publish), + CreateExperienceSchemaAsync(publish), + CreateSkillsSchemaAsync(publish), + CreateEducationSchemaAsync(publish), + CreatePublicationsSchemaAsync(publish), + CreateClientAsync(publish, appId.Id)); + } + + return next(); + } + + private static bool IsRightTemplate(CreateApp createApp) + { + return string.Equals(createApp.Template, TemplateName, StringComparison.OrdinalIgnoreCase); + } + + private static async Task CreateClientAsync(Func publish, Guid appId) + { + await publish(new AttachClient { Id = "sample-client", AppId = appId }); + } + + private async Task CreateBasicsAsync(Func publish) + { + var postsId = await CreateBasicsSchemaAsync(publish); + + await publish(new CreateContent + { + SchemaId = postsId, + Data = + new NamedContentData() + .AddField("firstName", + new ContentFieldData() + .AddValue("iv", "John")) + .AddField("lastName", + new ContentFieldData() + .AddValue("iv", "Doe")) + .AddField("profession", + new ContentFieldData() + .AddValue("iv", "Software Developer")), + Publish = true, + }); + } + + private async Task> CreateBasicsSchemaAsync(Func publish) + { + var command = new CreateSchema + { + Name = "basics", + Properties = new SchemaProperties + { + Label = "Basics" + }, + Fields = new List + { + new CreateSchemaField + { + Name = "firstName", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = true, + IsListField = true, + Label = "First Name", + Hints = "Your first name" + } + }, + new CreateSchemaField + { + Name = "lastName", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = true, + IsListField = true, + Label = "Last Name", + Hints = "Your last name" + } + }, + new CreateSchemaField + { + Name = "profession", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.TextArea, + IsRequired = true, + IsListField = false, + Label = "Profession", + Hints = "Define your profession" + } + }, + new CreateSchemaField + { + Name = "image", + Properties = new AssetsFieldProperties + { + IsRequired = false, + IsListField = false, + MustBeImage = true, + Label = "Image", + Hints = "Your image" + } + }, + new CreateSchemaField + { + Name = "summary", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.TextArea, + IsRequired = false, + IsListField = false, + Label = "Summary", + Hints = "Write a short summary about yourself" + } + }, + new CreateSchemaField + { + Name = "githubLink", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = false, + IsListField = false, + Label = "Github", + Hints = "An optional link to your Github account" + } + }, + new CreateSchemaField + { + Name = "blogLink", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = false, + IsListField = false, + Label = "Blog", + Hints = "An optional link to your blog" + } + }, + new CreateSchemaField + { + Name = "twitterLink", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = false, + IsListField = false, + Label = "Twitter", + Hints = "An optional link to your twitter account" + } + }, + new CreateSchemaField + { + Name = "linkedInLink", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = false, + IsListField = false, + Label = "LinkedIn", + Hints = "An optional link to your LinkedIn account" + } + }, + new CreateSchemaField + { + Name = "emailAddress", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = false, + IsListField = false, + Label = "Email Address", + Hints = "An optional email address to contact you" + } + }, + new CreateSchemaField + { + Name = "legalTerms", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.TextArea, + IsRequired = false, + IsListField = false, + Label = "Legal terms", + Hints = "The terms to fulfill legal requirements" + } + } + }, + Publish = true + }; + + await publish(command); + + return new NamedId(command.SchemaId, command.Name); + } + + private async Task> CreateProjectsSchemaAsync(Func publish) + { + var command = new CreateSchema + { + Name = "projects", + Properties = new SchemaProperties + { + Label = "Projects" + }, + Fields = new List + { + new CreateSchemaField + { + Name = "name", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = true, + IsListField = true, + Label = "Name", + Hints = "The name of the projection" + } + }, + new CreateSchemaField + { + Name = "description", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.TextArea, + IsRequired = true, + IsListField = false, + Label = "Description", + Hints = "Describe your project" + } + }, + new CreateSchemaField + { + Name = "image", + Properties = new AssetsFieldProperties + { + IsRequired = true, + IsListField = false, + MustBeImage = true, + Label = "Image", + Hints = "An image or screenshot for your project" + } + }, + new CreateSchemaField + { + Name = "label", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = false, + IsListField = false, + Label = "Label", + Hints = "An optional label to categorize your project, e.g. 'Open Source'" + } + }, + new CreateSchemaField + { + Name = "link", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = false, + IsListField = false, + Label = "link", + Hints = "The logo of the company or organization you worked for" + } + }, + new CreateSchemaField + { + Name = "year", + Properties = new NumberFieldProperties + { + IsRequired = false, + IsListField = false, + Label = "Year", + Hints = "The year, when you realized the project, used for sorting only" + } + } + }, + Publish = true + }; + + await publish(command); + + return new NamedId(command.SchemaId, command.Name); + } + + private async Task> CreateExperienceSchemaAsync(Func publish) + { + var command = new CreateSchema + { + Name = "experience", + Properties = new SchemaProperties + { + Label = "Experience" + }, + Fields = new List + { + new CreateSchemaField + { + Name = "position", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = true, + IsListField = true, + Label = "Position", + Hints = "Your position in this job" + } + }, + new CreateSchemaField + { + Name = "company", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = true, + IsListField = true, + Label = "Company", + Hints = "The company or organization you worked for" + } + }, + new CreateSchemaField + { + Name = "logo", + Properties = new AssetsFieldProperties + { + IsRequired = false, + IsListField = false, + MustBeImage = true, + Label = "Logo", + Hints = "The logo of the company or organization you worked for" + } + }, + new CreateSchemaField + { + Name = "from", + Properties = new DateTimeFieldProperties + { + Editor = DateTimeFieldEditor.Date, + IsRequired = true, + IsListField = false, + Label = "Start Date", + Hints = "The start date" + } + }, + new CreateSchemaField + { + Name = "to", + Properties = new DateTimeFieldProperties + { + Editor = DateTimeFieldEditor.Date, + IsRequired = false, + IsListField = false, + Label = "End Date", + Hints = "The end date, keep empty if you still work there" + } + } + }, + Publish = true + }; + + await publish(command); + + return new NamedId(command.SchemaId, command.Name); + } + + private async Task> CreateEducationSchemaAsync(Func publish) + { + var command = new CreateSchema + { + Name = "education", + Properties = new SchemaProperties + { + Label = "Education" + }, + Fields = new List + { + new CreateSchemaField + { + Name = "degree", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = true, + IsListField = true, + Label = "Degree", + Hints = "The degree you got or achieved" + } + }, + new CreateSchemaField + { + Name = "school", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = true, + IsListField = true, + Label = "School", + Hints = "The school or university" + } + }, + new CreateSchemaField + { + Name = "logo", + Properties = new AssetsFieldProperties + { + IsRequired = false, + IsListField = false, + MustBeImage = true, + Label = "Logo", + Hints = "The logo of the school" + } + }, + new CreateSchemaField + { + Name = "from", + Properties = new DateTimeFieldProperties + { + Editor = DateTimeFieldEditor.Date, + IsRequired = true, + IsListField = false, + Label = "Start Date", + Hints = "The start date" + } + }, + new CreateSchemaField + { + Name = "to", + Properties = new DateTimeFieldProperties + { + Editor = DateTimeFieldEditor.Date, + IsRequired = false, + IsListField = false, + Label = "End Date", + Hints = "The end date, keep empty if you still study there" + } + } + }, + Publish = true + }; + + await publish(command); + + return new NamedId(command.SchemaId, command.Name); + } + + private async Task> CreatePublicationsSchemaAsync(Func publish) + { + var command = new CreateSchema + { + Name = "publications", + Properties = new SchemaProperties + { + Label = "Publications" + }, + Fields = new List + { + new CreateSchemaField + { + Name = "name", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = true, + IsListField = true, + Label = "Name", + Hints = "The name or title of your publication" + } + }, + new CreateSchemaField + { + Name = "description", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.TextArea, + IsRequired = false, + IsListField = false, + Label = "Description", + Hints = "Describe the content of your publication" + } + }, + new CreateSchemaField + { + Name = "cover", + Properties = new AssetsFieldProperties + { + IsRequired = true, + IsListField = false, + MustBeImage = true, + Label = "Cover", + Hints = "The cover of your publication" + } + }, + new CreateSchemaField + { + Name = "link", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = false, + IsListField = false, + Label = "Link", + Hints = "An optional link to your publication" + } + } + }, + Publish = true + }; + + await publish(command); + + return new NamedId(command.SchemaId, command.Name); + } + + private async Task> CreateSkillsSchemaAsync(Func publish) + { + var command = new CreateSchema + { + Name = "skills", + Properties = new SchemaProperties + { + Label = "Skills" + }, + Fields = new List + { + new CreateSchemaField + { + Name = "name", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Input, + IsRequired = true, + IsListField = true, + Label = "Name", + Hints = "The name for your skill" + } + }, + new CreateSchemaField + { + Name = "experience", + Properties = new StringFieldProperties + { + Editor = StringFieldEditor.Dropdown, + IsRequired = true, + IsListField = true, + AllowedValues = ImmutableList.Create("Beginner", "Advanced", "Professional", "Expert"), + Label = "Experience", + Hints = "The level of experience" + } + } + }, + Publish = true + }; + + await publish(command); + + return new NamedId(command.SchemaId, command.Name); + } + } +} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs b/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs index dfd5d8b68..e7cc66f55 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Contents.Commands; diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchemaField.cs b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchemaField.cs index 47bdca094..82e8876eb 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchemaField.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchemaField.cs @@ -11,7 +11,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands { public sealed class CreateSchemaField { - public string Partitioning { get; set; } + public string Partitioning { get; set; } = Core.Partitioning.Invariant.Key; public string Name { get; set; } diff --git a/src/Squidex/Config/Domain/WriteServices.cs b/src/Squidex/Config/Domain/WriteServices.cs index a40bd1c87..505a0d4e8 100644 --- a/src/Squidex/Config/Domain/WriteServices.cs +++ b/src/Squidex/Config/Domain/WriteServices.cs @@ -68,6 +68,9 @@ namespace Squidex.Config.Domain services.AddSingletonAs() .As(); + services.AddSingletonAs() + .As(); + services.AddTransientAs() .As(); diff --git a/src/Squidex/app/features/apps/pages/apps-page.component.html b/src/Squidex/app/features/apps/pages/apps-page.component.html index 9c65780f2..ea2f3b699 100644 --- a/src/Squidex/app/features/apps/pages/apps-page.component.html +++ b/src/Squidex/app/features/apps/pages/apps-page.component.html @@ -53,6 +53,21 @@ + +
+
+
+ +
+ +

New Profile Sample

+ +
+
Create your profile page.
+
Sample Code: ASP.NET Core
+
+
+