mirror of https://github.com/Squidex/squidex.git
33 changed files with 561 additions and 60 deletions
@ -0,0 +1,17 @@ |
|||
// ==========================================================================
|
|||
// AppCreated.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using PinkParrot.Infrastructure.CQRS.Events; |
|||
|
|||
namespace PinkParrot.Events.Apps |
|||
{ |
|||
public class AppCreated : IEvent |
|||
{ |
|||
public string Name { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
// ==========================================================================
|
|||
// MongoDbModule.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using Autofac; |
|||
using Microsoft.AspNetCore.Identity; |
|||
using Microsoft.AspNetCore.Identity.MongoDB; |
|||
using Microsoft.Extensions.Options; |
|||
using MongoDB.Driver; |
|||
using PinkParrot.Infrastructure.CQRS.EventStore; |
|||
using PinkParrot.Store.MongoDb.Infrastructure; |
|||
|
|||
namespace PinkParrot.Store.MongoDb |
|||
{ |
|||
public class MongoDbModule : Module |
|||
{ |
|||
protected override void Load(ContainerBuilder builder) |
|||
{ |
|||
builder.Register(context => |
|||
{ |
|||
var options = context.Resolve<IOptions<MongoDbOptions>>().Value; |
|||
|
|||
var mongoDbClient = new MongoClient(options.ConnectionString); |
|||
var mongoDatabase = mongoDbClient.GetDatabase(options.DatabaseName); |
|||
|
|||
return mongoDatabase; |
|||
}).SingleInstance(); |
|||
|
|||
builder.Register<IUserStore<IdentityUser>>(context => |
|||
{ |
|||
var usersCollection = context.Resolve<IMongoDatabase>().GetCollection<IdentityUser>("Identity_Users"); |
|||
|
|||
IndexChecks.EnsureUniqueIndexOnNormalizedEmail(usersCollection); |
|||
IndexChecks.EnsureUniqueIndexOnNormalizedUserName(usersCollection); |
|||
|
|||
return new UserStore<IdentityUser>(usersCollection); |
|||
}).SingleInstance(); |
|||
|
|||
builder.Register<IRoleStore<IdentityRole>>(context => |
|||
{ |
|||
var rolesCollection = context.Resolve<IMongoDatabase>().GetCollection<IdentityRole>("Identity_Roles"); |
|||
|
|||
IndexChecks.EnsureUniqueIndexOnNormalizedRoleName(rolesCollection); |
|||
|
|||
return new RoleStore<IdentityRole>(rolesCollection); |
|||
}).SingleInstance(); |
|||
|
|||
builder.RegisterType<MongoPositionStorage>() |
|||
.As<IStreamPositionStorage>() |
|||
.SingleInstance(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
// ==========================================================================
|
|||
// MongoDbOptions.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
namespace PinkParrot.Store.MongoDb |
|||
{ |
|||
public class MongoDbOptions |
|||
{ |
|||
public string ConnectionString { get; set; } |
|||
|
|||
public string DatabaseName { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
// ==========================================================================
|
|||
// AppDomainObject.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using PinkParrot.Events.Apps; |
|||
using PinkParrot.Infrastructure; |
|||
using PinkParrot.Infrastructure.CQRS; |
|||
using PinkParrot.Infrastructure.CQRS.Events; |
|||
using PinkParrot.Infrastructure.Dispatching; |
|||
using PinkParrot.Write.Apps.Commands; |
|||
|
|||
namespace PinkParrot.Write.Apps |
|||
{ |
|||
public sealed class AppDomainObject : DomainObject |
|||
{ |
|||
private string name; |
|||
|
|||
public string Name |
|||
{ |
|||
get { return name; } |
|||
} |
|||
|
|||
public AppDomainObject(Guid id, int version) : base(id, version) |
|||
{ |
|||
} |
|||
|
|||
public void On(AppCreated @event) |
|||
{ |
|||
name = @event.Name; |
|||
} |
|||
|
|||
protected override void DispatchEvent(Envelope<IEvent> @event) |
|||
{ |
|||
this.DispatchAction(@event.Payload); |
|||
} |
|||
|
|||
public void Create(CreateApp command) |
|||
{ |
|||
Guard.Valid(command, nameof(command), "Cannot create app"); |
|||
|
|||
VerifyNotCreated(); |
|||
|
|||
RaiseEvent(new AppCreated { Name = command.Name }); |
|||
} |
|||
|
|||
private void VerifyNotCreated() |
|||
{ |
|||
if (!string.IsNullOrWhiteSpace(name)) |
|||
{ |
|||
throw new DomainException("App has already been created."); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
// ==========================================================================
|
|||
// CreateApp.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using PinkParrot.Infrastructure; |
|||
|
|||
namespace PinkParrot.Write.Apps.Commands |
|||
{ |
|||
public sealed class CreateApp : IValidatable |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public void Validate(IList<ValidationError> errors) |
|||
{ |
|||
if (!Name.IsSlug()) |
|||
{ |
|||
errors.Add(new ValidationError("Name must be a valid slug", "Name")); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
// ==========================================================================
|
|||
// EventStoreModule.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Net; |
|||
using Autofac; |
|||
using EventStore.ClientAPI; |
|||
using EventStore.ClientAPI.SystemData; |
|||
using Microsoft.Extensions.Options; |
|||
using PinkParrot.Infrastructure.CQRS.EventStore; |
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public class EventStoreModule : Module |
|||
{ |
|||
protected override void Load(ContainerBuilder builder) |
|||
{ |
|||
builder.Register(context => |
|||
{ |
|||
var options = context.Resolve<IOptions<EventStoreOptions>>().Value; |
|||
|
|||
var eventStore = |
|||
EventStoreConnection.Create( |
|||
ConnectionSettings.Create() |
|||
.UseConsoleLogger() |
|||
.UseDebugLogger() |
|||
.KeepReconnecting() |
|||
.KeepRetrying(), |
|||
new IPEndPoint(IPAddress.Parse(options.IPAddress), options.Port)); |
|||
|
|||
eventStore.ConnectAsync().Wait(); |
|||
|
|||
return eventStore; |
|||
}).SingleInstance(); |
|||
|
|||
builder.Register(context => |
|||
{ |
|||
var options = context.Resolve<IOptions<EventStoreOptions>>().Value; |
|||
|
|||
return new UserCredentials(options.Username, options.Password); |
|||
}).SingleInstance(); |
|||
|
|||
builder.Register(context => |
|||
{ |
|||
var options = context.Resolve<IOptions<EventStoreOptions>>().Value; |
|||
|
|||
return new DefaultNameResolver(options.Prefix); |
|||
}).SingleInstance(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
// ==========================================================================
|
|||
// EventStoreOptions.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public sealed class EventStoreOptions |
|||
{ |
|||
public string IPAddress { get; set; } |
|||
|
|||
public string Username { get; set; } |
|||
|
|||
public string Password { get; set; } |
|||
|
|||
public string Prefix { get; set; } |
|||
|
|||
public int Port { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
// ==========================================================================
|
|||
// EventStoreUsage.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Options; |
|||
using PinkParrot.Infrastructure.CQRS.EventStore; |
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public static class EventStoreUsage |
|||
{ |
|||
public static void UseEventStore(this IApplicationBuilder app) |
|||
{ |
|||
var options = app.ApplicationServices.GetService<IOptions<EventStoreOptions>>().Value; |
|||
|
|||
app.ApplicationServices.GetService<EventStoreBus>().Subscribe(options.Prefix); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
// ==========================================================================
|
|||
// IdentityOptions.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public sealed class IdentityOptions |
|||
{ |
|||
public string DefaultUsername { get; set; } |
|||
|
|||
public string DefaultPassword { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
// ==========================================================================
|
|||
// IdentityUsage.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.Identity; |
|||
using Microsoft.AspNetCore.Identity.MongoDB; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Options; |
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public static class IdentityUsage |
|||
{ |
|||
public static void UseDefaultUser(this IApplicationBuilder app) |
|||
{ |
|||
var options = app.ApplicationServices.GetService<IOptions<IdentityOptions>>().Value; |
|||
|
|||
var username = options.DefaultUsername; |
|||
var userManager = app.ApplicationServices.GetService<UserManager<IdentityUser>>(); |
|||
|
|||
if (!string.IsNullOrWhiteSpace(options.DefaultUsername) && |
|||
!string.IsNullOrWhiteSpace(options.DefaultPassword)) |
|||
{ |
|||
Task.Run(async () => |
|||
{ |
|||
if (userManager.SupportsQueryableUsers && !userManager.Users.Any()) |
|||
{ |
|||
var user = new IdentityUser { UserName = username, Email = username, EmailConfirmed = true }; |
|||
|
|||
await userManager.CreateAsync(user, options.DefaultPassword); |
|||
} |
|||
}).Wait(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
// ==========================================================================
|
|||
// InfrastructureUsage.cs
|
|||
// PinkParrot Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) PinkParrot Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using Microsoft.AspNetCore.Builder; |
|||
using PinkParrot.Pipeline; |
|||
|
|||
namespace PinkParrot.Configurations |
|||
{ |
|||
public static class InfrastructureUsage |
|||
{ |
|||
public static void UseTenants(this IApplicationBuilder app) |
|||
{ |
|||
app.UseMiddleware<TenantMiddleware>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
{ |
|||
"MongoDb": { |
|||
"ConnectionString": "mongodb://localhost", |
|||
"DatabaseName": "PinkParrot" |
|||
}, |
|||
"EventStore": { |
|||
"IPAddress": "127.0.0.1", |
|||
"Port": 1113, |
|||
"Prefix": "pinkparrot", |
|||
"Username": "admin", |
|||
"Password": "changeit" |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using PinkParrot.Infrastructure; |
|||
using PinkParrot.Write.Apps; |
|||
using PinkParrot.Write.Apps.Commands; |
|||
using Xunit; |
|||
|
|||
namespace PinkParrot.Write.Tests.Apps |
|||
{ |
|||
public class AppDomainObjectTest |
|||
{ |
|||
private readonly AppDomainObject sut = new AppDomainObject(Guid.NewGuid(), 0); |
|||
|
|||
[Fact] |
|||
public void Create_should_throw_if_created() |
|||
{ |
|||
sut.Create(new CreateApp { Name = "app" }); |
|||
|
|||
Assert.Throws<DomainException>(() => sut.Create(new CreateApp { Name = "app" })); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Create_should_specify_name() |
|||
{ |
|||
sut.Create(new CreateApp { Name = "app" }); |
|||
|
|||
Assert.Equal("app", sut.Name); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<PropertyGroup> |
|||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> |
|||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> |
|||
</PropertyGroup> |
|||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> |
|||
<PropertyGroup Label="Globals"> |
|||
<ProjectGuid>9a3dea7e-1681-4d48-ac5c-1f0de421a203</ProjectGuid> |
|||
<RootNamespace>PinkParrot.Write.Tests</RootNamespace> |
|||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath> |
|||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath> |
|||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> |
|||
</PropertyGroup> |
|||
<PropertyGroup> |
|||
<SchemaVersion>2.0</SchemaVersion> |
|||
</PropertyGroup> |
|||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> |
|||
</Project> |
|||
@ -0,0 +1,19 @@ |
|||
using System.Reflection; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
// General Information about an assembly is controlled through the following
|
|||
// set of attributes. Change these attribute values to modify the information
|
|||
// associated with an assembly.
|
|||
[assembly: AssemblyConfiguration("")] |
|||
[assembly: AssemblyCompany("")] |
|||
[assembly: AssemblyProduct("PinkParrot.Write.Tests")] |
|||
[assembly: AssemblyTrademark("")] |
|||
|
|||
// Setting ComVisible to false makes the types in this assembly not visible
|
|||
// to COM components. If you need to access a type in this assembly from
|
|||
// COM, set the ComVisible attribute to true on that type.
|
|||
[assembly: ComVisible(false)] |
|||
|
|||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|||
[assembly: Guid("6b9364c6-94a1-4631-9cf1-87616afaf1ea")] |
|||
@ -0,0 +1,31 @@ |
|||
{ |
|||
"buildOptions": { |
|||
"copyToOutput": { |
|||
"include": [ |
|||
"xunit.runner.json" |
|||
] |
|||
} |
|||
}, |
|||
"dependencies": { |
|||
"dotnet-test-xunit": "2.2.0-preview2-build1029", |
|||
"PinkParrot.Core": "1.0.0-*", |
|||
"PinkParrot.Infrastructure": "1.0.0-*", |
|||
"PinkParrot.Write": "1.0.0-*", |
|||
"xunit": "2.2.0-beta3-build3402" |
|||
}, |
|||
"frameworks": { |
|||
"netcoreapp1.0": { |
|||
"dependencies": { |
|||
"Microsoft.NETCore.App": { |
|||
"type": "platform", |
|||
"version": "1.0.1" |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"testRunner": "xunit", |
|||
"tooling": { |
|||
"defaultNamespace": "PinkParrot.Core.Tests" |
|||
}, |
|||
"version": "1.0.0-*" |
|||
} |
|||
Loading…
Reference in new issue