diff --git a/src/Squidex.Domain.Apps.Core/Apps/PermissionLevel.cs b/src/Squidex.Domain.Apps.Core/Apps/PermissionLevel.cs
index c60b1f0eb..06ec9cb06 100644
--- a/src/Squidex.Domain.Apps.Core/Apps/PermissionLevel.cs
+++ b/src/Squidex.Domain.Apps.Core/Apps/PermissionLevel.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Core.Apps
{
public enum PermissionLevel
diff --git a/src/Squidex.Domain.Apps.Core/Identity/SquidexClaimTypes.cs b/src/Squidex.Domain.Apps.Core/Identity/SquidexClaimTypes.cs
index 08004ca47..b0b071e50 100644
--- a/src/Squidex.Domain.Apps.Core/Identity/SquidexClaimTypes.cs
+++ b/src/Squidex.Domain.Apps.Core/Identity/SquidexClaimTypes.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Core.Identity
{
public static class SquidexClaimTypes
diff --git a/src/Squidex.Domain.Apps.Core/Identity/SquidexRoles.cs b/src/Squidex.Domain.Apps.Core/Identity/SquidexRoles.cs
index 5ed5df31c..3031c17e4 100644
--- a/src/Squidex.Domain.Apps.Core/Identity/SquidexRoles.cs
+++ b/src/Squidex.Domain.Apps.Core/Identity/SquidexRoles.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Core.Identity
{
public static class SquidexRoles
diff --git a/src/Squidex.Domain.Apps.Core/Schemas/BooleanFieldEditor.cs b/src/Squidex.Domain.Apps.Core/Schemas/BooleanFieldEditor.cs
index b82b6be70..6be38b6f9 100644
--- a/src/Squidex.Domain.Apps.Core/Schemas/BooleanFieldEditor.cs
+++ b/src/Squidex.Domain.Apps.Core/Schemas/BooleanFieldEditor.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Core.Schemas
{
public enum BooleanFieldEditor
diff --git a/src/Squidex.Domain.Apps.Core/Schemas/DateTimeCalculatedDefaultValue.cs b/src/Squidex.Domain.Apps.Core/Schemas/DateTimeCalculatedDefaultValue.cs
index 4395ad2c0..0e71b0187 100644
--- a/src/Squidex.Domain.Apps.Core/Schemas/DateTimeCalculatedDefaultValue.cs
+++ b/src/Squidex.Domain.Apps.Core/Schemas/DateTimeCalculatedDefaultValue.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Core.Schemas
{
public enum DateTimeCalculatedDefaultValue
diff --git a/src/Squidex.Domain.Apps.Core/Schemas/DateTimeFieldEditor.cs b/src/Squidex.Domain.Apps.Core/Schemas/DateTimeFieldEditor.cs
index d144cad0b..cb2be2f19 100644
--- a/src/Squidex.Domain.Apps.Core/Schemas/DateTimeFieldEditor.cs
+++ b/src/Squidex.Domain.Apps.Core/Schemas/DateTimeFieldEditor.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Core.Schemas
{
public enum DateTimeFieldEditor
diff --git a/src/Squidex.Domain.Apps.Core/Schemas/GeolocationFieldEditor.cs b/src/Squidex.Domain.Apps.Core/Schemas/GeolocationFieldEditor.cs
index 2100ee084..d6f3acff7 100644
--- a/src/Squidex.Domain.Apps.Core/Schemas/GeolocationFieldEditor.cs
+++ b/src/Squidex.Domain.Apps.Core/Schemas/GeolocationFieldEditor.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Core.Schemas
{
public enum GeolocationFieldEditor
diff --git a/src/Squidex.Domain.Apps.Core/Schemas/NumberFieldEditor.cs b/src/Squidex.Domain.Apps.Core/Schemas/NumberFieldEditor.cs
index 57c562cf7..28f164ef8 100644
--- a/src/Squidex.Domain.Apps.Core/Schemas/NumberFieldEditor.cs
+++ b/src/Squidex.Domain.Apps.Core/Schemas/NumberFieldEditor.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Core.Schemas
{
public enum NumberFieldEditor
diff --git a/src/Squidex.Domain.Apps.Core/Schemas/SchemaProperties.cs b/src/Squidex.Domain.Apps.Core/Schemas/SchemaProperties.cs
index 2a5618c36..4731958e7 100644
--- a/src/Squidex.Domain.Apps.Core/Schemas/SchemaProperties.cs
+++ b/src/Squidex.Domain.Apps.Core/Schemas/SchemaProperties.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Core.Schemas
{
public sealed class SchemaProperties : NamedElementPropertiesBase
diff --git a/src/Squidex.Domain.Apps.Core/Schemas/StringFieldEditor.cs b/src/Squidex.Domain.Apps.Core/Schemas/StringFieldEditor.cs
index 3af038292..1226fef19 100644
--- a/src/Squidex.Domain.Apps.Core/Schemas/StringFieldEditor.cs
+++ b/src/Squidex.Domain.Apps.Core/Schemas/StringFieldEditor.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Core.Schemas
{
public enum StringFieldEditor
diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Squidex.Domain.Apps.Read.MongoDb.csproj b/src/Squidex.Domain.Apps.Read.MongoDb/Squidex.Domain.Apps.Read.MongoDb.csproj
index 833fd3e2e..668717ccb 100644
--- a/src/Squidex.Domain.Apps.Read.MongoDb/Squidex.Domain.Apps.Read.MongoDb.csproj
+++ b/src/Squidex.Domain.Apps.Read.MongoDb/Squidex.Domain.Apps.Read.MongoDb.csproj
@@ -24,9 +24,4 @@
-
-
- C:\Users\mail2\.nuget\packages\system.reflection.metadata\1.4.1\lib\netstandard1.1\System.Reflection.Metadata.dll
-
-
diff --git a/src/Squidex.Domain.Apps.Read/Apps/IAppClientEntity.cs b/src/Squidex.Domain.Apps.Read/Apps/IAppClientEntity.cs
index bd02ee85a..8a5e04edf 100644
--- a/src/Squidex.Domain.Apps.Read/Apps/IAppClientEntity.cs
+++ b/src/Squidex.Domain.Apps.Read/Apps/IAppClientEntity.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Read.Apps
{
public interface IAppClientEntity
diff --git a/src/Squidex.Domain.Apps.Read/Apps/Services/IAppLimitsPlan.cs b/src/Squidex.Domain.Apps.Read/Apps/Services/IAppLimitsPlan.cs
index e6ef5ab03..3bc0a0012 100644
--- a/src/Squidex.Domain.Apps.Read/Apps/Services/IAppLimitsPlan.cs
+++ b/src/Squidex.Domain.Apps.Read/Apps/Services/IAppLimitsPlan.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Read.Apps.Services
{
public interface IAppLimitsPlan
diff --git a/src/Squidex.Domain.Apps.Read/Apps/Services/Implementations/ConfigAppLimitsPlan.cs b/src/Squidex.Domain.Apps.Read/Apps/Services/Implementations/ConfigAppLimitsPlan.cs
index e5e3d1476..0ed64ddcb 100644
--- a/src/Squidex.Domain.Apps.Read/Apps/Services/Implementations/ConfigAppLimitsPlan.cs
+++ b/src/Squidex.Domain.Apps.Read/Apps/Services/Implementations/ConfigAppLimitsPlan.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Read.Apps.Services.Implementations
{
public sealed class ConfigAppLimitsPlan : IAppLimitsPlan
diff --git a/src/Squidex.Domain.Apps.Read/Assets/IAssetEntity.cs b/src/Squidex.Domain.Apps.Read/Assets/IAssetEntity.cs
index 0bd1a25c5..ac23e8fd4 100644
--- a/src/Squidex.Domain.Apps.Read/Assets/IAssetEntity.cs
+++ b/src/Squidex.Domain.Apps.Read/Assets/IAssetEntity.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Read.Assets
{
public interface IAssetEntity : IAppRefEntity, IEntityWithCreatedBy, IEntityWithLastModifiedBy, IEntityWithVersion
diff --git a/src/Squidex.Domain.Apps.Read/IEntityWithVersion.cs b/src/Squidex.Domain.Apps.Read/IEntityWithVersion.cs
index 4eb2c50af..b80ed6b08 100644
--- a/src/Squidex.Domain.Apps.Read/IEntityWithVersion.cs
+++ b/src/Squidex.Domain.Apps.Read/IEntityWithVersion.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Read
{
public interface IEntityWithVersion
diff --git a/src/Squidex.Domain.Apps.Read/Schemas/WebhookResult.cs b/src/Squidex.Domain.Apps.Read/Schemas/WebhookResult.cs
index db82786d5..df9360b3d 100644
--- a/src/Squidex.Domain.Apps.Read/Schemas/WebhookResult.cs
+++ b/src/Squidex.Domain.Apps.Read/Schemas/WebhookResult.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Read.Schemas
{
public enum WebhookResult
diff --git a/src/Squidex.Domain.Apps.Read/Users/ExternalLogin.cs b/src/Squidex.Domain.Apps.Read/Users/ExternalLogin.cs
index 04afa5749..a618757ff 100644
--- a/src/Squidex.Domain.Apps.Read/Users/ExternalLogin.cs
+++ b/src/Squidex.Domain.Apps.Read/Users/ExternalLogin.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Read.Users
{
public sealed class ExternalLogin
diff --git a/src/Squidex.Domain.Apps.Read/Users/IRole.cs b/src/Squidex.Domain.Apps.Read/Users/IRole.cs
index 2daea1d65..558e520e1 100644
--- a/src/Squidex.Domain.Apps.Read/Users/IRole.cs
+++ b/src/Squidex.Domain.Apps.Read/Users/IRole.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Read.Users
{
public interface IRole
diff --git a/src/Squidex.Domain.Apps.Read/Users/IRoleFactory.cs b/src/Squidex.Domain.Apps.Read/Users/IRoleFactory.cs
index a54d681c1..930dea5ac 100644
--- a/src/Squidex.Domain.Apps.Read/Users/IRoleFactory.cs
+++ b/src/Squidex.Domain.Apps.Read/Users/IRoleFactory.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Read.Users
{
public interface IRoleFactory
diff --git a/src/Squidex.Domain.Apps.Read/Users/IUserFactory.cs b/src/Squidex.Domain.Apps.Read/Users/IUserFactory.cs
index 53c298ec0..573b8715b 100644
--- a/src/Squidex.Domain.Apps.Read/Users/IUserFactory.cs
+++ b/src/Squidex.Domain.Apps.Read/Users/IUserFactory.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Read.Users
{
public interface IUserFactory
diff --git a/src/Squidex.Domain.Apps.Write/Assets/Commands/DeleteAsset.cs b/src/Squidex.Domain.Apps.Write/Assets/Commands/DeleteAsset.cs
index ff27b0b63..a9cfd5cfe 100644
--- a/src/Squidex.Domain.Apps.Write/Assets/Commands/DeleteAsset.cs
+++ b/src/Squidex.Domain.Apps.Write/Assets/Commands/DeleteAsset.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Assets.Commands
{
public sealed class DeleteAsset : AssetAggregateCommand
diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/DeleteContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/DeleteContent.cs
index 738fad329..210815c1f 100644
--- a/src/Squidex.Domain.Apps.Write/Contents/Commands/DeleteContent.cs
+++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/DeleteContent.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Contents.Commands
{
public class DeleteContent : ContentCommand
diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/PatchContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/PatchContent.cs
index f49c799b7..d14f5f5f8 100644
--- a/src/Squidex.Domain.Apps.Write/Contents/Commands/PatchContent.cs
+++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/PatchContent.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Contents.Commands
{
public class PatchContent : ContentDataCommand
diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/PublishContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/PublishContent.cs
index 184a5644f..f6227ee79 100644
--- a/src/Squidex.Domain.Apps.Write/Contents/Commands/PublishContent.cs
+++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/PublishContent.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Contents.Commands
{
public class PublishContent : ContentCommand
diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/UnpublishContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/UnpublishContent.cs
index 5b169b4b4..c0a63beae 100644
--- a/src/Squidex.Domain.Apps.Write/Contents/Commands/UnpublishContent.cs
+++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/UnpublishContent.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Contents.Commands
{
public class UnpublishContent : ContentCommand
diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/UpdateContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/UpdateContent.cs
index ce3820262..87b824b25 100644
--- a/src/Squidex.Domain.Apps.Write/Contents/Commands/UpdateContent.cs
+++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/UpdateContent.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Contents.Commands
{
public class UpdateContent : ContentDataCommand
diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/DeleteField.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/DeleteField.cs
index 1ba90df08..3d4d987f4 100644
--- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/DeleteField.cs
+++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/DeleteField.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Schemas.Commands
{
public class DeleteField : FieldCommand
diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/DeleteSchema.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/DeleteSchema.cs
index 841f9935e..66ee9e9ae 100644
--- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/DeleteSchema.cs
+++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/DeleteSchema.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Schemas.Commands
{
public class DeleteSchema : SchemaAggregateCommand
diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/DisableField.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/DisableField.cs
index d916192e4..4fd5a0548 100644
--- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/DisableField.cs
+++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/DisableField.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Schemas.Commands
{
public class DisableField : FieldCommand
diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/EnableField.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/EnableField.cs
index dd9933c0c..678ab9781 100644
--- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/EnableField.cs
+++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/EnableField.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Schemas.Commands
{
public class EnableField : FieldCommand
diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/FieldCommand.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/FieldCommand.cs
index a9d3d05a1..4fe5f6b6f 100644
--- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/FieldCommand.cs
+++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/FieldCommand.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Schemas.Commands
{
public class FieldCommand : SchemaAggregateCommand
diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/HideField.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/HideField.cs
index 1dc20d1ab..31e92ab8a 100644
--- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/HideField.cs
+++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/HideField.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Schemas.Commands
{
public class HideField : FieldCommand
diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/PublishSchema.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/PublishSchema.cs
index d4d63d3da..1e04b79af 100644
--- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/PublishSchema.cs
+++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/PublishSchema.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Schemas.Commands
{
public class PublishSchema : SchemaAggregateCommand
diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/ShowField.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/ShowField.cs
index 48a8e2565..83b01c10c 100644
--- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/ShowField.cs
+++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/ShowField.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Schemas.Commands
{
public class ShowField : FieldCommand
diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/UnpublishSchema.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/UnpublishSchema.cs
index 387cdd34e..119ac26a1 100644
--- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/UnpublishSchema.cs
+++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/UnpublishSchema.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Domain.Apps.Write.Schemas.Commands
{
public class UnpublishSchema : SchemaAggregateCommand
diff --git a/src/Squidex.Domain.Users.MongoDb/MongoRoleStore.cs b/src/Squidex.Domain.Users.MongoDb/MongoRoleStore.cs
new file mode 100644
index 000000000..765b76514
--- /dev/null
+++ b/src/Squidex.Domain.Users.MongoDb/MongoRoleStore.cs
@@ -0,0 +1,92 @@
+// ==========================================================================
+// MongoRoleStore.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Identity.MongoDB;
+using MongoDB.Driver;
+
+namespace Squidex.Domain.Users.MongoDb
+{
+ public sealed class MongoRoleStore :
+ IRoleStore,
+ IRoleFactory
+ {
+ private readonly RoleStore innerStore;
+
+ public MongoRoleStore(IMongoDatabase database)
+ {
+ var rolesCollection = database.GetCollection("Identity_Roles");
+
+ IndexChecks.EnsureUniqueIndexOnNormalizedRoleName(rolesCollection);
+
+ innerStore = new RoleStore(rolesCollection);
+ }
+
+ public void Dispose()
+ {
+ innerStore.Dispose();
+ }
+
+ public IRole Create(string name)
+ {
+ return new WrappedIdentityRole { Name = name };
+ }
+
+ public async Task FindByIdAsync(string roleId, CancellationToken cancellationToken)
+ {
+ return await innerStore.FindByIdAsync(roleId, cancellationToken);
+ }
+
+ public async Task FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken)
+ {
+ return await innerStore.FindByNameAsync(normalizedRoleName, cancellationToken);
+ }
+
+ public Task CreateAsync(IRole role, CancellationToken cancellationToken)
+ {
+ return innerStore.CreateAsync((WrappedIdentityRole)role, cancellationToken);
+ }
+
+ public Task UpdateAsync(IRole role, CancellationToken cancellationToken)
+ {
+ return innerStore.UpdateAsync((WrappedIdentityRole)role, cancellationToken);
+ }
+
+ public Task DeleteAsync(IRole role, CancellationToken cancellationToken)
+ {
+ return innerStore.DeleteAsync((WrappedIdentityRole)role, cancellationToken);
+ }
+
+ public Task GetRoleIdAsync(IRole role, CancellationToken cancellationToken)
+ {
+ return innerStore.GetRoleIdAsync((WrappedIdentityRole)role, cancellationToken);
+ }
+
+ public Task GetRoleNameAsync(IRole role, CancellationToken cancellationToken)
+ {
+ return innerStore.GetRoleNameAsync((WrappedIdentityRole)role, cancellationToken);
+ }
+
+ public Task SetRoleNameAsync(IRole role, string roleName, CancellationToken cancellationToken)
+ {
+ return innerStore.SetRoleNameAsync((WrappedIdentityRole)role, roleName, cancellationToken);
+ }
+
+ public Task GetNormalizedRoleNameAsync(IRole role, CancellationToken cancellationToken)
+ {
+ return innerStore.GetNormalizedRoleNameAsync((WrappedIdentityRole)role, cancellationToken);
+ }
+
+ public Task SetNormalizedRoleNameAsync(IRole role, string normalizedName, CancellationToken cancellationToken)
+ {
+ return innerStore.SetNormalizedRoleNameAsync((WrappedIdentityRole)role, normalizedName, cancellationToken);
+ }
+ }
+}
diff --git a/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs b/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs
new file mode 100644
index 000000000..33f5facd7
--- /dev/null
+++ b/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs
@@ -0,0 +1,329 @@
+// ==========================================================================
+// MongoUserStore.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Identity.MongoDB;
+using MongoDB.Driver;
+using Squidex.Shared.Users;
+
+namespace Squidex.Domain.Users.MongoDb
+{
+ public sealed class MongoUserStore :
+ IUserPasswordStore,
+ IUserRoleStore,
+ IUserLoginStore,
+ IUserSecurityStampStore,
+ IUserEmailStore,
+ IUserClaimStore,
+ IUserPhoneNumberStore,
+ IUserTwoFactorStore,
+ IUserLockoutStore,
+ IUserAuthenticationTokenStore,
+ IUserFactory,
+ IUserResolver,
+ IQueryableUserStore
+ {
+ private readonly UserStore innerStore;
+
+ public MongoUserStore(IMongoDatabase database)
+ {
+ var usersCollection = database.GetCollection("Identity_Users");
+
+ IndexChecks.EnsureUniqueIndexOnNormalizedEmail(usersCollection);
+ IndexChecks.EnsureUniqueIndexOnNormalizedUserName(usersCollection);
+
+ innerStore = new UserStore(usersCollection);
+ }
+
+ public void Dispose()
+ {
+ innerStore.Dispose();
+ }
+
+ public IQueryable Users
+ {
+ get { return innerStore.Users; }
+ }
+
+ public IUser Create(string email)
+ {
+ return new WrappedIdentityUser { Email = email, UserName = email };
+ }
+
+ public async Task FindByIdAsync(string userId)
+ {
+ return await innerStore.FindByIdAsync(userId, CancellationToken.None);
+ }
+
+ public async Task FindByIdAsync(string userId, CancellationToken cancellationToken)
+ {
+ return await innerStore.FindByIdAsync(userId, cancellationToken);
+ }
+
+ public async Task FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken)
+ {
+ return await innerStore.FindByEmailAsync(normalizedEmail, cancellationToken);
+ }
+
+ public async Task FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
+ {
+ return await innerStore.FindByNameAsync(normalizedUserName, cancellationToken);
+ }
+
+ public async Task FindByLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken)
+ {
+ return await innerStore.FindByLoginAsync(loginProvider, providerKey, cancellationToken);
+ }
+
+ public async Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken)
+ {
+ return (await innerStore.GetUsersForClaimAsync(claim, cancellationToken)).OfType().ToList();
+ }
+
+ public async Task> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken)
+ {
+ return (await innerStore.GetUsersInRoleAsync(roleName, cancellationToken)).OfType().ToList();
+ }
+
+ public Task CreateAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.CreateAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task UpdateAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.UpdateAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task DeleteAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.DeleteAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task GetUserIdAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetUserIdAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task GetUserNameAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetUserNameAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetUserNameAsync(IUser user, string userName, CancellationToken cancellationToken)
+ {
+ return innerStore.SetUserNameAsync((WrappedIdentityUser)user, userName, cancellationToken);
+ }
+
+ public Task GetNormalizedUserNameAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetNormalizedUserNameAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetNormalizedUserNameAsync(IUser user, string normalizedName, CancellationToken cancellationToken)
+ {
+ return innerStore.SetNormalizedUserNameAsync((WrappedIdentityUser)user, normalizedName, cancellationToken);
+ }
+
+ public Task GetPasswordHashAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetPasswordHashAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetPasswordHashAsync(IUser user, string passwordHash, CancellationToken cancellationToken)
+ {
+ return innerStore.SetPasswordHashAsync((WrappedIdentityUser)user, passwordHash, cancellationToken);
+ }
+
+ public Task AddToRoleAsync(IUser user, string roleName, CancellationToken cancellationToken)
+ {
+ return innerStore.AddToRoleAsync((WrappedIdentityUser)user, roleName, cancellationToken);
+ }
+
+ public Task RemoveFromRoleAsync(IUser user, string roleName, CancellationToken cancellationToken)
+ {
+ return innerStore.RemoveFromRoleAsync((WrappedIdentityUser)user, roleName, cancellationToken);
+ }
+
+ public Task> GetRolesAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetRolesAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task IsInRoleAsync(IUser user, string roleName, CancellationToken cancellationToken)
+ {
+ return innerStore.IsInRoleAsync((WrappedIdentityUser)user, roleName, cancellationToken);
+ }
+
+ public Task AddLoginAsync(IUser user, UserLoginInfo login, CancellationToken cancellationToken)
+ {
+ return innerStore.AddLoginAsync((WrappedIdentityUser)user, login, cancellationToken);
+ }
+
+ public Task RemoveLoginAsync(IUser user, string loginProvider, string providerKey, CancellationToken cancellationToken)
+ {
+ return innerStore.RemoveLoginAsync((WrappedIdentityUser)user, loginProvider, providerKey, cancellationToken);
+ }
+
+ public Task> GetLoginsAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetLoginsAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task GetSecurityStampAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetSecurityStampAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetSecurityStampAsync(IUser user, string stamp, CancellationToken cancellationToken)
+ {
+ return innerStore.SetSecurityStampAsync((WrappedIdentityUser)user, stamp, cancellationToken);
+ }
+
+ public Task GetEmailAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetEmailAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetEmailAsync(IUser user, string email, CancellationToken cancellationToken)
+ {
+ return innerStore.SetEmailAsync((WrappedIdentityUser)user, email, cancellationToken);
+ }
+
+ public Task GetEmailConfirmedAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetEmailConfirmedAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetEmailConfirmedAsync(IUser user, bool confirmed, CancellationToken cancellationToken)
+ {
+ return innerStore.SetEmailConfirmedAsync((WrappedIdentityUser)user, confirmed, cancellationToken);
+ }
+
+ public Task GetNormalizedEmailAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetNormalizedEmailAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetNormalizedEmailAsync(IUser user, string normalizedEmail, CancellationToken cancellationToken)
+ {
+ return innerStore.SetNormalizedEmailAsync((WrappedIdentityUser)user, normalizedEmail, cancellationToken);
+ }
+
+ public Task> GetClaimsAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetClaimsAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task AddClaimsAsync(IUser user, IEnumerable claims, CancellationToken cancellationToken)
+ {
+ return innerStore.AddClaimsAsync((WrappedIdentityUser)user, claims, cancellationToken);
+ }
+
+ public Task ReplaceClaimAsync(IUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken)
+ {
+ return innerStore.ReplaceClaimAsync((WrappedIdentityUser)user, claim, newClaim, cancellationToken);
+ }
+
+ public Task RemoveClaimsAsync(IUser user, IEnumerable claims, CancellationToken cancellationToken)
+ {
+ return innerStore.RemoveClaimsAsync((WrappedIdentityUser)user, claims, cancellationToken);
+ }
+
+ public Task GetPhoneNumberAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetPhoneNumberAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetPhoneNumberAsync(IUser user, string phoneNumber, CancellationToken cancellationToken)
+ {
+ return innerStore.SetPhoneNumberAsync((WrappedIdentityUser)user, phoneNumber, cancellationToken);
+ }
+
+ public Task GetPhoneNumberConfirmedAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetPhoneNumberConfirmedAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetPhoneNumberConfirmedAsync(IUser user, bool confirmed, CancellationToken cancellationToken)
+ {
+ return innerStore.SetPhoneNumberConfirmedAsync((WrappedIdentityUser)user, confirmed, cancellationToken);
+ }
+
+ public Task GetTwoFactorEnabledAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetTwoFactorEnabledAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetTwoFactorEnabledAsync(IUser user, bool enabled, CancellationToken cancellationToken)
+ {
+ return innerStore.SetTwoFactorEnabledAsync((WrappedIdentityUser)user, enabled, cancellationToken);
+ }
+
+ public Task GetLockoutEndDateAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetLockoutEndDateAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetLockoutEndDateAsync(IUser user, DateTimeOffset? lockoutEnd, CancellationToken cancellationToken)
+ {
+ return innerStore.SetLockoutEndDateAsync((WrappedIdentityUser)user, lockoutEnd, cancellationToken);
+ }
+
+ public Task GetAccessFailedCountAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetAccessFailedCountAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task IncrementAccessFailedCountAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.IncrementAccessFailedCountAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task ResetAccessFailedCountAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.ResetAccessFailedCountAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task GetLockoutEnabledAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return innerStore.GetLockoutEnabledAsync((WrappedIdentityUser)user, cancellationToken);
+ }
+
+ public Task SetLockoutEnabledAsync(IUser user, bool enabled, CancellationToken cancellationToken)
+ {
+ return innerStore.SetLockoutEnabledAsync((WrappedIdentityUser)user, enabled, cancellationToken);
+ }
+
+ public Task SetTokenAsync(IUser user, string loginProvider, string name, string value, CancellationToken cancellationToken)
+ {
+ return innerStore.SetTokenAsync((WrappedIdentityUser)user, loginProvider, name, value, cancellationToken);
+ }
+
+ public Task RemoveTokenAsync(IUser user, string loginProvider, string name, CancellationToken cancellationToken)
+ {
+ return innerStore.RemoveTokenAsync((WrappedIdentityUser)user, loginProvider, name, cancellationToken);
+ }
+
+ public Task GetTokenAsync(IUser user, string loginProvider, string name, CancellationToken cancellationToken)
+ {
+ return innerStore.GetTokenAsync((WrappedIdentityUser)user, loginProvider, name, cancellationToken);
+ }
+
+ public Task HasPasswordAsync(IUser user, CancellationToken cancellationToken)
+ {
+ return Task.FromResult(!string.IsNullOrWhiteSpace(((WrappedIdentityUser)user).PasswordHash));
+ }
+ }
+}
diff --git a/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj b/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj
new file mode 100644
index 000000000..b6da5d210
--- /dev/null
+++ b/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj
@@ -0,0 +1,19 @@
+
+
+ netstandard1.6
+
+
+ full
+ True
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Squidex.Domain.Users.MongoDb/WrappedIdentityRole.cs b/src/Squidex.Domain.Users.MongoDb/WrappedIdentityRole.cs
new file mode 100644
index 000000000..fee399a23
--- /dev/null
+++ b/src/Squidex.Domain.Users.MongoDb/WrappedIdentityRole.cs
@@ -0,0 +1,16 @@
+// ==========================================================================
+// WrappedIdentityRole.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using Microsoft.AspNetCore.Identity.MongoDB;
+
+namespace Squidex.Domain.Users.MongoDb
+{
+ public sealed class WrappedIdentityRole : IdentityRole, IRole
+ {
+ }
+}
diff --git a/src/Squidex.Domain.Users.MongoDb/WrappedIdentityUser.cs b/src/Squidex.Domain.Users.MongoDb/WrappedIdentityUser.cs
new file mode 100644
index 000000000..abbce010a
--- /dev/null
+++ b/src/Squidex.Domain.Users.MongoDb/WrappedIdentityUser.cs
@@ -0,0 +1,46 @@
+// ==========================================================================
+// WrappedIdentityUser.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using Microsoft.AspNetCore.Identity.MongoDB;
+using Squidex.Shared.Users;
+
+namespace Squidex.Domain.Users.MongoDb
+{
+ public sealed class WrappedIdentityUser : IdentityUser, IUser
+ {
+ public bool IsLocked
+ {
+ get { return LockoutEndDateUtc != null && LockoutEndDateUtc.Value > DateTime.UtcNow; }
+ }
+
+ IReadOnlyList IUser.Claims
+ {
+ get { return Claims.Select(x => new Claim(x.Type, x.Value)).ToList(); }
+ }
+
+ IReadOnlyList IUser.Logins
+ {
+ get { return Logins.Select(x => new ExternalLogin(x.LoginProvider, x.ProviderKey, x.ProviderDisplayName)).ToList(); }
+ }
+
+ public void UpdateEmail(string email)
+ {
+ Email = UserName = email;
+ }
+
+ public void SetClaim(string type, string value)
+ {
+ Claims.RemoveAll(x => string.Equals(x.Type, type, StringComparison.OrdinalIgnoreCase));
+ Claims.Add(new IdentityUserClaim { Type = type, Value = value });
+ }
+ }
+}
diff --git a/src/Squidex.Domain.Users/AssetUserPictureStore.cs b/src/Squidex.Domain.Users/AssetUserPictureStore.cs
new file mode 100644
index 000000000..00780a709
--- /dev/null
+++ b/src/Squidex.Domain.Users/AssetUserPictureStore.cs
@@ -0,0 +1,43 @@
+// ==========================================================================
+// AssetUserPictureStore.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using System.IO;
+using System.Threading.Tasks;
+using Squidex.Infrastructure;
+using Squidex.Infrastructure.Assets;
+
+namespace Squidex.Domain.Users
+{
+ public sealed class AssetUserPictureStore : IUserPictureStore
+ {
+ private readonly IAssetStore assetStore;
+
+ public AssetUserPictureStore(IAssetStore assetStore)
+ {
+ Guard.NotNull(assetStore, nameof(assetStore));
+
+ this.assetStore = assetStore;
+ }
+
+ public Task UploadAsync(string userId, Stream stream)
+ {
+ return assetStore.UploadAsync(userId, 0, "picture", stream);
+ }
+
+ public async Task DownloadAsync(string userId)
+ {
+ var memoryStream = new MemoryStream();
+
+ await assetStore.DownloadAsync(userId, 0, "picture", memoryStream);
+
+ memoryStream.Position = 0;
+
+ return memoryStream;
+ }
+ }
+}
diff --git a/src/Squidex.Domain.Users/IRole.cs b/src/Squidex.Domain.Users/IRole.cs
new file mode 100644
index 000000000..9c3b55f09
--- /dev/null
+++ b/src/Squidex.Domain.Users/IRole.cs
@@ -0,0 +1,15 @@
+// ==========================================================================
+// IRole.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+namespace Squidex.Domain.Users
+{
+ public interface IRole
+ {
+ string Name { get; }
+ }
+}
diff --git a/src/Squidex.Domain.Users/IRoleFactory.cs b/src/Squidex.Domain.Users/IRoleFactory.cs
new file mode 100644
index 000000000..a9a03f3a5
--- /dev/null
+++ b/src/Squidex.Domain.Users/IRoleFactory.cs
@@ -0,0 +1,15 @@
+// ==========================================================================
+// IRoleFactory.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+namespace Squidex.Domain.Users
+{
+ public interface IRoleFactory
+ {
+ IRole Create(string name);
+ }
+}
diff --git a/src/Squidex.Domain.Users/IUserFactory.cs b/src/Squidex.Domain.Users/IUserFactory.cs
new file mode 100644
index 000000000..fef18423a
--- /dev/null
+++ b/src/Squidex.Domain.Users/IUserFactory.cs
@@ -0,0 +1,17 @@
+// ==========================================================================
+// IUserFactory.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using Squidex.Shared.Users;
+
+namespace Squidex.Domain.Users
+{
+ public interface IUserFactory
+ {
+ IUser Create(string email);
+ }
+}
diff --git a/src/Squidex.Domain.Users/IUserPictureStore.cs b/src/Squidex.Domain.Users/IUserPictureStore.cs
new file mode 100644
index 000000000..2f2abaac9
--- /dev/null
+++ b/src/Squidex.Domain.Users/IUserPictureStore.cs
@@ -0,0 +1,20 @@
+// ==========================================================================
+// IUserPictureStore.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Squidex.Domain.Users
+{
+ public interface IUserPictureStore
+ {
+ Task UploadAsync(string userId, Stream stream);
+
+ Task DownloadAsync(string userId);
+ }
+}
diff --git a/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj b/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj
new file mode 100644
index 000000000..2d3950684
--- /dev/null
+++ b/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj
@@ -0,0 +1,17 @@
+
+
+ netstandard1.6
+
+
+ full
+ True
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Squidex.Domain.Users/UserExtensions.cs b/src/Squidex.Domain.Users/UserExtensions.cs
new file mode 100644
index 000000000..1fe92e1f9
--- /dev/null
+++ b/src/Squidex.Domain.Users/UserExtensions.cs
@@ -0,0 +1,75 @@
+// ==========================================================================
+// UserExtensions.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using System;
+using System.Linq;
+using Squidex.Infrastructure;
+using Squidex.Shared.Identity;
+using Squidex.Shared.Users;
+
+// ReSharper disable InvertIf
+
+namespace Squidex.Domain.Users
+{
+ public static class UserExtensions
+ {
+ public static void UpdateDisplayName(this IUser user, string displayName)
+ {
+ user.SetClaim(SquidexClaimTypes.SquidexDisplayName, displayName);
+ }
+
+ public static void SetPictureUrl(this IUser user, string pictureUrl)
+ {
+ user.SetClaim(SquidexClaimTypes.SquidexPictureUrl, pictureUrl);
+ }
+
+ public static void SetPictureUrlToStore(this IUser user)
+ {
+ user.SetClaim(SquidexClaimTypes.SquidexPictureUrl, "store");
+ }
+
+ public static void SetPictureUrlFromGravatar(this IUser user, string email)
+ {
+ user.SetClaim(SquidexClaimTypes.SquidexPictureUrl, GravatarHelper.CreatePictureUrl(email));
+ }
+
+ public static bool IsPictureUrlStored(this IUser user)
+ {
+ return string.Equals(user.Claims.FirstOrDefault(x => x.Type == SquidexClaimTypes.SquidexPictureUrl)?.Value, "store", StringComparison.OrdinalIgnoreCase);
+ }
+
+ public static string PictureUrl(this IUser user)
+ {
+ return user.Claims.FirstOrDefault(x => x.Type == SquidexClaimTypes.SquidexPictureUrl)?.Value;
+ }
+
+ public static string DisplayName(this IUser user)
+ {
+ return user.Claims.FirstOrDefault(x => x.Type == SquidexClaimTypes.SquidexDisplayName)?.Value;
+ }
+
+ public static string PictureNormalizedUrl(this IUser user)
+ {
+ var url = user.Claims.FirstOrDefault(x => x.Type == SquidexClaimTypes.SquidexPictureUrl)?.Value;
+
+ if (!string.IsNullOrWhiteSpace(url) && Uri.IsWellFormedUriString(url, UriKind.Absolute) && url.Contains("gravatar"))
+ {
+ if (url.Contains("?"))
+ {
+ url += "&d=404";
+ }
+ else
+ {
+ url += "?d=404";
+ }
+ }
+
+ return url;
+ }
+ }
+}
diff --git a/src/Squidex.Domain.Users/UserManagerExtensions.cs b/src/Squidex.Domain.Users/UserManagerExtensions.cs
new file mode 100644
index 000000000..bc9032de1
--- /dev/null
+++ b/src/Squidex.Domain.Users/UserManagerExtensions.cs
@@ -0,0 +1,132 @@
+// ==========================================================================
+// UserManagerExtensions.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity;
+using Squidex.Infrastructure;
+using Squidex.Shared.Users;
+
+// ReSharper disable ImplicitlyCapturedClosure
+// ReSharper disable InvertIf
+// ReSharper disable ReturnTypeCanBeEnumerable.Local
+
+namespace Squidex.Domain.Users
+{
+ public static class UserManagerExtensions
+ {
+ public static Task> QueryByEmailAsync(this UserManager userManager, string email = null, int take = 10, int skip = 0)
+ {
+ var users = QueryUsers(userManager, email).Skip(skip).Take(take).ToList();
+
+ return Task.FromResult>(users);
+ }
+
+ public static Task CountByEmailAsync(this UserManager userManager, string email = null)
+ {
+ var count = QueryUsers(userManager, email).LongCount();
+
+ return Task.FromResult(count);
+ }
+
+ private static IQueryable QueryUsers(UserManager userManager, string email = null)
+ {
+ var result = userManager.Users;
+
+ if (!string.IsNullOrWhiteSpace(email))
+ {
+ var upperEmail = email.ToUpperInvariant();
+
+ result = result.Where(x => x.NormalizedEmail.Contains(upperEmail));
+ }
+
+ return result;
+ }
+
+ public static async Task CreateAsync(this UserManager userManager, IUserFactory factory, string email, string displayName, string password)
+ {
+ var user = factory.Create(email);
+
+ user.UpdateDisplayName(displayName);
+ user.SetPictureUrlFromGravatar(email);
+
+ await DoChecked(() => userManager.CreateAsync(user), "Cannot create user.");
+
+ if (!string.IsNullOrWhiteSpace(password))
+ {
+ await DoChecked(() => userManager.AddPasswordAsync(user, password), "Cannot create user.");
+ }
+
+ return user;
+ }
+
+ public static async Task UpdateAsync(this UserManager userManager, string id, string email, string displayName, string password)
+ {
+ var user = await userManager.FindByIdAsync(id);
+
+ if (user == null)
+ {
+ throw new DomainObjectNotFoundException(id, typeof(IUser));
+ }
+
+ if (!string.IsNullOrWhiteSpace(email))
+ {
+ user.UpdateEmail(email);
+ }
+
+ if (!string.IsNullOrWhiteSpace(displayName))
+ {
+ user.UpdateDisplayName(displayName);
+ }
+
+ await DoChecked(() => userManager.UpdateAsync(user), "Cannot update user.");
+
+ if (!string.IsNullOrWhiteSpace(password))
+ {
+ await DoChecked(() => userManager.RemovePasswordAsync(user), "Cannot update user.");
+ await DoChecked(() => userManager.AddPasswordAsync(user, password), "Cannot update user.");
+ }
+ }
+
+ public static async Task LockAsync(this UserManager userManager, string id)
+ {
+ var user = await userManager.FindByIdAsync(id);
+
+ if (user == null)
+ {
+ throw new DomainObjectNotFoundException(id, typeof(IUser));
+ }
+
+ await DoChecked(() => userManager.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.AddYears(100)), "Cannot lock user.");
+ }
+
+ public static async Task UnlockAsync(this UserManager userManager, string id)
+ {
+ var user = await userManager.FindByIdAsync(id);
+
+ if (user == null)
+ {
+ throw new DomainObjectNotFoundException(id, typeof(IUser));
+ }
+
+ await DoChecked(() => userManager.SetLockoutEndDateAsync(user, null), "Cannot unlock user.");
+ }
+
+ private static async Task DoChecked(Func> action, string message)
+ {
+ var result = await action();
+
+ if (!result.Succeeded)
+ {
+ throw new ValidationException(message, result.Errors.Select(x => new ValidationError(x.Description)).ToArray());
+ }
+ }
+ }
+}
diff --git a/src/Squidex.Infrastructure/Assets/ImageInfo.cs b/src/Squidex.Infrastructure/Assets/ImageInfo.cs
index c4f01451f..85147ed58 100644
--- a/src/Squidex.Infrastructure/Assets/ImageInfo.cs
+++ b/src/Squidex.Infrastructure/Assets/ImageInfo.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.Assets
{
public sealed class ImageInfo
diff --git a/src/Squidex.Infrastructure/CQRS/Commands/EntityCreatedResult.cs b/src/Squidex.Infrastructure/CQRS/Commands/EntityCreatedResult.cs
index cef2f5324..259b836df 100644
--- a/src/Squidex.Infrastructure/CQRS/Commands/EntityCreatedResult.cs
+++ b/src/Squidex.Infrastructure/CQRS/Commands/EntityCreatedResult.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.CQRS.Commands
{
public static class EntityCreatedResult
diff --git a/src/Squidex.Infrastructure/CQRS/Commands/EntityCreatedResult_T.cs b/src/Squidex.Infrastructure/CQRS/Commands/EntityCreatedResult_T.cs
index d704f1cbc..7b56d620c 100644
--- a/src/Squidex.Infrastructure/CQRS/Commands/EntityCreatedResult_T.cs
+++ b/src/Squidex.Infrastructure/CQRS/Commands/EntityCreatedResult_T.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.CQRS.Commands
{
public sealed class EntityCreatedResult : EntitySavedResult
diff --git a/src/Squidex.Infrastructure/CQRS/Commands/EntitySavedResult.cs b/src/Squidex.Infrastructure/CQRS/Commands/EntitySavedResult.cs
index 2e7b280c7..deef50b7c 100644
--- a/src/Squidex.Infrastructure/CQRS/Commands/EntitySavedResult.cs
+++ b/src/Squidex.Infrastructure/CQRS/Commands/EntitySavedResult.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.CQRS.Commands
{
public class EntitySavedResult
diff --git a/src/Squidex.Infrastructure/CQRS/Commands/ICommand.cs b/src/Squidex.Infrastructure/CQRS/Commands/ICommand.cs
index c87233bd4..fb3516b3b 100644
--- a/src/Squidex.Infrastructure/CQRS/Commands/ICommand.cs
+++ b/src/Squidex.Infrastructure/CQRS/Commands/ICommand.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.CQRS.Commands
{
public interface ICommand
diff --git a/src/Squidex.Infrastructure/CQRS/Events/CommonHeaders.cs b/src/Squidex.Infrastructure/CQRS/Events/CommonHeaders.cs
index c561fc89e..617123666 100644
--- a/src/Squidex.Infrastructure/CQRS/Events/CommonHeaders.cs
+++ b/src/Squidex.Infrastructure/CQRS/Events/CommonHeaders.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.CQRS.Events
{
public static class CommonHeaders
diff --git a/src/Squidex.Infrastructure/CQRS/Events/EnvelopeHeaders.cs b/src/Squidex.Infrastructure/CQRS/Events/EnvelopeHeaders.cs
index d00193b16..f95580f9d 100644
--- a/src/Squidex.Infrastructure/CQRS/Events/EnvelopeHeaders.cs
+++ b/src/Squidex.Infrastructure/CQRS/Events/EnvelopeHeaders.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.CQRS.Events
{
public sealed class EnvelopeHeaders : PropertiesBag
diff --git a/src/Squidex.Infrastructure/CQRS/Events/Envelope_1.cs b/src/Squidex.Infrastructure/CQRS/Events/Envelope_1.cs
index 010d32c49..a6bddbeda 100644
--- a/src/Squidex.Infrastructure/CQRS/Events/Envelope_1.cs
+++ b/src/Squidex.Infrastructure/CQRS/Events/Envelope_1.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.CQRS.Events
{
public class Envelope where TPayload : class
diff --git a/src/Squidex.Infrastructure/CQRS/Events/IEvent.cs b/src/Squidex.Infrastructure/CQRS/Events/IEvent.cs
index 863bfaf64..11915d798 100644
--- a/src/Squidex.Infrastructure/CQRS/Events/IEvent.cs
+++ b/src/Squidex.Infrastructure/CQRS/Events/IEvent.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.CQRS.Events
{
public interface IEvent
diff --git a/src/Squidex.Infrastructure/CQRS/Events/IEventConsumerInfo.cs b/src/Squidex.Infrastructure/CQRS/Events/IEventConsumerInfo.cs
index ce89b7068..e05f9623a 100644
--- a/src/Squidex.Infrastructure/CQRS/Events/IEventConsumerInfo.cs
+++ b/src/Squidex.Infrastructure/CQRS/Events/IEventConsumerInfo.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.CQRS.Events
{
public interface IEventConsumerInfo
diff --git a/src/Squidex.Infrastructure/CQRS/Events/StoredEvent.cs b/src/Squidex.Infrastructure/CQRS/Events/StoredEvent.cs
index 6890ee2f8..2029df12e 100644
--- a/src/Squidex.Infrastructure/CQRS/Events/StoredEvent.cs
+++ b/src/Squidex.Infrastructure/CQRS/Events/StoredEvent.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.CQRS.Events
{
public sealed class StoredEvent
diff --git a/src/Squidex.Infrastructure/Caching/IInvalidatingCache.cs b/src/Squidex.Infrastructure/Caching/IInvalidatingCache.cs
index 0deefe866..4047b604a 100644
--- a/src/Squidex.Infrastructure/Caching/IInvalidatingCache.cs
+++ b/src/Squidex.Infrastructure/Caching/IInvalidatingCache.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.Caching
{
public interface IInvalidatingCache
diff --git a/src/Squidex.Infrastructure/IExternalSystem.cs b/src/Squidex.Infrastructure/IExternalSystem.cs
index 4408e645c..8943f9de6 100644
--- a/src/Squidex.Infrastructure/IExternalSystem.cs
+++ b/src/Squidex.Infrastructure/IExternalSystem.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure
{
public interface IExternalSystem
diff --git a/src/Squidex.Infrastructure/Log/ILogAppender.cs b/src/Squidex.Infrastructure/Log/ILogAppender.cs
index 596c6b8d6..99c2669ed 100644
--- a/src/Squidex.Infrastructure/Log/ILogAppender.cs
+++ b/src/Squidex.Infrastructure/Log/ILogAppender.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.Log
{
public interface ILogAppender
diff --git a/src/Squidex.Infrastructure/Log/ILogChannel.cs b/src/Squidex.Infrastructure/Log/ILogChannel.cs
index 20ebee481..7824f10a9 100644
--- a/src/Squidex.Infrastructure/Log/ILogChannel.cs
+++ b/src/Squidex.Infrastructure/Log/ILogChannel.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.Log
{
public interface ILogChannel
diff --git a/src/Squidex.Infrastructure/Log/Internal/IConsole.cs b/src/Squidex.Infrastructure/Log/Internal/IConsole.cs
index f6f4a9309..6186d4a60 100644
--- a/src/Squidex.Infrastructure/Log/Internal/IConsole.cs
+++ b/src/Squidex.Infrastructure/Log/Internal/IConsole.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.Log.Internal
{
public interface IConsole
diff --git a/src/Squidex.Infrastructure/Log/Internal/LogMessageEntry.cs b/src/Squidex.Infrastructure/Log/Internal/LogMessageEntry.cs
index e106bb4c4..5c506116e 100644
--- a/src/Squidex.Infrastructure/Log/Internal/LogMessageEntry.cs
+++ b/src/Squidex.Infrastructure/Log/Internal/LogMessageEntry.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.Log.Internal
{
public struct LogMessageEntry
diff --git a/src/Squidex.Infrastructure/Log/SemanticLogLevel.cs b/src/Squidex.Infrastructure/Log/SemanticLogLevel.cs
index aa724f5db..232811359 100644
--- a/src/Squidex.Infrastructure/Log/SemanticLogLevel.cs
+++ b/src/Squidex.Infrastructure/Log/SemanticLogLevel.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.Log
{
public enum SemanticLogLevel
diff --git a/src/Squidex.Infrastructure/Reflection/IPropertyAccessor.cs b/src/Squidex.Infrastructure/Reflection/IPropertyAccessor.cs
index 26004bfd5..9efc49e13 100644
--- a/src/Squidex.Infrastructure/Reflection/IPropertyAccessor.cs
+++ b/src/Squidex.Infrastructure/Reflection/IPropertyAccessor.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.Reflection
{
public interface IPropertyAccessor
diff --git a/src/Squidex.Infrastructure/Security/OpenIdClaims.cs b/src/Squidex.Infrastructure/Security/OpenIdClaims.cs
index 407af18e0..e01fb6d88 100644
--- a/src/Squidex.Infrastructure/Security/OpenIdClaims.cs
+++ b/src/Squidex.Infrastructure/Security/OpenIdClaims.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Infrastructure.Security
{
public static class OpenIdClaims
diff --git a/src/Squidex.Shared/Identity/SquidexClaimTypes.cs b/src/Squidex.Shared/Identity/SquidexClaimTypes.cs
new file mode 100644
index 000000000..9a26f7ec4
--- /dev/null
+++ b/src/Squidex.Shared/Identity/SquidexClaimTypes.cs
@@ -0,0 +1,19 @@
+// ==========================================================================
+// SquidexClaimTypes.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+namespace Squidex.Shared.Identity
+{
+ public static class SquidexClaimTypes
+ {
+ public static readonly string SquidexDisplayName = "urn:squidex:name";
+
+ public static readonly string SquidexPictureUrl = "urn:squidex:picture";
+
+ public static readonly string Prefix = "urn:squidex:";
+ }
+}
diff --git a/src/Squidex.Shared/Identity/SquidexRoles.cs b/src/Squidex.Shared/Identity/SquidexRoles.cs
new file mode 100644
index 000000000..f9ed773d8
--- /dev/null
+++ b/src/Squidex.Shared/Identity/SquidexRoles.cs
@@ -0,0 +1,21 @@
+// ==========================================================================
+// SquidexRoles.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+namespace Squidex.Shared.Identity
+{
+ public static class SquidexRoles
+ {
+ public static readonly string Administrator = "ADMINISTRATOR";
+
+ public static readonly string AppOwner = "APP-OWNER";
+
+ public static readonly string AppEditor = "APP-EDITOR";
+
+ public static readonly string AppDeveloper = "APP-DEVELOPER";
+ }
+}
diff --git a/src/Squidex.Shared/Squidex.Shared.csproj b/src/Squidex.Shared/Squidex.Shared.csproj
new file mode 100644
index 000000000..c8bca6ac3
--- /dev/null
+++ b/src/Squidex.Shared/Squidex.Shared.csproj
@@ -0,0 +1,12 @@
+
+
+ netstandard1.6
+
+
+ full
+ True
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Squidex.Shared/Users/ExternalLogin.cs b/src/Squidex.Shared/Users/ExternalLogin.cs
new file mode 100644
index 000000000..4f9c41b30
--- /dev/null
+++ b/src/Squidex.Shared/Users/ExternalLogin.cs
@@ -0,0 +1,32 @@
+// ==========================================================================
+// ExternalLogin.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+namespace Squidex.Shared.Users
+{
+ public sealed class ExternalLogin
+ {
+ public string LoginProvider { get; }
+
+ public string ProviderKey { get; }
+
+ public string ProviderDisplayName { get; }
+
+ public ExternalLogin(string loginProvider, string providerKey, string providerDisplayName)
+ {
+ LoginProvider = loginProvider;
+
+ ProviderKey = providerKey;
+ ProviderDisplayName = providerDisplayName;
+
+ if (string.IsNullOrWhiteSpace(ProviderDisplayName))
+ {
+ ProviderDisplayName = loginProvider;
+ }
+ }
+ }
+}
diff --git a/src/Squidex.Shared/Users/IUser.cs b/src/Squidex.Shared/Users/IUser.cs
new file mode 100644
index 000000000..a283a23f0
--- /dev/null
+++ b/src/Squidex.Shared/Users/IUser.cs
@@ -0,0 +1,34 @@
+// ==========================================================================
+// IUser.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using System.Collections.Generic;
+using System.Security.Claims;
+
+namespace Squidex.Shared.Users
+{
+ public interface IUser
+ {
+ bool IsLocked { get; }
+
+ string Id { get; }
+
+ string Email { get; }
+
+ string NormalizedEmail { get; }
+
+ IReadOnlyList Claims { get; }
+
+ IReadOnlyList Logins { get; }
+
+ void UpdateEmail(string email);
+
+ void AddClaim(Claim claim);
+
+ void SetClaim(string type, string value);
+ }
+}
diff --git a/src/Squidex.Shared/Users/IUserResolver.cs b/src/Squidex.Shared/Users/IUserResolver.cs
new file mode 100644
index 000000000..20693a42c
--- /dev/null
+++ b/src/Squidex.Shared/Users/IUserResolver.cs
@@ -0,0 +1,17 @@
+// ==========================================================================
+// IUserResolver.cs
+// Squidex Headless CMS
+// ==========================================================================
+// Copyright (c) Squidex Group
+// All rights reserved.
+// ==========================================================================
+
+using System.Threading.Tasks;
+
+namespace Squidex.Shared.Users
+{
+ public interface IUserResolver
+ {
+ Task FindByIdAsync(string id);
+ }
+}
diff --git a/src/Squidex/Config/Constants.cs b/src/Squidex/Config/Constants.cs
index 70b040482..f1a9f9385 100644
--- a/src/Squidex/Config/Constants.cs
+++ b/src/Squidex/Config/Constants.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Config
{
public static class Constants
diff --git a/src/Squidex/Config/Identity/MyIdentityOptions.cs b/src/Squidex/Config/Identity/MyIdentityOptions.cs
index 0b5b4d16f..10d0fc99a 100644
--- a/src/Squidex/Config/Identity/MyIdentityOptions.cs
+++ b/src/Squidex/Config/Identity/MyIdentityOptions.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Config.Identity
{
public sealed class MyIdentityOptions
diff --git a/src/Squidex/Controllers/Api/Assets/Models/AssetsDto.cs b/src/Squidex/Controllers/Api/Assets/Models/AssetsDto.cs
index 49157dc3f..0811b3f58 100644
--- a/src/Squidex/Controllers/Api/Assets/Models/AssetsDto.cs
+++ b/src/Squidex/Controllers/Api/Assets/Models/AssetsDto.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Controllers.Api.Assets.Models
{
public sealed class AssetsDto
diff --git a/src/Squidex/Controllers/Api/EventConsumers/Models/EventConsumerDto.cs b/src/Squidex/Controllers/Api/EventConsumers/Models/EventConsumerDto.cs
index 13c7d3fbf..7fd83332f 100644
--- a/src/Squidex/Controllers/Api/EventConsumers/Models/EventConsumerDto.cs
+++ b/src/Squidex/Controllers/Api/EventConsumers/Models/EventConsumerDto.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Controllers.Api.EventConsumers.Models
{
public sealed class EventConsumerDto
diff --git a/src/Squidex/Controllers/Api/Plans/Models/PlanDto.cs b/src/Squidex/Controllers/Api/Plans/Models/PlanDto.cs
index 9653a7b58..30c1191f9 100644
--- a/src/Squidex/Controllers/Api/Plans/Models/PlanDto.cs
+++ b/src/Squidex/Controllers/Api/Plans/Models/PlanDto.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Controllers.Api.Plans.Models
{
public class PlanDto
diff --git a/src/Squidex/Controllers/Api/Statistics/Models/CurrentCallsDto.cs b/src/Squidex/Controllers/Api/Statistics/Models/CurrentCallsDto.cs
index 1a80a83aa..7082bf5d8 100644
--- a/src/Squidex/Controllers/Api/Statistics/Models/CurrentCallsDto.cs
+++ b/src/Squidex/Controllers/Api/Statistics/Models/CurrentCallsDto.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Controllers.Api.Statistics.Models
{
public class CurrentCallsDto
diff --git a/src/Squidex/Controllers/Api/Statistics/Models/CurrentStorageDto.cs b/src/Squidex/Controllers/Api/Statistics/Models/CurrentStorageDto.cs
index 1bf5a3f87..85f5e91d9 100644
--- a/src/Squidex/Controllers/Api/Statistics/Models/CurrentStorageDto.cs
+++ b/src/Squidex/Controllers/Api/Statistics/Models/CurrentStorageDto.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Controllers.Api.Statistics.Models
{
public class CurrentStorageDto
diff --git a/src/Squidex/Controllers/Api/Users/Models/UsersDto.cs b/src/Squidex/Controllers/Api/Users/Models/UsersDto.cs
index 803d2179e..fc0ca93fd 100644
--- a/src/Squidex/Controllers/Api/Users/Models/UsersDto.cs
+++ b/src/Squidex/Controllers/Api/Users/Models/UsersDto.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Controllers.Api.Users.Models
{
public class UsersDto
diff --git a/src/Squidex/Controllers/ContentApi/Models/ContentsDto.cs b/src/Squidex/Controllers/ContentApi/Models/ContentsDto.cs
index 07349ac5f..d1d594ca3 100644
--- a/src/Squidex/Controllers/ContentApi/Models/ContentsDto.cs
+++ b/src/Squidex/Controllers/ContentApi/Models/ContentsDto.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Controllers.ContentApi.Models
{
public class AssetsDto
diff --git a/src/Squidex/Controllers/UI/ExternalProvider.cs b/src/Squidex/Controllers/UI/ExternalProvider.cs
index 125534e0e..26574c5b1 100644
--- a/src/Squidex/Controllers/UI/ExternalProvider.cs
+++ b/src/Squidex/Controllers/UI/ExternalProvider.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Controllers.UI
{
public class ExternalProvider
diff --git a/src/Squidex/Pipeline/IAppTrackingWeightFeature.cs b/src/Squidex/Pipeline/IAppTrackingWeightFeature.cs
index 595f1adbe..56274c735 100644
--- a/src/Squidex/Pipeline/IAppTrackingWeightFeature.cs
+++ b/src/Squidex/Pipeline/IAppTrackingWeightFeature.cs
@@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
+
namespace Squidex.Pipeline
{
public interface IAppTrackingWeightFeature