Browse Source

Dependencies reduced

pull/65/head
Sebastian Stehle 9 years ago
parent
commit
8da0108013
  1. 93
      src/Squidex.Read.MongoDb/Users/MongoRoleStore.cs
  2. 50
      src/Squidex.Read.MongoDb/Users/MongoUserEntity.cs
  3. 323
      src/Squidex.Read.MongoDb/Users/MongoUserStore.cs
  4. 17
      src/Squidex.Read.MongoDb/Users/WrappedIdentityRole.cs
  5. 41
      src/Squidex.Read.MongoDb/Users/WrappedIdentityUser.cs
  6. 2
      src/Squidex.Read/Squidex.Read.csproj
  7. 15
      src/Squidex.Read/Users/IRole.cs
  8. 15
      src/Squidex.Read/Users/IRoleFactory.cs
  9. 32
      src/Squidex.Read/Users/IUser.cs
  10. 15
      src/Squidex.Read/Users/IUserFactory.cs
  11. 16
      src/Squidex.Read/Users/IUserResolver.cs
  12. 30
      src/Squidex.Read/Users/Repositories/IUserRepository.cs
  13. 42
      src/Squidex.Read/Users/UserExtensions.cs
  14. 95
      src/Squidex.Read/Users/UserManagerExtensions.cs
  15. 12
      src/Squidex.Write/Apps/AppCommandHandler.cs
  16. 32
      src/Squidex/Config/Domain/StoreMongoDbModule.cs
  17. 6
      src/Squidex/Config/Identity/IdentityServices.cs
  18. 14
      src/Squidex/Config/Identity/IdentityUsage.cs
  19. 4
      src/Squidex/Controllers/Api/Apps/AppLanguagesController.cs
  20. 8
      src/Squidex/Controllers/Api/Assets/AssetsController.cs
  21. 8
      src/Squidex/Controllers/Api/Schemas/SchemasController.cs
  22. 33
      src/Squidex/Controllers/Api/Users/UserManagementController.cs
  23. 19
      src/Squidex/Controllers/Api/Users/UsersController.cs
  24. 10
      src/Squidex/Controllers/ContentApi/ContentsController.cs
  25. 29
      src/Squidex/Controllers/UI/Account/AccountController.cs
  26. 1
      src/Squidex/Controllers/UI/Account/ExternalProvider.cs
  27. 13
      tests/Squidex.Write.Tests/Apps/AppCommandHandlerTests.cs

93
src/Squidex.Read.MongoDb/Users/MongoRoleStore.cs

@ -0,0 +1,93 @@
// ==========================================================================
// 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;
using Squidex.Read.Users;
namespace Squidex.Read.MongoDb.Users
{
public sealed class MongoRoleStore :
IRoleStore<IRole>,
IRoleFactory
{
private readonly RoleStore<WrappedIdentityRole> innerStore;
public MongoRoleStore(IMongoDatabase database)
{
var rolesCollection = database.GetCollection<WrappedIdentityRole>("Identity_Roles");
IndexChecks.EnsureUniqueIndexOnNormalizedRoleName(rolesCollection);
innerStore = new RoleStore<WrappedIdentityRole>(rolesCollection);
}
public void Dispose()
{
innerStore.Dispose();
}
public IRole Create(string name)
{
return new WrappedIdentityRole { Name = name };
}
public async Task<IRole> FindByIdAsync(string roleId, CancellationToken cancellationToken)
{
return await innerStore.FindByIdAsync(roleId, cancellationToken);
}
public async Task<IRole> FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken)
{
return await innerStore.FindByNameAsync(normalizedRoleName, cancellationToken);
}
public Task<IdentityResult> CreateAsync(IRole role, CancellationToken cancellationToken)
{
return innerStore.CreateAsync((WrappedIdentityRole)role, cancellationToken);
}
public Task<IdentityResult> UpdateAsync(IRole role, CancellationToken cancellationToken)
{
return innerStore.UpdateAsync((WrappedIdentityRole)role, cancellationToken);
}
public Task<IdentityResult> DeleteAsync(IRole role, CancellationToken cancellationToken)
{
return innerStore.DeleteAsync((WrappedIdentityRole)role, cancellationToken);
}
public Task<string> GetRoleIdAsync(IRole role, CancellationToken cancellationToken)
{
return innerStore.GetRoleIdAsync((WrappedIdentityRole)role, cancellationToken);
}
public Task<string> 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<string> 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);
}
}
}

50
src/Squidex.Read.MongoDb/Users/MongoUserEntity.cs

@ -1,50 +0,0 @@
// ==========================================================================
// MongoUserEntity.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Microsoft.AspNetCore.Identity.MongoDB;
using Squidex.Core.Identity;
using Squidex.Read.Users;
namespace Squidex.Read.MongoDb.Users
{
public class MongoUserEntity : IUserEntity
{
private readonly IdentityUser inner;
public string Id
{
get { return inner.Id; }
}
public string Email
{
get { return inner.Email; }
}
public string DisplayName
{
get { return inner.Claims.Find(x => x.Type == SquidexClaimTypes.SquidexDisplayName)?.Value; }
}
public string PictureUrl
{
get { return inner.Claims.Find(x => x.Type == SquidexClaimTypes.SquidexPictureUrl)?.Value; }
}
public bool IsLocked
{
get { return inner.LockoutEndDateUtc != null && inner.LockoutEndDateUtc.Value > DateTime.UtcNow; }
}
public MongoUserEntity(IdentityUser inner)
{
this.inner = inner;
}
}
}

323
src/Squidex.Read.MongoDb/Users/MongoUserStore.cs

@ -0,0 +1,323 @@
// ==========================================================================
// 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.Read.Users;
namespace Squidex.Read.MongoDb.Users
{
public sealed class MongoUserStore :
IUserPasswordStore<IUser>,
IUserRoleStore<IUser>,
IUserLoginStore<IUser>,
IUserSecurityStampStore<IUser>,
IUserEmailStore<IUser>,
IUserClaimStore<IUser>,
IUserPhoneNumberStore<IUser>,
IUserTwoFactorStore<IUser>,
IUserLockoutStore<IUser>,
IUserAuthenticationTokenStore<IUser>,
IUserFactory,
IQueryableUserStore<IUser>
{
private readonly UserStore<WrappedIdentityUser> innerStore;
public MongoUserStore(IMongoDatabase database)
{
var usersCollection = database.GetCollection<WrappedIdentityUser>("Identity_Users");
IndexChecks.EnsureUniqueIndexOnNormalizedEmail(usersCollection);
IndexChecks.EnsureUniqueIndexOnNormalizedUserName(usersCollection);
innerStore = new UserStore<WrappedIdentityUser>(usersCollection);
}
public void Dispose()
{
innerStore.Dispose();
}
public IQueryable<IUser> Users
{
get { return innerStore.Users; }
}
public IUser Create(string email)
{
return new WrappedIdentityUser { Email = email, UserName = email };
}
public async Task<IUser> FindByIdAsync(string userId, CancellationToken cancellationToken)
{
return await innerStore.FindByIdAsync(userId, cancellationToken);
}
public async Task<IUser> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken)
{
return await innerStore.FindByEmailAsync(normalizedEmail, cancellationToken);
}
public async Task<IUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
return await innerStore.FindByNameAsync(normalizedUserName, cancellationToken);
}
public async Task<IUser> FindByLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken)
{
return await innerStore.FindByLoginAsync(loginProvider, providerKey, cancellationToken);
}
public async Task<IList<IUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken)
{
return (await innerStore.GetUsersForClaimAsync(claim, cancellationToken)).OfType<IUser>().ToList();
}
public async Task<IList<IUser>> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken)
{
return (await innerStore.GetUsersInRoleAsync(roleName, cancellationToken)).OfType<IUser>().ToList();
}
public Task<IdentityResult> CreateAsync(IUser user, CancellationToken cancellationToken)
{
return innerStore.CreateAsync((WrappedIdentityUser)user, cancellationToken);
}
public Task<IdentityResult> UpdateAsync(IUser user, CancellationToken cancellationToken)
{
return innerStore.UpdateAsync((WrappedIdentityUser)user, cancellationToken);
}
public Task<IdentityResult> DeleteAsync(IUser user, CancellationToken cancellationToken)
{
return innerStore.DeleteAsync((WrappedIdentityUser)user, cancellationToken);
}
public Task<string> GetUserIdAsync(IUser user, CancellationToken cancellationToken)
{
return innerStore.GetUserIdAsync((WrappedIdentityUser)user, cancellationToken);
}
public Task<string> 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<string> 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<string> 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<bool> HasPasswordAsync(IUser user, CancellationToken cancellationToken)
{
return innerStore.HasPasswordAsync((WrappedIdentityUser)user, 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<IList<string>> GetRolesAsync(IUser user, CancellationToken cancellationToken)
{
return innerStore.GetRolesAsync((WrappedIdentityUser)user, cancellationToken);
}
public Task<bool> 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<IList<UserLoginInfo>> GetLoginsAsync(IUser user, CancellationToken cancellationToken)
{
return innerStore.GetLoginsAsync((WrappedIdentityUser)user, cancellationToken);
}
public Task<string> 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<string> 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<bool> 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<string> 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<IList<Claim>> GetClaimsAsync(IUser user, CancellationToken cancellationToken)
{
return innerStore.GetClaimsAsync((WrappedIdentityUser)user, cancellationToken);
}
public Task AddClaimsAsync(IUser user, IEnumerable<Claim> 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<Claim> claims, CancellationToken cancellationToken)
{
return innerStore.RemoveClaimsAsync((WrappedIdentityUser)user, claims, cancellationToken);
}
public Task<string> 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<bool> 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<bool> 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<DateTimeOffset?> 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<int> GetAccessFailedCountAsync(IUser user, CancellationToken cancellationToken)
{
return innerStore.GetAccessFailedCountAsync((WrappedIdentityUser)user, cancellationToken);
}
public Task<int> 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<bool> 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<string> GetTokenAsync(IUser user, string loginProvider, string name, CancellationToken cancellationToken)
{
return innerStore.GetTokenAsync((WrappedIdentityUser)user, loginProvider, name, cancellationToken);
}
}
}

17
src/Squidex.Read.MongoDb/Users/WrappedIdentityRole.cs

@ -0,0 +1,17 @@
// ==========================================================================
// WrappedIdentityRole.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Microsoft.AspNetCore.Identity.MongoDB;
using Squidex.Read.Users;
namespace Squidex.Read.MongoDb.Users
{
public sealed class WrappedIdentityRole : IdentityRole, IRole
{
}
}

41
src/Squidex.Read.MongoDb/Users/WrappedIdentityUser.cs

@ -0,0 +1,41 @@
// ==========================================================================
// 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.Read.Users;
namespace Squidex.Read.MongoDb.Users
{
public sealed class WrappedIdentityUser : IdentityUser, IUser
{
public bool IsLocked
{
get { return LockoutEndDateUtc != null && LockoutEndDateUtc.Value > DateTime.UtcNow; }
}
IReadOnlyList<Claim> IUser.Claims
{
get { return Claims.Select(x => new Claim(x.Type, x.Value)).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 });
}
}
}

2
src/Squidex.Read/Squidex.Read.csproj

@ -13,7 +13,9 @@
<ProjectReference Include="..\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="1.1.2" />
<PackageReference Include="NodaTime" Version="2.0.2" />
<PackageReference Include="System.Linq.Queryable" Version="4.3.0" />
</ItemGroup>
</Project>

15
src/Squidex.Read/Users/IRole.cs

@ -0,0 +1,15 @@
// ==========================================================================
// IRole.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Read.Users
{
public interface IRole
{
string Name { get; }
}
}

15
src/Squidex.Read/Users/IRoleFactory.cs

@ -0,0 +1,15 @@
// ==========================================================================
// IRoleFactory.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Read.Users
{
public interface IRoleFactory
{
IRole Create(string name);
}
}

32
src/Squidex.Read/Users/IUser.cs

@ -0,0 +1,32 @@
// ==========================================================================
// IUser.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Security.Claims;
namespace Squidex.Read.Users
{
public interface IUser
{
bool IsLocked { get; }
string Id { get; }
string Email { get; }
string NormalizedEmail { get; }
IReadOnlyList<Claim> Claims { get; }
void UpdateEmail(string email);
void AddClaim(Claim claim);
void SetClaim(string type, string value);
}
}

15
src/Squidex.Read/Users/IUserFactory.cs

@ -0,0 +1,15 @@
// ==========================================================================
// IUserFactory.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Read.Users
{
public interface IUserFactory
{
IUser Create(string email);
}
}

16
src/Squidex.Read/Users/IUserEntity.cs → src/Squidex.Read/Users/IUserResolver.cs

@ -1,23 +1,17 @@
// ==========================================================================
// IUserEntity.cs
// IUserResolver.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Threading.Tasks;
namespace Squidex.Read.Users
{
public interface IUserEntity
public interface IUserResolver
{
string Id { get; }
string Email { get; }
string PictureUrl { get; }
string DisplayName { get; }
bool IsLocked { get; }
Task<IUser> FindById(string id);
}
}

30
src/Squidex.Read/Users/Repositories/IUserRepository.cs

@ -1,30 +0,0 @@
// ==========================================================================
// IUserRepository.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Squidex.Read.Users.Repositories
{
public interface IUserRepository
{
Task<IReadOnlyList<IUserEntity>> QueryByEmailAsync(string email = null, int take = 10, int skip = 0);
Task<IUserEntity> FindUserByIdAsync(string id);
Task<string> CreateAsync(string email, string displayName, string password);
Task UpdateAsync(string id, string email, string displayName, string password);
Task LockAsync(string id);
Task UnlockAsync(string id);
Task<long> CountAsync(string email = null);
}
}

42
src/Squidex.Read/Users/UserExtensions.cs

@ -0,0 +1,42 @@
// ==========================================================================
// UserExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Linq;
using Squidex.Core.Identity;
using Squidex.Infrastructure;
namespace Squidex.Read.Users
{
public static class UserExtensions
{
public static void SetDisplayName(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 SetPictureUrlFromGravatar(this IUser user, string email)
{
user.SetClaim(SquidexClaimTypes.SquidexPictureUrl, GravatarHelper.CreatePictureUrl(email));
}
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;
}
}
}

95
src/Squidex.Read.MongoDb/Users/MongoUserRepository.cs → src/Squidex.Read/Users/UserManagerExtensions.cs

@ -1,5 +1,5 @@
// ==========================================================================
// MongoUserRepository.cs
// UserManagerExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -9,66 +9,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.MongoDB;
using Squidex.Core.Identity;
using Squidex.Infrastructure;
using Squidex.Read.Users;
using Squidex.Read.Users.Repositories;
// ReSharper disable ImplicitlyCapturedClosure
// ReSharper disable InvertIf
// ReSharper disable ReturnTypeCanBeEnumerable.Local
namespace Squidex.Read.MongoDb.Users
namespace Squidex.Read.Users
{
public sealed class MongoUserRepository : IUserRepository
public static class UserManagerExtensions
{
private readonly UserManager<IdentityUser> userManager;
public MongoUserRepository(UserManager<IdentityUser> userManager)
public static Task<IReadOnlyList<IUser>> QueryByEmailAsync(this UserManager<IUser> userManager, string email = null, int take = 10, int skip = 0)
{
Guard.NotNull(userManager, nameof(userManager));
this.userManager = userManager;
}
var users = QueryUsers(userManager, email).Skip(skip).Take(take).ToList();
public Task<IReadOnlyList<IUserEntity>> QueryByEmailAsync(string email, int take = 10, int skip = 0)
{
var users = QueryUsers(email).Skip(skip).Take(take).ToList();
return Task.FromResult<IReadOnlyList<IUserEntity>>(users.Select(x => (IUserEntity)new MongoUserEntity(x)).ToList());
return Task.FromResult<IReadOnlyList<IUser>>(users);
}
public Task<long> CountAsync(string email = null)
public static Task<long> CountAsync(this UserManager<IUser> userManager, string email = null)
{
var count = QueryUsers(email).LongCount();
var count = QueryUsers(userManager, email).LongCount();
return Task.FromResult(count);
}
public async Task<IUserEntity> FindUserByIdAsync(string id)
private static IQueryable<IUser> QueryUsers(UserManager<IUser> userManager, string email = null)
{
var user = await userManager.FindByIdAsync(id);
var result = userManager.Users;
return user != null ? new MongoUserEntity(user) : null;
if (!string.IsNullOrWhiteSpace(email))
{
var upperEmail = email.ToUpperInvariant();
result = result.Where(x => x.NormalizedEmail.Contains(upperEmail));
}
return result;
}
public async Task<string> CreateAsync(string email, string displayName, string password)
public static async Task<string> CreateAsync(this UserManager<IUser> userManager, IUserFactory factory, string email, string displayName, string password)
{
var pictureUrl = GravatarHelper.CreatePictureUrl(email);
var user = factory.Create(email);
var user = new IdentityUser
{
Email = email,
Claims = new List<IdentityUserClaim>
{
new IdentityUserClaim(new Claim(SquidexClaimTypes.SquidexPictureUrl, pictureUrl)),
new IdentityUserClaim(new Claim(SquidexClaimTypes.SquidexDisplayName, displayName))
},
UserName = email
};
user.SetDisplayName(displayName);
user.SetPictureUrlFromGravatar(email);
await DoChecked(() => userManager.CreateAsync(user), "Cannot create user.");
@ -80,57 +67,53 @@ namespace Squidex.Read.MongoDb.Users
return user.Id;
}
public async Task UpdateAsync(string id, string email, string displayName, string password)
public static async Task UpdateAsync(this UserManager<IUser> userManager, string id, string email, string displayName, string password)
{
var user = await userManager.FindByIdAsync(id);
if (user == null)
{
throw new DomainObjectNotFoundException(id, typeof(IdentityUser));
throw new DomainObjectNotFoundException(id, typeof(IUser));
}
if (!string.IsNullOrWhiteSpace(email))
{
user.Email = user.UserName = email;
user.UpdateEmail(email);
}
if (!string.IsNullOrWhiteSpace(displayName))
{
user.Claims.Find(x => x.Type == SquidexClaimTypes.SquidexDisplayName).Value = displayName;
}
if (!string.IsNullOrWhiteSpace(password))
{
user.PasswordHash = null;
user.SetClaim(SquidexClaimTypes.SquidexDisplayName, 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 async Task LockAsync(string id)
public static async Task LockAsync(this UserManager<IUser> userManager, string id)
{
var user = await userManager.FindByIdAsync(id);
if (user == null)
{
throw new DomainObjectNotFoundException(id, typeof(IdentityUser));
throw new DomainObjectNotFoundException(id, typeof(IUser));
}
await DoChecked(() => userManager.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.AddYears(100)), "Cannot lock user.");
}
public async Task UnlockAsync(string id)
public static async Task UnlockAsync(this UserManager<IUser> userManager, string id)
{
var user = await userManager.FindByIdAsync(id);
if (user == null)
{
throw new DomainObjectNotFoundException(id, typeof(IdentityUser));
throw new DomainObjectNotFoundException(id, typeof(IUser));
}
await DoChecked(() => userManager.SetLockoutEndDateAsync(user, null), "Cannot unlock user.");
@ -145,19 +128,5 @@ namespace Squidex.Read.MongoDb.Users
throw new ValidationException(message, result.Errors.Select(x => new ValidationError(x.Description)).ToArray());
}
}
private IQueryable<IdentityUser> QueryUsers(string email = null)
{
var result = userManager.Users;
if (!string.IsNullOrWhiteSpace(email))
{
var upperEmail = email.ToUpperInvariant();
result = userManager.Users.Where(x => x.NormalizedEmail.Contains(upperEmail));
}
return result;
}
}
}

12
src/Squidex.Write/Apps/AppCommandHandler.cs

@ -13,7 +13,7 @@ using Squidex.Infrastructure.Dispatching;
using Squidex.Infrastructure.Tasks;
using Squidex.Read.Apps.Repositories;
using Squidex.Read.Apps.Services;
using Squidex.Read.Users.Repositories;
using Squidex.Read.Users;
using Squidex.Write.Apps.Commands;
// ReSharper disable InvertIf
@ -25,25 +25,25 @@ namespace Squidex.Write.Apps
private readonly IAggregateHandler handler;
private readonly IAppRepository appRepository;
private readonly IAppLimitsProvider appLimitsProvider;
private readonly IUserRepository userRepository;
private readonly IUserResolver userResolver;
private readonly ClientKeyGenerator keyGenerator;
public AppCommandHandler(
IAggregateHandler handler,
IAppRepository appRepository,
IAppLimitsProvider appLimitsProvider,
IUserRepository userRepository,
IUserResolver userResolver,
ClientKeyGenerator keyGenerator)
{
Guard.NotNull(handler, nameof(handler));
Guard.NotNull(keyGenerator, nameof(keyGenerator));
Guard.NotNull(appRepository, nameof(appRepository));
Guard.NotNull(userRepository, nameof(userRepository));
Guard.NotNull(userResolver, nameof(userResolver));
Guard.NotNull(appLimitsProvider, nameof(appLimitsProvider));
this.handler = handler;
this.keyGenerator = keyGenerator;
this.userRepository = userRepository;
this.userResolver = userResolver;
this.appRepository = appRepository;
this.appLimitsProvider = appLimitsProvider;
}
@ -69,7 +69,7 @@ namespace Squidex.Write.Apps
protected async Task On(AssignContributor command, CommandContext context)
{
if (await userRepository.FindUserByIdAsync(command.ContributorId) == null)
if (await userResolver.FindById(command.ContributorId) == null)
{
var error =
new ValidationError("Cannot find contributor the contributor",

32
src/Squidex/Config/Domain/StoreMongoDbModule.cs

@ -10,7 +10,6 @@ using Autofac;
using Autofac.Core;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.MongoDB;
using Microsoft.Extensions.Configuration;
using MongoDB.Driver;
using Squidex.Core.Schemas;
@ -33,7 +32,7 @@ using Squidex.Read.MongoDb.Schemas;
using Squidex.Read.MongoDb.Users;
using Squidex.Read.Schemas.Repositories;
using Squidex.Read.Schemas.Services.Implementations;
using Squidex.Read.Users.Repositories;
using Squidex.Read.Users;
namespace Squidex.Config.Domain
{
@ -85,31 +84,18 @@ namespace Squidex.Config.Domain
.Named<IMongoDatabase>(MongoContentDatabaseRegistration)
.SingleInstance();
builder.Register<IUserStore<IdentityUser>>(c =>
{
var usersCollection = c.ResolveNamed<IMongoDatabase>(MongoDatabaseRegistration).GetCollection<IdentityUser>("Identity_Users");
IndexChecks.EnsureUniqueIndexOnNormalizedEmail(usersCollection);
IndexChecks.EnsureUniqueIndexOnNormalizedUserName(usersCollection);
return new UserStore<IdentityUser>(usersCollection);
})
builder.RegisterType<MongoUserStore>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IUserStore<IUser>>()
.As<IUserFactory>()
.SingleInstance();
builder.Register<IRoleStore<IdentityRole>>(c =>
{
var rolesCollection = c.ResolveNamed<IMongoDatabase>(MongoDatabaseRegistration).GetCollection<IdentityRole>("Identity_Roles");
IndexChecks.EnsureUniqueIndexOnNormalizedRoleName(rolesCollection);
return new RoleStore<IdentityRole>(rolesCollection);
})
builder.RegisterType<MongoRoleStore>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IRoleStore<IRole>>()
.As<IRoleFactory>()
.SingleInstance();
builder.RegisterType<MongoUserRepository>()
.As<IUserRepository>()
.InstancePerLifetimeScope();
builder.RegisterType<MongoPersistedGrantStore>()
.WithParameter(ResolvedParameter.ForNamed<IMongoDatabase>(MongoDatabaseRegistration))
.As<IPersistedGrantStore>()

6
src/Squidex/Config/Identity/IdentityServices.cs

@ -16,11 +16,11 @@ using IdentityModel;
using IdentityServer4.Models;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity.MongoDB;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Core.Identity;
using Squidex.Infrastructure;
using Squidex.Read.Users;
using StackExchange.Redis;
namespace Squidex.Config.Identity
@ -100,7 +100,7 @@ namespace Squidex.Config.Identity
{
options.UserInteraction.ErrorUrl = "/account/error/";
})
.AddAspNetIdentity<IdentityUser>()
.AddAspNetIdentity<IUser>()
.AddInMemoryApiResources(GetApiResources())
.AddInMemoryIdentityResources(GetIdentityResources())
.AddSigningCredential(certificate);
@ -110,7 +110,7 @@ namespace Squidex.Config.Identity
public static IServiceCollection AddMyIdentity(this IServiceCollection services)
{
services.AddIdentity<IdentityUser, IdentityRole>().AddDefaultTokenProviders();
services.AddIdentity<IUser, IRole>().AddDefaultTokenProviders();
return services;
}

14
src/Squidex/Config/Identity/IdentityUsage.cs

@ -10,10 +10,10 @@ 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;
using Squidex.Core.Identity;
using Squidex.Read.Users;
// ReSharper disable InvertIf
@ -37,9 +37,10 @@ namespace Squidex.Config.Identity
public static IApplicationBuilder UseAdminRole(this IApplicationBuilder app)
{
var roleManager = app.ApplicationServices.GetRequiredService<RoleManager<IdentityRole>>();
var roleManager = app.ApplicationServices.GetRequiredService<RoleManager<IRole>>();
var roleFactory = app.ApplicationServices.GetRequiredService<IRoleFactory>();
roleManager.CreateAsync(new IdentityRole { Name = SquidexRoles.Administrator, NormalizedName = SquidexRoles.Administrator }).Wait();
roleManager.CreateAsync(roleFactory.Create(SquidexRoles.Administrator)).Wait();
return app;
}
@ -48,7 +49,8 @@ namespace Squidex.Config.Identity
{
var options = app.ApplicationServices.GetService<IOptions<MyIdentityOptions>>().Value;
var userManager = app.ApplicationServices.GetService<UserManager<IdentityUser>>();
var userManager = app.ApplicationServices.GetService<UserManager<IUser>>();
var userFactory = app.ApplicationServices.GetService<IUserFactory>();
if (options.IsAdminConfigured())
{
@ -59,7 +61,7 @@ namespace Squidex.Config.Identity
{
var user = await userManager.FindByEmailAsync(adminPass);
async Task userInitAsync(IdentityUser theUser)
async Task userInitAsync(IUser theUser)
{
await userManager.RemovePasswordAsync(theUser);
await userManager.ChangePasswordAsync(theUser, null, adminEmail);
@ -75,7 +77,7 @@ namespace Squidex.Config.Identity
}
else if ((userManager.SupportsQueryableUsers && !userManager.Users.Any()) || options.EnforceAdmin)
{
user = new IdentityUser { UserName = adminEmail, Email = adminEmail, EmailConfirmed = true };
user = userFactory.Create(adminEmail);
await userManager.CreateAsync(user);
await userInitAsync(user);

4
src/Squidex/Controllers/Api/Apps/AppLanguagesController.cs

@ -50,7 +50,7 @@ namespace Squidex.Controllers.Api.Apps
[ProducesResponseType(typeof(LanguageDto[]), 200)]
public IActionResult GetLanguages(string app)
{
var model = App.LanguagesConfig.OfType<LanguageConfig>().Select(x =>
var response = App.LanguagesConfig.OfType<LanguageConfig>().Select(x =>
SimpleMapper.Map(x.Language,
new AppLanguageDto
{
@ -61,7 +61,7 @@ namespace Squidex.Controllers.Api.Apps
Response.Headers["ETag"] = new StringValues(App.Version.ToString());
return Ok(model);
return Ok(response);
}
/// <summary>

8
src/Squidex/Controllers/Api/Assets/AssetsController.cs

@ -102,13 +102,13 @@ namespace Squidex.Controllers.Api.Assets
await Task.WhenAll(taskForAssets, taskForCount);
var model = new AssetsDto
var response = new AssetsDto
{
Total = taskForCount.Result,
Items = taskForAssets.Result.Select(x => SimpleMapper.Map(x, new AssetDto())).ToArray()
};
return Ok(model);
return Ok(response);
}
/// <summary>
@ -133,11 +133,11 @@ namespace Squidex.Controllers.Api.Assets
return NotFound();
}
var model = SimpleMapper.Map(entity, new AssetDto());
var response = SimpleMapper.Map(entity, new AssetDto());
Response.Headers["ETag"] = new StringValues(entity.Version.ToString());
return Ok(model);
return Ok(response);
}
/// <summary>

8
src/Squidex/Controllers/Api/Schemas/SchemasController.cs

@ -55,9 +55,9 @@ namespace Squidex.Controllers.Api.Schemas
{
var schemas = await schemaRepository.QueryAllAsync(AppId);
var model = schemas.Select(s => s.ToModel()).ToList();
var response = schemas.Select(s => s.ToModel()).ToList();
return Ok(model);
return Ok(response);
}
/// <summary>
@ -83,11 +83,11 @@ namespace Squidex.Controllers.Api.Schemas
return NotFound();
}
var model = entity.ToDetailsModel();
var response = entity.ToDetailsModel();
Response.Headers["ETag"] = new StringValues(entity.Version.ToString());
return Ok(model);
return Ok(response);
}
/// <summary>

33
src/Squidex/Controllers/Api/Users/UserManagementController.cs

@ -9,6 +9,7 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using NSwag.Annotations;
using Squidex.Controllers.Api.Users.Models;
@ -16,7 +17,7 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Security;
using Squidex.Pipeline;
using Squidex.Read.Users.Repositories;
using Squidex.Read.Users;
namespace Squidex.Controllers.Api.Users
{
@ -25,11 +26,13 @@ namespace Squidex.Controllers.Api.Users
[SwaggerIgnore]
public class UserManagementController : Controller
{
private readonly IUserRepository userRepository;
private readonly UserManager<IUser> userManager;
private readonly IUserFactory userFactory;
public UserManagementController(IUserRepository userRepository)
public UserManagementController(UserManager<IUser> userManager, IUserFactory userFactory)
{
this.userRepository = userRepository;
this.userManager = userManager;
this.userFactory = userFactory;
}
[HttpGet]
@ -37,18 +40,18 @@ namespace Squidex.Controllers.Api.Users
[ApiCosts(0)]
public async Task<IActionResult> GetUsers([FromQuery] string query = null, [FromQuery] int skip = 0, [FromQuery] int take = 10)
{
var taskForUsers = userRepository.QueryByEmailAsync(query, take, skip);
var taskForCount = userRepository.CountAsync(query);
var taskForUsers = userManager.QueryByEmailAsync(query, take, skip);
var taskForCount = userManager.CountAsync(query);
await Task.WhenAll(taskForUsers, taskForCount);
var model = new UsersDto
var response = new UsersDto
{
Total = taskForCount.Result,
Items = taskForUsers.Result.Select(x => SimpleMapper.Map(x, new UserDto())).ToArray()
Items = taskForUsers.Result.Select(x => SimpleMapper.Map(x, new UserDto { DisplayName = x.DisplayName(), PictureUrl = x.PictureUrl() })).ToArray()
};
return Ok(model);
return Ok(response);
}
[HttpPost]
@ -56,11 +59,11 @@ namespace Squidex.Controllers.Api.Users
[ApiCosts(0)]
public async Task<IActionResult> Create([FromBody] CreateUserDto request)
{
var id = await userRepository.CreateAsync(request.Email, request.DisplayName, request.Password);
var id = await userManager.CreateAsync(userFactory, request.Email, request.DisplayName, request.Password);
var model = new EntityCreatedDto { Id = id };
var response = new EntityCreatedDto { Id = id };
return Ok(model);
return Ok(response);
}
[HttpPut]
@ -68,7 +71,7 @@ namespace Squidex.Controllers.Api.Users
[ApiCosts(0)]
public async Task<IActionResult> Update(string id, [FromBody] UpdateUserDto request)
{
await userRepository.UpdateAsync(id, request.Email, request.DisplayName, request.Password);
await userManager.UpdateAsync(id, request.Email, request.DisplayName, request.Password);
return NoContent();
}
@ -83,7 +86,7 @@ namespace Squidex.Controllers.Api.Users
throw new ValidationException("Locking user failed.", new ValidationError("You cannot lock yourself."));
}
await userRepository.LockAsync(id);
await userManager.LockAsync(id);
return NoContent();
}
@ -98,7 +101,7 @@ namespace Squidex.Controllers.Api.Users
throw new ValidationException("Unlocking user failed.", new ValidationError("You cannot unlock yourself."));
}
await userRepository.UnlockAsync(id);
await userManager.UnlockAsync(id);
return NoContent();
}

19
src/Squidex/Controllers/Api/Users/UsersController.cs

@ -9,12 +9,13 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using NSwag.Annotations;
using Squidex.Controllers.Api.Users.Models;
using Squidex.Infrastructure.Reflection;
using Squidex.Pipeline;
using Squidex.Read.Users.Repositories;
using Squidex.Read.Users;
namespace Squidex.Controllers.Api.Users
{
@ -26,11 +27,11 @@ namespace Squidex.Controllers.Api.Users
[SwaggerTag("Users")]
public class UsersController : Controller
{
private readonly IUserRepository userRepository;
private readonly UserManager<IUser> userManager;
public UsersController(IUserRepository userRepository)
public UsersController(UserManager<IUser> userManager)
{
this.userRepository = userRepository;
this.userManager = userManager;
}
/// <summary>
@ -48,11 +49,11 @@ namespace Squidex.Controllers.Api.Users
[ProducesResponseType(typeof(UserDto[]), 200)]
public async Task<IActionResult> GetUsers(string query)
{
var entities = await userRepository.QueryByEmailAsync(query ?? string.Empty);
var entities = await userManager.QueryByEmailAsync(query ?? string.Empty);
var response = entities.Select(x => SimpleMapper.Map(x, new UserDto())).ToList();
var models = entities.Select(x => SimpleMapper.Map(x, new UserDto { DisplayName = x.DisplayName(), PictureUrl = x.PictureUrl() })).ToArray();
return Ok(response);
return Ok(models);
}
/// <summary>
@ -68,14 +69,14 @@ namespace Squidex.Controllers.Api.Users
[ProducesResponseType(typeof(UserDto), 200)]
public async Task<IActionResult> GetUser(string id)
{
var entity = await userRepository.FindUserByIdAsync(id);
var entity = await userManager.FindByIdAsync(id);
if (entity == null)
{
return NotFound();
}
var response = SimpleMapper.Map(entity, new UserDto());
var response = SimpleMapper.Map(entity, new UserDto { DisplayName = entity.DisplayName(), PictureUrl = entity.PictureUrl() });
return Ok(response);
}

10
src/Squidex/Controllers/ContentApi/ContentsController.cs

@ -59,7 +59,7 @@ namespace Squidex.Controllers.ContentApi
await Task.WhenAll(taskForContents, taskForCount);
var model = new AssetsDto
var response = new AssetsDto
{
Total = taskForCount.Result,
Items = taskForContents.Result.Take(200).Select(x =>
@ -75,7 +75,7 @@ namespace Squidex.Controllers.ContentApi
}).ToArray()
};
return Ok(model);
return Ok(response);
}
[HttpGet]
@ -97,16 +97,16 @@ namespace Squidex.Controllers.ContentApi
return NotFound();
}
var model = SimpleMapper.Map(entity, new ContentDto());
var resposne = SimpleMapper.Map(entity, new ContentDto());
if (entity.Data != null)
{
model.Data = entity.Data.ToApiModel(schemaEntity.Schema, App.LanguagesConfig, null, hidden);
resposne.Data = entity.Data.ToApiModel(schemaEntity.Schema, App.LanguagesConfig, null, hidden);
}
Response.Headers["ETag"] = new StringValues(entity.Version.ToString());
return Ok(model);
return Ok(resposne);
}
[HttpPost]

29
src/Squidex/Controllers/UI/Account/AccountController.cs

@ -14,7 +14,6 @@ using System.Text;
using System.Threading.Tasks;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.MongoDB;
using Microsoft.AspNetCore.Mvc;
using NSwag.Annotations;
using Microsoft.Extensions.Options;
@ -24,6 +23,7 @@ using Squidex.Core.Identity;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Tasks;
using Squidex.Read.Users;
// ReSharper disable InvertIf
// ReSharper disable RedundantIfElseBlock
@ -34,16 +34,18 @@ namespace Squidex.Controllers.UI.Account
[SwaggerIgnore]
public sealed class AccountController : Controller
{
private readonly SignInManager<IdentityUser> signInManager;
private readonly UserManager<IdentityUser> userManager;
private readonly SignInManager<IUser> signInManager;
private readonly UserManager<IUser> userManager;
private readonly IUserFactory userFactory;
private readonly IOptions<MyIdentityOptions> identityOptions;
private readonly IOptions<MyUrlsOptions> urlOptions;
private readonly ISemanticLog log;
private readonly IIdentityServerInteractionService interactions;
public AccountController(
SignInManager<IdentityUser> signInManager,
UserManager<IdentityUser> userManager,
SignInManager<IUser> signInManager,
UserManager<IUser> userManager,
IUserFactory userFactory,
IOptions<MyIdentityOptions> identityOptions,
IOptions<MyUrlsOptions> urlOptions,
ISemanticLog log,
@ -52,6 +54,7 @@ namespace Squidex.Controllers.UI.Account
this.log = log;
this.urlOptions = urlOptions;
this.userManager = userManager;
this.userFactory = userFactory;
this.interactions = interactions;
this.identityOptions = identityOptions;
this.signInManager = signInManager;
@ -258,12 +261,12 @@ namespace Squidex.Controllers.UI.Account
}
}
private Task<bool> AddLoginAsync(IdentityUser user, UserLoginInfo externalLogin)
private Task<bool> AddLoginAsync(IUser user, UserLoginInfo externalLogin)
{
return MakeIdentityOperation(() => userManager.AddLoginAsync(user, externalLogin));
}
private Task<bool> AddUserAsync(IdentityUser user)
private Task<bool> AddUserAsync(IUser user)
{
return MakeIdentityOperation(() => userManager.CreateAsync(user));
}
@ -275,7 +278,7 @@ namespace Squidex.Controllers.UI.Account
return result.Succeeded;
}
private Task<bool> LockAsync(IdentityUser user, bool isFirst)
private Task<bool> LockAsync(IUser user, bool isFirst)
{
if (isFirst || !identityOptions.Value.LockAutomatically)
{
@ -285,7 +288,7 @@ namespace Squidex.Controllers.UI.Account
return MakeIdentityOperation(() => userManager.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.AddYears(100)));
}
private Task<bool> MakeAdminAsync(IdentityUser user, bool isFirst)
private Task<bool> MakeAdminAsync(IUser user, bool isFirst)
{
if (!isFirst)
{
@ -295,18 +298,18 @@ namespace Squidex.Controllers.UI.Account
return MakeIdentityOperation(() => userManager.AddToRoleAsync(user, SquidexRoles.Administrator));
}
private static IdentityUser CreateUser(ExternalLoginInfo externalLogin, string email)
private IUser CreateUser(ExternalLoginInfo externalLogin, string email)
{
var user = new IdentityUser { Email = email, UserName = email };
var user = userFactory.Create(email);
if (!externalLogin.Principal.HasClaim(x => x.Type == SquidexClaimTypes.SquidexPictureUrl))
{
user.AddClaim(new Claim(SquidexClaimTypes.SquidexPictureUrl, GravatarHelper.CreatePictureUrl(email)));
user.SetClaim(SquidexClaimTypes.SquidexPictureUrl, GravatarHelper.CreatePictureUrl(email));
}
if (!externalLogin.Principal.HasClaim(x => x.Type == SquidexClaimTypes.SquidexDisplayName))
{
user.AddClaim(new Claim(SquidexClaimTypes.SquidexDisplayName, email));
user.SetClaim(SquidexClaimTypes.SquidexDisplayName, email);
}
foreach (var squidexClaim in externalLogin.Principal.Claims.Where(c => c.Type.StartsWith(SquidexClaimTypes.Prefix)))

1
src/Squidex/Controllers/UI/Account/ExternalProvider.cs

@ -5,6 +5,7 @@
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Controllers.UI.Account
{
public class ExternalProvider

13
tests/Squidex.Write.Tests/Apps/AppCommandHandlerTests.cs

@ -17,7 +17,6 @@ using Squidex.Read.Apps.Repositories;
using Squidex.Read.Apps.Services;
using Squidex.Read.Apps.Services.Implementations;
using Squidex.Read.Users;
using Squidex.Read.Users.Repositories;
using Squidex.Write.Apps.Commands;
using Squidex.Write.TestHelpers;
using Xunit;
@ -32,7 +31,7 @@ namespace Squidex.Write.Apps
private readonly Mock<ClientKeyGenerator> keyGenerator = new Mock<ClientKeyGenerator>();
private readonly Mock<IAppRepository> appRepository = new Mock<IAppRepository>();
private readonly Mock<IAppLimitsProvider> appLimitsProvider = new Mock<IAppLimitsProvider>();
private readonly Mock<IUserRepository> userRepository = new Mock<IUserRepository>();
private readonly Mock<IUserResolver> userResolver = new Mock<IUserResolver>();
private readonly AppCommandHandler sut;
private readonly AppDomainObject app;
private readonly Language language = Language.DE;
@ -44,7 +43,7 @@ namespace Squidex.Write.Apps
{
app = new AppDomainObject(AppId, -1);
sut = new AppCommandHandler(Handler, appRepository.Object, appLimitsProvider.Object, userRepository.Object, keyGenerator.Object);
sut = new AppCommandHandler(Handler, appRepository.Object, appLimitsProvider.Object, userResolver.Object, keyGenerator.Object);
}
[Fact]
@ -88,7 +87,7 @@ namespace Squidex.Write.Apps
var context = CreateContextForCommand(new AssignContributor { ContributorId = contributorId });
userRepository.Setup(x => x.FindUserByIdAsync(contributorId)).Returns(Task.FromResult<IUserEntity>(null));
userResolver.Setup(x => x.FindById(contributorId)).Returns(Task.FromResult<IUser>(null));
await TestUpdate(app, async _ =>
{
@ -107,7 +106,7 @@ namespace Squidex.Write.Apps
var context = CreateContextForCommand(new AssignContributor { ContributorId = contributorId });
userRepository.Setup(x => x.FindUserByIdAsync(It.IsAny<string>())).Returns(Task.FromResult(new Mock<IUserEntity>().Object));
userResolver.Setup(x => x.FindById(It.IsAny<string>())).Returns(Task.FromResult(new Mock<IUser>().Object));
await TestUpdate(app, async _ =>
{
@ -122,7 +121,7 @@ namespace Squidex.Write.Apps
var context = CreateContextForCommand(new AssignContributor { ContributorId = contributorId });
userRepository.Setup(x => x.FindUserByIdAsync(contributorId)).Returns(Task.FromResult<IUserEntity>(null));
userResolver.Setup(x => x.FindById(contributorId)).Returns(Task.FromResult<IUser>(null));
await TestUpdate(app, async _ =>
{
@ -139,7 +138,7 @@ namespace Squidex.Write.Apps
var context = CreateContextForCommand(new AssignContributor { ContributorId = contributorId });
userRepository.Setup(x => x.FindUserByIdAsync(contributorId)).Returns(Task.FromResult(new Mock<IUserEntity>().Object));
userResolver.Setup(x => x.FindById(contributorId)).Returns(Task.FromResult(new Mock<IUser>().Object));
await TestUpdate(app, async _ =>
{

Loading…
Cancel
Save